当前位置: 首页 > news >正文

【Android】四大组件之ContentProvider

目录

一、什么是 ContentProvider

二、创建和使用 ContentProvider

三、跨应用权限控制

四、数据变更通知

五、多表关联与视图

六、异步处理


你手机里的通讯录,存储了所有联系人的信息。如果你想把这些联系人信息分享给其他App,就可以通过ContentProvider来实现。

一、什么是 ContentProvider

ContentProvider‌ 是 Android 四大组件之一,负责实现‌跨应用程序的数据共享与访问‌,通过统一接口封装数据存储细节,提供标准化操作方式。

1. 核心特点

  •  数据共享桥梁:提供安全的跨应用数据共享机制,允许不同应用通过 ‌URI(统一资源标识符)‌ 访问数据,无需直接操作对方数据库或文件系统。
  • 统一数据接口:独立于底层数据存储形式(SQLite、文件或网络),对外均以‌表格形式‌组织数据,简化调用方操作逻辑(query()、insert()、update()、delete()等标准接口)。
  • 跨进程通信支持‌:底层基于 Android ‌Binder 机制‌实现进程间通信(IPC),确保数据交互高效且安全。
  • 数据安全:ContentProvider可以通过权限控制来保护数据。比如,你可以设置只有特定应用才能访问你的数据。

2. 典型使用场景

场景说明
系统数据访问读取通讯录、短信、媒体文件等系统内置数据。
应用间数据共享例如电商应用向物流应用提供订单状态数据。
内部数据封装统一管理应用内多模块数据访问逻辑(如本地缓存与网络数据整合)。

二、创建和使用 ContentProvider

1. 定义数据模型与 Contract 类

使用 ‌Contract 类‌ 统一管理 URI、表名及列名,提升代码可维护性:

public final class UserContract {  public static final String AUTHORITY = "com.example.provider";  public static final Uri CONTENT_URI= Uri.parse("content://" + AUTHORITY + "/users");  public static class UserEntry implements BaseColumns {  public static final String TABLE_NAME = "users";  public static final String COLUMN_NAME = "name";  public static final String COLUMN_AGE = "age";  }  
}  

2. 实现 Provider 类

继承 ContentProvider 并重写关键方法,集成 SQLite 数据库操作( CRUD) :

public class UserProvider extends ContentProvider {  private SQLiteOpenHelper mDbHelper;  @Override  public boolean onCreate() {  mDbHelper = new UserDatabaseHelper(getContext()); // 自定义数据库帮助类  return true; // 初始化数据库等资源,返回 true 表示成功   }  @Override  public Cursor query(Uri uri, String[] projection, String selection,  String[] selectionArgs, String sortOrder) {  SQLiteDatabase db = mDbHelper.getReadableDatabase();  SQLiteQueryBuilder qb = new SQLiteQueryBuilder();  qb.setTables(UserEntry.TABLE_NAME);  Cursor cursor = qb.query(db, projection, selection, selectionArgs,  null, null, sortOrder);  cursor.setNotificationUri(getContext().getContentResolver(), uri);  return cursor;  // 查询数据,返回 Cursor 对象  }@Override  public Uri insert(Uri uri, ContentValues values) {  // 插入数据,返回新记录的 URI  }  @Override  public int update(Uri uri, ContentValues values, String selection,  String[] selectionArgs) {  // 更新数据,返回受影响的行数  }  @Override  public int delete(Uri uri, String selection, String[] selectionArgs) {  // 删除数据,返回受影响的行数  }  @Override  public String getType(Uri uri) {  // 返回 URI 对应的 MIME 类型  }  
}  
  • onCreate() 在主线程执行,要避免耗时操作。可以在 onCreate() 中初始化线程池,或在 CRUD 方法中启动 AsyncTask
  • 所有 CRUD 方法需处理线程安全问题。

3. 定义 URI 规则

  • URI 结构‌:content://<Authority>/<Path>/<ID>
    • Authority‌:唯一标识 Provider(需在 AndroidManifest.xml 中声明)。
    • Path‌:标识数据表或资源类型(如 userorder)。
  • 使用 UriMatcher:根据 URI 区分操作类型(如单条或多条数据) ‌
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);  
static {  sUriMatcher.addURI(UserContract.AUTHORITY, "users", USERS);  sUriMatcher.addURI(UserContract.AUTHORITY, "users/#", USER_ID);  
}  @Override  
public Uri insert(Uri uri, ContentValues values) {  switch (sUriMatcher.match(uri)) {  case USERS:  long id = db.insert(UserEntry.TABLE_NAME, null, values);  return ContentUris.withAppendedId(uri, id);  default:  throw new IllegalArgumentException("Unsupported URI: " + uri);  }  
}  

4. 注册与权限控制

在 AndroidManifest.xml 中声明provider:

