关于“运行在主线程的ContentProvider为什么不会影响主线程”的记录

xiaoxiao2021-02-28  148

我们四大组件都是运行在UI线程上的,之前据我自己所看到的是主线程上有耗时的操作可能会造成ANR,今天做了一个实验,建立一个工程,主Activity有一个可以触发显示一个Toast的按钮,另外还有一个SQLiteOpenHelper的子类,另外一个继承ContentProvider,提供往数据库插入数据的操作: 01 packagecth.android.verifycontentprovider; 02   03 importandroid.content.ContentProvider; 04 importandroid.content.ContentUris; 05 importandroid.content.ContentValues; 06 importandroid.content.UriMatcher; 07 importandroid.database.Cursor; 08 importandroid.database.sqlite.SQLiteDatabase; 09 importandroid.net.Uri; 10   11 publicclass MyContentProvider extendsContentProvider { 12   13         privateMySQLiteOpenHelper mySQLiteOpenHelper; 14         privatestatic String authority = "cth.android.verifycontentprovider.MyContentProvider"; 15         privatestatic String path = "student"; 16         privatestatic final int student = 1; 17         privatestatic final int students = 2; 18         privateUriMatcher uriMatcher = newUriMatcher(UriMatcher.NO_MATCH); 19         { 20                 uriMatcher.addURI(authority, path + "/#", student); 21                 uriMatcher.addURI(authority, path, students); 22         } 23   24         <a href="http://home.51cto.com/index.php?s=/space/5017954"target="_blank">@Override</a> 25         publicboolean onCreate() { 26                 mySQLiteOpenHelper = newMySQLiteOpenHelper(getContext()); 27                 returntrue; 28         } 29   30         <a href="http://home.51cto.com/index.php?s=/space/5017954"target="_blank">@Override</a> 31         publicCursor query(Uri uri, String[] projection, String selection, 32                         String[] selectionArgs, String sortOrder) { 33                 // TODO Auto-generated method stub 34                 returnnull; 35         } 36   37         <a href="http://home.51cto.com/index.php?s=/space/5017954"target="_blank">@Override</a> 38         publicString getType(Uri uri) { 39                 // TODO Auto-generated method stub 40                 returnnull; 41         } 42   43         <a href="http://home.51cto.com/index.php?s=/space/5017954"target="_blank">@Override</a> 44         publicUri insert(Uri uri, ContentValues values) { 45                 Uri resultUri = null; 46                 SQLiteDatabase myDb = null; 47                 intflag = uriMatcher.match(uri); 48                 switch(flag) { 49                 casestudents: 50                         myDb = mySQLiteOpenHelper.getWritableDatabase(); 51                         longid = myDb.insert("student",null, values); 52                         resultUri = ContentUris.withAppendedId(uri, id); 53                         break; 54                 } 55   56                 returnresultUri; 57         } 58   59         <a href="http://home.51cto.com/index.php?s=/space/5017954"target="_blank">@Override</a> 60         publicint delete(Uri uri, String selection, String[] selectionArgs) { 61                 // TODO Auto-generated method stub 62                 return0; 63         } 64   65         <a href="http://home.51cto.com/index.php?s=/space/5017954"target="_blank">@Override</a> 66         publicint update(Uri uri, ContentValues values, String selection, 67                         String[] selectionArgs) { 68                 // TODO Auto-generated method stub 69                 return0; 70         } 71   72 } 然后我另外建一个工程,通过getContentResolver获得对象后利用ContentProvider往数据库插1000条数据: 01 packagecth.android.verifycontentprovider_insert; 02   03 importandroid.app.Activity; 04 importandroid.content.ContentResolver; 05 importandroid.content.ContentValues; 06 importandroid.net.Uri; 07 importandroid.os.Bundle; 08 importandroid.util.Log; 09 importandroid.view.View; 10 importandroid.view.View.OnClickListener; 11 importandroid.widget.Button; 12   13 publicclass MainActivity extendsActivity { 14   15         privateButton btn_insertData; 16         <a href="http://home.51cto.com/index.php?s=/space/5017954"target="_blank">@Override</a> 17         protectedvoid onCreate(Bundle savedInstanceState) { 18                 super.onCreate(savedInstanceState); 19                 setContentView(R.layout.activity_main); 20                   21                 btn_insertData = (Button) findViewById(R.id.btn_insertData); 22                 btn_insertData.setOnClickListener(newOnClickListener() { 23                           24                         <a href="http://home.51cto.com/index.php?s=/space/5017954"target="_blank">@Override</a> 25                         publicvoid onClick(View v) { 26                                 newThread(newRunnable() { 27                                           28                                         <a href="http://home.51cto.com/index.php?s=/space/5017954"target="_blank">@Override</a> 29                                         publicvoid run() { 30                                                 for(inti = 1;i <= 1000;i++) { 31                                                         String uriString = "content://cth.android.verifycontentprovider.MyContentProvider/student/"; 32                                                         Uri url = Uri.parse(uriString); 33                                                         ContentValues values = newContentValues(); 34                                                         values.put("id", i); 35                                                         values.put("name","Mike"+ i); 36                                                         values.put("age", i + 10); 37                                                         ContentResolver cr = getContentResolver(); 38                                                         try{ 39                                                                 Thread.sleep(100); 40                                                         }catch(InterruptedException e) { 41                                                                 e.printStackTrace(); 42                                                         } 43                                                         Uri rowNum = cr.insert(url, values); 44                                                         Log.i("cth",rowNum.toString()); 45                                                 } 46                                         } 47                                 }).start();; 48                                   49                         } 50                 }); 51         } 52 } 在插入1000条数据的过程中我打开包含有ContentProvider的APP,点击主Activity上的Button,结果能显示一个Toast, 意思就是其他进程利用ContentProvider机制往本进程的数据库插入数据,在插入数据的过程中不影响到本进程的UI操作,这是为什么,是本进程的ContentProvider在其他进程访问数据库时没在运行呢还是说这个ContentProvider虽说是存在于主线程,但其实是有安卓系统进行管理而不是主线程?  contentProvider的初始化是在它自己进程的主线程里面完成,一般发生在有人第一次访问这个contentProvider或者这个contentProvider进程第一次启动,比如这个进程有个service,开机启动,那么随着servier启动的还有contentProvider. contentProvider有个android:multiProcess属性,用来配置是否在多个进程里面,有不同的实例。如果为true,那么它就会在每个访问这个contentProvider的进程里面生成一个对象。这个时候调用contentProvider,就是哪个线程调用的,contentProvider就运行在那个线程里面。如果这个值配置为false,那么多个进程之间共享一个contentProvider,通过binder来进行进程之间对象传递。如果多个进程同时访问,会为每个访问请求分配个线程。所以,这些操作,比如查询,不会运行在contentProvider进程的主线程。 contentProvider查询等操作是否需要等待,需要binder来设置。 另外,contentProvider查询的数据传递是通过ashmem来完成的。 总而言之, 1. contentProvider的初始化是在主线程里面完成。 2. 请求查询等操作的话,应用程序最好自己起一个线程去完成。 3. contentProvider实现比较复杂,底层交互甚多。 首先感谢你细心的回答,看完你的回答后,我还是存在以下几个不解之处:1、您说的“contentProvider的初始化是在它自己进程的主线程里面完成”,初始化应该未生成对象吧?也就是说ContentProvider并没有在主线程生成对象,而是谁访问它,它才在访问的线程完成实例化并生成对象? 2、如果android:multiProcess的值为false,您说“多个进程之间共享一个contentProvider,通过binder来进行进程之间对象传递。”,那么传递的对象是否是在ContentProvider所属的进程完成实例化后才通过binder传递给需要的进程? 3、还有“contentProvider查询的数据传递是通过ashmem来完成的。”,是不是说存放查询结果的Cursor之所以能够跨进程返回到访问ContentProvider的进程是因为它是把返回值Cursor通过ashmem机制存放到某块内存,然后访问ContentProvider的进程再去取? 1. 第一点的话,ContentProvider初始化的时候,会把自己初始化之后生成的对象存在Ams里面,ams的话是一个系统进程。嗯,具体你可以百度下,因为内容比较多。然后其他进程去请求获取contentProvider对象时,一般第一次都会来ams里面获取。获取到之后,一般会在自己进程里面进行缓存。以便于下次获取。 2. 是的,它是ContentProvider初始化完成之后存在ams的对象,通过binder传给具体的某个调用contentProvider的进程 3. ashmem机制的话是比较底层的东西,嗯,ContentProvider通信的基础吧。大概意思就是ContentProvider进程里面有一块共享内存,用来存放这次查询的数据。然后通过binder这个内存地址传递给调用ContentProvider的进程,这样,这个调用ContentProvider的进程就能访问ContentProvider进程的共享内存了。 至于cursor的话,只是java上层的一个对象,底层ashmem那块,怎么跨进程传地址,怎么读数据已经全部封装好了。。 contentProivder 启动这块,可以参考下这个帖子: http://bbs.51cto.com/thread-1068382-1.html
转载请注明原文地址: https://www.6miu.com/read-18853.html

最新回复(0)