<!-- 定义自定义权限 -->  
<permission android:name="com.example.READ_USERS"  android:protectionLevel="dangerous" />  
<permission android:name="com.example.WRITE_USERS"  android:protectionLevel="dangerous" />  <!-- 应用权限到 Provider --> 
<provider  android:name=".UserProvider" <!-- Provider 实现类的全路径 -->  android:authorities="com.example.provider" <!-- 唯一标识符,与Contract类一致 -->  android:exported="true" <!-- 是否允许其他应用访问(默认 false) -->   android:readPermission="com.example.READ_USERS"  android:writePermission="com.example.WRITE_USERS" />  
  • android:name:指向继承 ContentProvider 的具体实现类(如 UserProvider)。
  • android:authorities:唯一标识 Provider 的 URI 前缀(如 content://com.example.provider/users
  • exported:是否允许其他应用访问(默认为 false)。
  • protectionLevel 设为 dangerous 表示需用户手动授权。
  • readPermission/writePermission:自定义权限控制。

在 Provider 方法中动态检查权限:

@Override  
public Cursor query(Uri uri, String[] projection, String selection,  String[] selectionArgs, String sortOrder) {  if (getContext().checkCallingPermission("com.example.READ_DATA")  != PackageManager.PERMISSION_GRANTED) {  throw new SecurityException("Permission denied");  }  // 执行查询逻辑  
}  @Override  
public int delete(Uri uri, String selection, String[] selectionArgs) {  if (getContext().checkCallingPermission("com.example.WRITE_USERS")  != PackageManager.PERMISSION_GRANTED) {  throw new SecurityException("Permission denied");  }  // 删除逻辑  
}  

注意‌:静态权限声明需配合动态校验

5. 客户端调用

调用方配置:

<manifest ...>  <!-- 声明权限 -->  <uses-permission android:name="com.example.READ_USERS" />  <uses-permission android:name="com.example.WRITE_USERS" />  <application ...>  <!-- 无 Provider 声明,直接通过 ContentResolver 调用 -->  </application>  
</manifest>  

通过 ContentResolver 访问和操作 Provider 数据:

// 插入数据  
ContentValues values = new ContentValues();  
values.put(UserEntry.COLUMN_NAME, "Alice");  
values.put(UserEntry.COLUMN_AGE, 25);  
getContentResolver().insert(UserContract.CONTENT_URI, values);  // 查询数据  
Cursor cursor = getContentResolver().query(  UserContract.CONTENT_URI,  new String[]{UserEntry._ID, UserEntry.COLUMN_NAME},  UserEntry.COLUMN_AGE + " > ?",  new String[]{"20"},  null  
);  

调用方无需声明 <provider>,但需通过权限声明和 URI 匹配访问目标 Provider,并遵循 Provider 方的路径与权限规则。

  • 客户端无需直接操作 Provider 实例。
  • 跨进程时需声明权限。

三、跨应用权限控制

配置目标实现方式
跨应用调用权限调用方声明 <uses-permission>,Provider 方配置 android:exported="true"
动态权限申请针对 dangerous 级别权限,调用方需在运行时请求用户授权。
路径级访问控制Provider 方通过 <path-permission> 细化权限,调用方需匹配声明。

1. 声明 Provider 权限

<!-- 定义自定义权限 -->  
<permission android:name="com.example.READ_USERS"  android:protectionLevel="dangerous" />  
<permission android:name="com.example.WRITE_USERS"  android:protectionLevel="dangerous" />  <!-- 应用权限到 Provider --> 
<provider  android:name=".UserProvider" <!-- Provider 实现类的全路径 -->  android:authorities="com.example.provider" <!-- 唯一标识符,与Contract类一致 -->  android:exported="true" <!-- 是否允许其他应用访问(默认 false) -->   android:readPermission="com.example.READ_USERS"  android:writePermission="com.example.WRITE_USERS" />  
  • protectionLevel 设为 dangerous 表示需用户手动授权。
  • readPermission/writePermission:自定义权限控制。

2. 路径级权限细化(可选)

若 Provider 方通过 <path-permission> 限制特定路径,调用方需确保拥有对应权限:

<!-- Provider 方配置 -->  
<provider ...>  <path-permission  android:pathPrefix="/admin"  android:permission="com.example.ADMIN_PERMISSION" />  
</provider>  

3. 调用方配置

<manifest ...>  <!-- 声明权限 -->  <uses-permission android:name="com.example.READ_USERS" />  <uses-permission android:name="com.example.WRITE_USERS" />  <!-- 如果存在路径细化,调用方需声明额外权限 -->  <uses-permission android:name="com.example.ADMIN_PERMISSION" />  <application ...>  <!-- 无 Provider 声明,直接通过 ContentResolver 调用 -->  </application>  
</manifest>  

4. 动态权限申请 

在调用方的 Activity/Fragment 中实现动态权限申请流程:

public class MainActivity extends AppCompatActivity {  private static final int REQUEST_READ_PERMISSION = 100;  @Override  protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  // 检查权限  if (ContextCompat.checkSelfPermission(this, "com.example.READ_USERS")  != PackageManager.PERMISSION_GRANTED) {  // 权限未授予,显示申请弹窗  ActivityCompat.requestPermissions(this,  new String[]{"com.example.READ_USERS"},  REQUEST_READ_PERMISSION);  } else {  // 已授权,执行数据访问  queryData();  }  }  // 处理权限申请结果  @Override  public void onRequestPermissionsResult(int requestCode,  @NonNull String[] permissions, @NonNull int[] grantResults) {  super.onRequestPermissionsResult(requestCode, permissions, grantResults);  if (requestCode == REQUEST_READ_PERMISSION) {  if (grantResults.length > 0 && grantResults[0]== PackageManager.PERMISSION_GRANTED) {  queryData();  } else {  // 权限被拒绝,提示用户  Toast.makeText(this, "权限被拒绝,无法读取数据",Toast.LENGTH_SHORT).show();  }  }  }  private void queryData() {  // 通过 ContentResolver 访问 Provider 数据  Cursor cursor = getContentResolver().query(  UserContract.CONTENT_URI,  null, null, null, null  );  // 处理查询结果...  }  
}  

同一权限组内的权限只需申请一次(如 READ_CONTACTS 和 WRITE_CONTACTS 属于同一组)

4. ‌用户拒绝后引导设置‌

若用户勾选“不再询问”,需引导用户前往系统设置手动开启权限(可通过 shouldShowRequestPermissionRationale 判断)。

if (ActivityCompat.shouldShowRequestPermissionRationale(this,"com.example.READ_USERS")) {  // 用户之前可能拒绝过权限但未勾选“不再询问”// 展示解释性弹窗后再次申请  
} else {  // 用户勾选“不再询问”或系统禁止权限(如厂商定制 ROM 限制)// 跳转系统设置界面手动开启权限 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);  intent.setData(Uri.parse("package:" + getPackageName()));  startActivity(intent);  
}  

若用户‌从未请求过该权限‌,shouldShowRequestPermissionRationale() 也会返回 false。但此时代码通常不会进入此分支(因首次请求时直接调用 requestPermissions())。

部分设备可能不支持 Settings.ACTION_APPLICATION_DETAILS_SETTINGS,需增加异常捕获并提示用户手动查找权限设置 。 

四、数据变更通知

角色职责
客户端注册 ContentObserver 并实现 onChange 回调逻辑(如刷新 UI)。
ContentProvider数据变更时调用 notifyChange 触发通知。
系统服务通过 ContentService 统一管理观察者,完成消息分发。

1. 客户端注册观察者

在使用数据的客户端(如 Activity、Fragment)中,通过 ContentResolver 注册 ContentObserver,并指定监听的目标 URI,从而实时更新UI。

// 使用者(Activity)通过ContentResolver注册观察者  
getContentResolver().registerContentObserver(  UserContract.CONTENT_URI,  true,  // 是否监听子 URI  new ContentObserver(new Handler()) {  @Override  public void onChange(boolean selfChange) {  // 数据变化时触发回调}  }  
);
  • registerContentObserver 是客户端主动调用的方法,用于绑定观察者与目标数据 URI。
  • true 表示监听该 URI 及其所有子路径(如 content://com.example.provider/users/)的数据变更。

2. 提供者触发通知

在 ‌ContentProvider‌ 中,当数据发生变更(如 insertupdatedelete)时,需调用 notifyChange 方法触发回调:

// 在 Provider 的 insert/update/delete 方法中  
getContext().getContentResolver().notifyChange(uri, null);  
  • notifyChange 会通知所有注册了该 URI 的观察者。
  • 可通过第二个参数 observer 指定跳过特定观察者(通常设为 null)。

3. 系统级支持

  • ContentService‌:负责管理所有注册的观察者,以树形结构维护 URI 监听关系,实现高效的跨进程通知分发。
  • Binder 机制‌:底层通过 Binder 传递观察者对象(封装为 Transport 代理),确保跨进程通信的可行性。

客户端需主动注册观察者监听 URI,而通知触发由 Provider 发起,两者通过系统服务协同实现实时数据同步。

五、多表关联与视图

场景CODE_BOOKS_WITH_AUTHORS (多表关联查询)CODE_VIEW_BOOKS (视图查询)
实现方式运行时动态拼接 SQL JOIN预定义视图(静态 SQL)
灵活性支持动态筛选条件(如 LIKE筛选条件受视图定义限制
性能依赖索引优化视图可预编译优化
适用场景需要灵活关联条件的查询高频复杂查询(如报表)
字段冲突解决需手动设置列别名(AS视图定义时已解决别名问题

1. 定义 Contract 类

public final class BookstoreContract {public static final String AUTHORITY = "com.example.bookstore.provider";public static final Uri BASE_URI = Uri.parse("content://" + AUTHORITY);// 动态 JOIN 查询的 URI 路径public static class BooksWithAuthors implements BaseColumns {public static final String PATH = "books_with_authors";public static final Uri CONTENT_URI= Uri.withAppendedPath(BASE_URI, PATH);public static final String CONTENT_TYPE= "vnd.android.cursor.dir/vnd.bookstore.books_with_authors";}// 视图查询的 URI 路径public static class ViewBooks implements BaseColumns {public static final String PATH = "view_books";public static final Uri CONTENT_URI= Uri.withAppendedPath(BASE_URI, PATH);public static final String CONTENT_TYPE= "vnd.android.cursor.dir/vnd.bookstore.view_books";}
}

2.  ContentProvider 实现类

  • 多表动态关联查询‌(CODE_BOOKS_WITH_AUTHORS
    • 用 SQLiteQueryBuilder 动态构建 LEFT JOIN 查询,关联 books 表和 authors 表。
    • setTables() 指定关联逻辑,setProjectionMap() 解决字段冲突(如列别名定义)。
  • 视图查询‌(CODE_VIEW_BOOKS
    • 预定义视图 view_books_with_authors,将 LEFT JOIN 逻辑固化到数据库中。
    • 直接通过视图名称查询数据,简化复杂查询的调用过程。
public class BookstoreProvider extends ContentProvider {private static final String TAG = "BookstoreProvider";private SQLiteOpenHelper mDbHelper;// UriMatcher 标识码定义private static final int CODE_BOOKS_WITH_AUTHORS = 100;  // 动态 JOIN 查询private static final int CODE_VIEW_BOOKS = 200;           // 视图查询private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);static {sUriMatcher.addURI(BookstoreContract.AUTHORITY,BookstoreContract.BooksWithAuthors.PATH,CODE_BOOKS_WITH_AUTHORS);sUriMatcher.addURI(BookstoreContract.AUTHORITY,BookstoreContract.ViewBooks.PATH,CODE_VIEW_BOOKS);}// 列名映射(解决多表字段冲突)private static final HashMap<String, String> sBooksMap= new HashMap<>();static {sBooksMap.put(BooksWithAuthors._ID, "books._id AS _id");sBooksMap.put("title", "books.title");sBooksMap.put("author_name", "authors.name AS author_name");}@Overridepublic Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();String table = null;  // 默认表名switch (sUriMatcher.match(uri)) {// 动态 JOIN 查询(CODE_BOOKS_WITH_AUTHORS)case CODE_BOOKS_WITH_AUTHORS:queryBuilder.setTables("books LEFT JOIN authors ON books.author_id = authors._id");queryBuilder.setProjectionMap(sBooksMap);break;// 视图查询(CODE_VIEW_BOOKS)case CODE_VIEW_BOOKS:table = "view_books_with_authors";  // 直接查询预定义的视图queryBuilder.setTables(table);break;default:throw new IllegalArgumentException("Unknown URI: " + uri);}SQLiteDatabase db = mDbHelper.getReadableDatabase();Cursor cursor;if (table == null) {// 动态 JOIN 查询cursor = queryBuilder.query(db,projection,selection,selectionArgs,null,  // groupBynull,  // havingsortOrder);} else {// 视图查询(直接使用标准查询)cursor = db.query(table,projection,selection,selectionArgs,null,  // groupBynull,  // havingsortOrder);}cursor.setNotificationUri(getContext().getContentResolver(), uri);return cursor;}@Overridepublic boolean onCreate() {mDbHelper = new BookstoreDbHelper(getContext());return true;}// 其他必要方法(insert/update/delete/getType)省略...
}

3. 创建数据库视图(SQLiteOpenHelper)

public class BookstoreDbHelper extends SQLiteOpenHelper {private static final String DATABASE_NAME = "bookstore.db";private static final int DATABASE_VERSION = 1;// 基表定义private static final String SQL_CREATE_BOOKS ="CREATE TABLE books (" +"_id INTEGER PRIMARY KEY AUTOINCREMENT," +"title TEXT NOT NULL," +"author_id INTEGER," +"FOREIGN KEY(author_id) REFERENCES authors(_id))";private static final String SQL_CREATE_AUTHORS ="CREATE TABLE authors (" +"_id INTEGER PRIMARY KEY AUTOINCREMENT," +"name TEXT NOT NULL)";// 视图定义(固化多表关联逻辑)private static final String SQL_CREATE_VIEW_BOOKS_WITH_AUTHORS ="CREATE VIEW view_books_with_authors AS " +"SELECT books._id, books.title, authors.name AS author_name " +"FROM books LEFT JOIN authors ON books.author_id = authors._id";@Overridepublic void onCreate(SQLiteDatabase db) {db.execSQL(SQL_CREATE_AUTHORS);db.execSQL(SQL_CREATE_BOOKS);db.execSQL(SQL_CREATE_VIEW_BOOKS_WITH_AUTHORS); // 创建视图}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {db.execSQL("DROP VIEW IF EXISTS view_books_with_authors");db.execSQL("DROP TABLE IF EXISTS books");db.execSQL("DROP TABLE IF EXISTS authors");onCreate(db);}
}

4. 客户端调用对比

// 动态 JOIN 查询(CODE_BOOKS_WITH_AUTHORS)
Cursor dynamicJoinCursor = getContentResolver().query(BookstoreContract.BooksWithAuthors.CONTENT_URI,new String[]{"title", "author_name"},"author_name LIKE ?",new String[]{"张%"},null
);// 视图查询(CODE_VIEW_BOOKS)
Cursor viewCursor = getContentResolver().query(BookstoreContract.ViewBooks.CONTENT_URI,new String[]{"title", "author_name"},null,null,"title ASC"
);

六、异步处理

场景推荐方案优势缺点
批量写入线程池 + Handler高吞吐量,可控并发度代码复杂度高,回调繁琐
列表数据加载AsyncQueryHandler自动线程管理,简化代码Android 11+ 已废弃,推荐用协程
实时数据同步ContentObserver精准监听特定数据源变化频繁更新可能引发过多回调,延迟+消耗

1. 异步批量插入(线程池 + Handler)

场景‌:后台线程执行大数据量插入,避免阻塞 UI 线程(主线程)。

public class BookProvider extends ContentProvider {private ExecutorService mExecutor = Executors.newFixedThreadPool(4);private Handler mHandler = new Handler(Looper.getMainLooper());private SQLiteOpenHelper mDbHelper;@Overridepublic boolean onCreate() {mDbHelper = new BookDbHelper(getContext());return true;}@Overridepublic int bulkInsert(Uri uri, ContentValues[] values) {mExecutor.execute(() -> {SQLiteDatabase db = mDbHelper.getWritableDatabase();db.beginTransaction();try {for (ContentValues value : values) {db.insert("books", null, value);}db.setTransactionSuccessful();} finally {db.endTransaction();// 主线程通知数据变更mHandler.post(() -> {getContext().getContentResolver().notifyChange(uri, null);});}});return values.length; // 返回预计插入数量(实际需回调确认)}
}

调用示例‌:

ContentValues[] valuesArray = new ContentValues[100];
// 填充 valuesArray...
ContentResolver resolver = getContentResolver();
resolver.bulkInsert(BookContract.CONTENT_URI, valuesArray);
  • 使用线程池管理并发写入
  • 通过 Handler 切换至主线程发送变更通知

‌2. 异步查询(AsyncQueryHandler)

场景‌:列表页异步加载数据并自动更新 UI。

public class BookListActivity extends AppCompatActivity {private ListView mListView;private SimpleCursorAdapter mAdapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_book_list);mListView = findViewById(R.id.list_view);// 初始化适配器mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, null, new String[]{"title", "author"}, new int[]{android.R.id.text1, android.R.id.text2}, 0);mListView.setAdapter(mAdapter);// 启动异步查询:AsyncQueryHandler asyncHandler= new AsyncQueryHandler(getContentResolver()) {@Overrideprotected void onQueryComplete(int token, Object cookie, Cursor cursor) {mAdapter.swapCursor(cursor);}};asyncHandler.startQuery(0, null, BookContract.CONTENT_URI,new String[]{"_id", "title", "author"}, "category=?", new String[]{"tech"}, "rating DESC");}
}
  • AsyncQueryHandler 自动管理线程切换
  • 查询结果直接更新 CursorAdapter 关联的 UI

 3. 数据变更监听(ContentObserver)

场景‌:实时监测收藏夹数据变化并刷新界面。

public class FavoriteFragment extends Fragment {private FavoriteAdapter mAdapter;private ContentObserver mObserver;@Overridepublic void onResume() {super.onResume();// 注册监听器:mObserver = new ContentObserver(new Handler()) {@Overridepublic void onChange(boolean selfChange) {loadData(); // 数据变化时重新加载}};getActivity().getContentResolver().registerContentObserver(BookContract.Favorite.CONTENT_URI,true,mObserver);}@Overridepublic void onPause() {super.onPause();// 注销监听防止内存泄漏:getActivity().getContentResolver().unregisterContentObserver(mObserver);}private void loadData() {new AsyncTask<Void, Void, Cursor>() {@Overrideprotected Cursor doInBackground(Void... voids) {return getActivity().getContentResolver().query(BookContract.Favorite.CONTENT_URI,null, null, null, "last_updated DESC");}@Overrideprotected void onPostExecute(Cursor cursor) {mAdapter.swapCursor(cursor);}}.execute();}
}
  • ContentObserver 监听指定 URI 的数据变化
  • AsyncTask 执行后台查询(注意 Android 11+ 已弃用,建议替换为协程或线程池)

相关文章:

【Android】四大组件之ContentProvider

目录 一、什么是 ContentProvider 二、创建和使用 ContentProvider 三、跨应用权限控制 四、数据变更通知 五、多表关联与视图 六、异步处理 你手机里的通讯录&#xff0c;存储了所有联系人的信息。如果你想把这些联系人信息分享给其他App&#xff0c;就可以通过ContentP…...

Qwen3 发布:优化编码与代理能力,强化 MCP 支持引领 AI 新潮流

人工智能领域的每一次重大突破都如同璀璨星辰&#xff0c;照亮了人类前行的道路。2025 年 4 月 29 日凌晨&#xff0c;阿里巴巴旗下的 Qwen 官方团队正式发布了最新一代大语言模型 ——Qwen3&#xff0c;犹如一颗重磅炸弹&#xff0c;在 AI 领域掀起了惊涛骇浪。此次发布&#…...

LEETERS题解

【题目描述】 给出一个rowcolrowcol的大写字母矩阵&#xff0c;一开始的位置为左上角&#xff0c;你可以向上下左右四个方向移动&#xff0c;并且不能移向曾经经过的字母。问最多可以经过几个字母。 【输入】 第一行&#xff0c;输入字母矩阵行数RR和列数SS&#xff0c;1≤R,S≤…...

图像加密算法概述

版本: 1.0 日期: 2025年5月1日 目录 引言 1.1 什么是图像加密?1.2 为什么需要图像加密?1.3 图像数据的特点与加密挑战加密基础概念 2.1 明文与密文2.2 加密与解密2.3 密钥2.4 对称加密与非对称加密为什么传统文本加密算法不完全适用于图像? 3.1 数据量巨大3.2 高度冗余性…...

loads、dumps、jsonpath使用场景

在处理JSON数据时&#xff0c;loads、dumps 和 jsonpath 是三个非常有用的工具或概念。它们各自在不同的场景下发挥作用&#xff0c;让我们一一来看&#xff1a; 1. loads loads 函数是 Python 中 json 模块的一部分&#xff0c;用于将 JSON 格式的字符串解析成 Python 的数据…...

Winform(7.序列化方式整理)

今天我又对序列化方式进行了整理,可以与上一篇序列化方式一起看 一.序列化方式(四种) 1.二进制序列化 //定义 Person 类,需要标记为可序列化 [Serializable] public class Person { public string Name{get;set;} public int Age{get;set;} } 在进行二进制序列化…...

通过AI的联网功能提升搜索检索能力

以百度ai搜索&#xff08;百度AI搜索 - 办公学习一站解决&#xff09;为例&#xff0c;ai会自动根据问题搜集现有互联网文章&#xff0c;避免人工通过传统检索引擎的结果逐个去查找&#xff0c;这种方式文章的相关性会更高。 tip&#xff1a;快速查看每篇文档&#xff0c;仅关…...

Spring IoC容器的设计与实现

Spring整体架构与模块划分 核心容器&#xff08;Core Container&#xff09; spring-core 基础工具类&#xff1a;如资源加载&#xff08;Resource接口&#xff09;、反射工具&#xff08;ReflectionUtils&#xff09;、类型转换&#xff08;ConversionService&#xff09;。…...

使用vue的插值表达式渲染变量,格式均正确,但无法渲染

如图&#xff0c;作者遇到的问题为&#xff0c;输入以下代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><…...

数据库 AI 助手测评:Chat2DB、SQLFlow 等工具如何提升开发效率?

一、引言:数据库开发的 “效率革命” 正在发生 在某互联网金融公司的凌晨故障现场,资深 DBA 正满头大汗地排查一条执行超时的 SQL—— 该语句涉及 7 张核心业务表的复杂关联,因索引缺失导致全表扫描,最终引发交易系统阻塞。这类场景在传统数据库开发中屡见不鲜:据 Gartne…...

21.1Linux中的LCD驱动实验(知识)_csdn

1、LCD 和 LTDC 简介 1.1、LCD 简介 1.1.1、分辨率 1.1.2、像素格式 可以看到红、绿、蓝每个8位&#xff0c;还有一位是A7~A0就是透明通道&#xff0c;32位ARG8888。 1.1.3、LCD 屏幕接口 1.1.4、LCD 时间参数 如果将 LCD 显示一帧图像的过程想象成绘画&#xff0c;那么…...

Angular教程前言:历史、安装与用途

Angular 是一个强大且流行的开源前端 Web 应用程序框架&#xff0c;由 Google 开发并维护 1。它在现代 Web 开发中占据着重要的地位&#xff0c;尤其在构建动态、高效且可扩展的 Web 应用程序方面表现出色&#xff0c;特别适用于单页应用程序 (SPA) 和复杂的用户界面 1。本教程…...

node.js模块化步骤(各标准区别)CommonJS规范、AMD规范、UMD规范、ES Modules (ESM)

前后端建议统一使用ESM 文章目录 Node.js模块化发展历程与标准对比一、模块化的意义1.1 解决的核心问题1.2 没有模块化的问题 二、CommonJS规范2.1 核心特征2.2 实现示例 三、AMD (Asynchronous Module Definition)3.1 特点3.2 代码示例 四、UMD (Universal Module Definition)…...

Unity图片导入设置

&#x1f3c6; 个人愚见&#xff0c;没事写写笔记 &#x1f3c6;《博客内容》&#xff1a;Unity3D开发内容 &#x1f3c6;&#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f50e;Unity支持的图片格式 ☀️BMP:是Windows操作系统的标准图像文件格式&#xff0c;特点是…...

MySQL与分布式架构的碰撞

目录 一、分布式架构的核心挑战与MySQL的应对策略 1.1 高并发与扩展性 1.3 高可用与容灾 二、MySQL分布式架构的核心技术实现 2.1 读写分离与主从复制&#xff08;扩展&#xff09; 2.2 数据分片与分布式存储&#xff08;扩展&#xff09; 2.3 MySQL Cluster与NDB引擎&am…...

python-MySQL鏈接

python鏈接MySQL&#xff0c;主要利用庫 pip install mysql-connector-pythonimport mysql.connector# 配置连接参数 config {"user": "your_username","password": "your_password","host": "localhost", # 或…...

cv::remap() 和 cv::undistortion() 的区别

在 OpenCV 中&#xff0c;cv::remap 和 cv::undistort 都用于处理图像畸变校正&#xff0c;但它们的实现方式和应用场景有显著区别。以下是详细对比&#xff1a; 1. cv::undistort&#xff1a;直接畸变校正 功能 输入&#xff1a;原始畸变图像 相机内参矩阵 (cameraMatrix) …...

【AI提示词】决策树专家

提示说明 一位熟悉决策树算法的机器学习专家&#xff0c;擅长用树状图量化不同选择的结果概率。 提示词 # Role: 决策树专家## Profile - language: 中文 - description: 一位熟悉决策树算法的机器学习专家&#xff0c;擅长用树状图量化不同选择的结果概率 - background: 决…...

【中间件】bthread_数据结构_学习笔记

bthread数据结构 bthread_数据结构_学习笔记1 pthread_cond_t1.1 definition1.2 解释1.3 设计动机1.4 使用示例1.5 注意事项1.6 进一步延伸&#xff1a;pthread_cond_s 2 pthread_mutex_t bthread_数据结构_学习笔记 1 pthread_cond_t POSIX线程库 /usr/include/x86_64-linux…...

VM虚拟机安装CentOS7.9

目录 1.下载CentOS7.9 2.VM虚拟机选择自定义&#xff0c;然后一直傻瓜式下一步 3.选择编辑虚拟机设置&#xff0c;然后选择刚刚下载的ISO 4.输入 ip addr 获取ip地址 5.用Xshell连接 1.下载CentOS7.9 链接&#xff1a;https://pan.baidu.com/s/1kW2gGWnbcjNtq4kz46LKVw?p…...

C++/SDL 进阶游戏开发 —— 双人塔防(代号:村庄保卫战 18)

&#x1f381;个人主页&#xff1a;工藤新一 &#x1f50d;系列专栏&#xff1a;C面向对象&#xff08;类和对象篇&#xff09; &#x1f31f;心中的天空之城&#xff0c;终会照亮我前方的路 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 文章目录 二…...

Cribl 数据脱敏 更多方法 MASK (三)

我做过好几个cribl 数据脱敏的实验: Cribl 脱敏mask-CSDN博客...

【笔记】深度学习模型训练的 GPU 内存优化之旅⑤:内存分配篇

开设此专题&#xff0c;目的一是梳理文献&#xff0c;目的二是分享知识。因为笔者读研期间的研究方向是单卡上的显存优化&#xff0c;所以最初思考的专题名称是“显存突围&#xff1a;深度学习模型训练的 GPU 内存优化之旅”&#xff0c;英文缩写是 “MLSys_GPU_Memory_Opt”。…...

【5G 架构】边缘计算平台是如何与3GPP网络连接的?

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G技术研究。 博客内容主要围绕…...

5.0.0 GripSpliter的使用(探讨水平竖直对齐参数)

布局控件Grid 配合 GridSplitter 无需编写任何代码 就能实现网格大小可拖动。 其HorizontalAlignment、VerticalAlignment属性的使用非常具有迷惑性;本文做了一些一些实验,总结为把这两个属性均设置为strech即可。 总结如下:经过实验,发现以下情况可以正常工作。 水平方向…...

python如何把pdf转word

在Python中将PDF转换为Word文档&#xff08;.docx&#xff09;比反向转换&#xff08;Word转PDF&#xff09;更具挑战性&#xff0c;因为PDF是固定格式&#xff0c;而Word是可编辑格式。以下是几种可行的方法及详细步骤&#xff1a; 方法1&#xff1a;使用 pdf2docx 库 pdf2do…...

go实现双向链表

需求 实现双向链表的节点生成、正反向遍历、指定删除。 实现 package mainimport ("fmt" )type zodiac_sign struct {number intdizhi stringanimal stringyear intprevious *zodiac_signnext *zodiac_sign }// 添加 // func add_node_by_order(pr…...

33、VS中提示“以下文件中的行尾不一致。是否将行尾标准化?“是什么意思?

在Visual Studio&#xff08;VS&#xff09;中遇到提示“以下文件中的行尾不一致。是否将行尾标准化&#xff1f;”时&#xff0c;意味着当前打开或正在编辑的文件内部存在行尾符&#xff08;EOL&#xff0c;End-Of-Line&#xff09;格式不统一的情况。以下是详细解释和应对建议…...

C 语言 第五章 指针(5)

目录 函数参数传递机制&#xff1a;地址传递 值传递 简单变量指针作为形参 举例1&#xff1a; 举例2&#xff1a; 举例3&#xff1a; 数组作为形参 举例&#xff1a; 函数参数传递机制&#xff1a;地址传递 值传递 void test(int a, int b) { a 10; b 20; print…...

Python项目源码69:Excel数据筛选器1.0(tkinter+sqlite3+pandas)

功能说明&#xff1a;以下是一个使用Tkinter和Pandas实现的完整示例&#xff0c;支持Excel数据读取、双表格展示和高级条件筛选功能&#xff1a; 1.文件操作&#xff1a;点击"打开文件"按钮选择Excel文件&#xff08;支持.xlsx和.xls格式&#xff09;&#xff0c;自…...

机器人--架构及设备

机器人的四大组成部分 控制系统 驱控系统 驱控驱动系统控制系统。 注意&#xff0c;这里的控制系统不是机器人层面的控制系统&#xff0c;属于更小层级的&#xff0c;驱控系统的控制系统。 驱动系统&#xff1a; 一般指硬件设备&#xff0c;比如电机驱动器&#xff0c;I/O…...

机器人--主机--控制系统

机器人主机 机器人主机&#xff0c;即控制系统。 作用 机器人主机的核心功能 传感器数据处理&#xff1a;处理摄像头、激光雷达、IMU等数据。 运行SLAM/导航算法&#xff1a;如Google Cartographer、RTAB-Map。 路径规划与控制&#xff1a;执行A*、DWA等算法。 通信管理&a…...

Stm32 烧录 Micropython

目录 前言 准备工作 开始操作 问题回顾 后记 前言 去年曾经尝试Pico制作openmv固件&#xff0c;由于知识储备不够最后失败了&#xff0c;留了一个大坑&#xff0c;有了前几天的基础&#xff0c;慢慢补齐知识&#xff0c;最近这一周一直在学习如何编译Stm固件并烧录到单片机…...

leetcode 977. Squares of a Sorted Array

题目描述 双指针法一 用right表示原数组中负数和非负数的分界线。 nums[0,right-1]的是负数&#xff0c;nums[right,nums.size()-1]是非负数。 然后用合并两个有序数组的方法。合并即可。 class Solution { public:vector<int> sortedSquares(vector<int>&…...

使用Nexus搭建远程maven仓库

1、Nexus介绍 Nexus 是 Sonatype 公司的一款用于搭建私服的产品&#xff0c;使用非常广泛。在早期&#xff0c;我们都拿Nexus当maven私服仓库&#xff0c;后来&#xff0c;随着版本不断更新&#xff0c;它支持的数据类型越来越多&#xff0c;比如npm仓库&#xff0c;nuget仓库&…...

坚鹏:工行《DEEPSEEK赋能银行智能办公及数字化营销服务》培训

中国工商银行上海市分行《DEEPSEEK赋能银行智能办公及数字化营销服务》培训圆满落幕 中国工商银行作为全球领先的综合性金融服务集团&#xff0c;始终走在金融科技创新的前沿。截至2024年末&#xff0c;工商银行总资产规模突破40万亿元&#xff0c;连续多年稳居全球银行榜首。在…...

操作系统OS是如何指挥外围设备的呢?

众所周知&#xff0c;OS的职责之一就是管理外围设备&#xff0c;比如常见的磁盘、硬盘、显示器、麦克风等&#xff0c;但并不是外围设备的一切都必须由OS管理&#xff0c;比如无线鼠标上的开关键&#xff0c;当你通过它关闭鼠标时&#xff0c;这个操作并不会经过OS&#xff0c;…...

实现Sentinel与Nacos的规则双向同步

实现Sentinel与Nacos的规则双向同步&#xff1a;完整解决方案 前言 在微服务架构中&#xff0c;流量控制和熔断降级是保障系统稳定性的重要手段。阿里开源的Sentinel作为一款轻量级的流量控制组件&#xff0c;常被用于实现这些功能。然而&#xff0c;在实际生产环境中&#x…...

2025五一杯数学建模A题:支路车流量推测问题,思路分析+模型代码

一持续更新&#xff0c;见文末名片 二、问题背景 想象一下&#xff0c;城市的道路如同一张巨大的脉络图&#xff0c;主路如同大动脉&#xff0c;配备着车流量监测设备&#xff0c;能实时记录车流量数据&#xff0c;就像我们身体的传感器一样。然而&#xff0c;当多条支路像毛细…...

Linux51 安装baidunetdisk yum install rpm -ivh

推测网卡 感觉是不是以前哪里设置了下 deepseek说的这个设置 我没有设置过 这个不会弄啊 准备用虚拟机安个软件 神奇 换了这个命令又能打开网卡了 参考了这个 参考 之前地址我觉得配置错误 动态分配 我就删掉ip地址了 路由表中无ip地址吗&#xff1f; OK 卸载 运…...

【Python-Day 8】从入门到精通:Python 条件判断 if-elif-else 语句全解析

Langchain系列文章目录 01-玩转LangChain&#xff1a;从模型调用到Prompt模板与输出解析的完整指南 02-玩转 LangChain Memory 模块&#xff1a;四种记忆类型详解及应用场景全覆盖 03-全面掌握 LangChain&#xff1a;从核心链条构建到动态任务分配的实战指南 04-玩转 LangChai…...

若依 FastAPI + Vue3 项目 Docker 部署笔记( 启动器打包教程)

本文记录了将 start.bat 打包成 .exe 启动器的详细教程&#xff0c;适合项目交付或导师演示用。 &#x1f9ed; 一、如何将 start.bat 打包为启动器 .exe&#xff08;含图标 自动打开浏览器&#xff09; ✅ 1. 创建三大功能脚本 start.bat → 启动项目&#xff08;docke…...

Lebesgue测度和积分理论发展概观

1. 发展背景 积分可以从两个角度来理解。首先&#xff0c;积分是微分的逆函数&#xff0c;因此积分是反导数(译注&#xff1a;但积分是独立于微分的&#xff0c;不能微分的函数也可能可积)。然而&#xff0c;这是一个非常抽象的概念。其次&#xff0c;两点之间的积分可以看…...

算法题题型总结

二叉树题型 解法综述&#xff1a;二叉树的解法&#xff0c;基本上都是依赖遍历&#xff0c;再加上递归的思路来做的。那递归又分为深度优先和广度优先。深度优先算法&#xff0c;前序&#xff0c;中序&#xff0c;后序。广度优先&#xff0c;利用先进先出队列&#xff0c;一层…...

网络编程——TCP和UDP详细讲解

文章目录 TCP/UDP全面详解什么是TCP和UDP&#xff1f;TCP如何保证可靠性&#xff1f;1. 序列号&#xff08;Sequence Number&#xff09;2. 确认应答&#xff08;ACK&#xff09;3. 超时重传&#xff08;Timeout Retransmission&#xff09;4. 窗口控制&#xff08;Sliding Win…...

Qt多线程TCP服务器实现指南

在Qt中实现多线程TCP服务器可以通过为每个客户端连接分配独立的线程来处理&#xff0c;以提高并发性能。以下是一个分步实现的示例&#xff1a; 1. 自定义工作线程类&#xff08;处理客户端通信&#xff09; // workerthread.h #include <QObject> #include <QTcpSo…...

【经管数据】A股上市公司资产定价效率数据(2000-2023年)

数据简介&#xff1a;资产定价效率是衡量市场是否能够有效、准确地反映资产内在价值的重要指标。在理想的市场条件下&#xff0c;资产的市场价格应该与其内在价值保持一致&#xff0c;即市场定价效率达到最高。然而&#xff0c;在实际市场中&#xff0c;由于信息不对称、交易摩…...

打包 Python 项目为 Windows 可执行文件:高效部署指南

Hypackpy 是一款由白月黑羽开发的 Python 项目打包工具&#xff0c;它与 PyInstaller 等传统工具不同&#xff0c;通过直接打包解释器环境和项目代码&#xff0c;并允许开发者修改配置文件以排除不需要的内容&#xff0c;从而创建方便用户一键运行的可执行程序。以下是使用 Hyp…...

【QNX+Android虚拟化方案】138 - USB 底层传输原理

【QNX+Android虚拟化方案】138 - USB 底层传输原理 1. USB 数据包的格式2. 数据传输事务过程3. 四种传输类型3.1 批量传输3.2 中断传输3.3 实时传输3.4 控制传输4. USB 设备枚举过程4.1 Attached: 发送控制传输,读取设备描述符4.2 Power -> Default 这个状态无数据传输4.3 …...

QT6 源(66)篇三:阅读与注释类 QAbstractSpinBox ,这是螺旋框的基类,附上源码

&#xff08;9&#xff09;所有代码来自于头文件 qabstractspinbox . h : #ifndef QABSTRACTSPINBOX_H #define QABSTRACTSPINBOX_H#include <QtWidgets/qtwidgetsglobal.h> #include <QtWidgets/qwidget.h> #include <QtGui/qvalidator.h>/* QT_CONFIG宏实…...