关于“运行在主线程的ContentProvider为什么不会影响主线程”的记录
2017-08-30 23:59
549 查看
我们四大组件都是运行在UI线程上的,之前据我自己所看到的是主线程上有耗时的操作可能会造成ANR,今天做了一个实验,建立一个工程,主Activity有一个可以触发显示一个Toast的按钮,另外还有一个SQLiteOpenHelper的子类,另外一个继承ContentProvider,提供往数据库插入数据的操作:
然后我另外建一个工程,通过getContentResolver获得对象后利用ContentProvider往数据库插1000条数据:
在插入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
01 | package cth.android.verifycontentprovider; |
02 |
03 | import android.content.ContentProvider; |
04 | import android.content.ContentUris; |
05 | import android.content.ContentValues; |
06 | import android.content.UriMatcher; |
07 | import android.database.Cursor; |
08 | import android.database.sqlite.SQLiteDatabase; |
09 | import android.net.Uri; |
10 |
11 | public class MyContentProvider extends ContentProvider { |
12 |
13 | private MySQLiteOpenHelpermySQLiteOpenHelper; |
14 | private static String authority = "cth.android.verifycontentprovider.MyContentProvider" ; |
15 | private static String path = "student" ; |
16 | private static final int student = 1 ; |
17 | private static final int students = 2 ; |
18 | private UriMatcheruriMatcher = new UriMatcher(UriMatcher.NO_MATCH); |
19 | { |
20 | uriMatcher.addURI(authority,path + "/#" ,student); |
21 | uriMatcher.addURI(authority,path, students); |
22 | } |
23 |
24 | <ahref= "http://home.51cto.com/index.php?s=/space/5017954" target= "_blank" > @Override </a> |
25 | public boolean onCreate() { |
26 | mySQLiteOpenHelper= new MySQLiteOpenHelper(getContext()); |
27 | return true ; |
28 | } |
29 |
30 | <ahref= "http://home.51cto.com/index.php?s=/space/5017954" target= "_blank" > @Override </a> |
31 | public Cursorquery(Uri uri, String[] projection, String selection, |
32 | String[]selectionArgs, String sortOrder) { |
33 | //TODO Auto-generated method stub |
34 | return null ; |
35 | } |
36 |
37 | <ahref= "http://home.51cto.com/index.php?s=/space/5017954" target= "_blank" > @Override </a> |
38 | public StringgetType(Uri uri) { |
39 | //TODO Auto-generated method stub |
40 | return null ; |
41 | } |
42 |
43 | <ahref= "http://home.51cto.com/index.php?s=/space/5017954" target= "_blank" > @Override </a> |
44 | public Uriinsert(Uri uri, ContentValues values) { |
45 | UriresultUri = null ; |
46 | SQLiteDatabasemyDb = null ; |
47 | int flag= uriMatcher.match(uri); |
48 | switch (flag){ |
49 | case students: |
50 | myDb= mySQLiteOpenHelper.getWritableDatabase(); |
51 | long id= myDb.insert( "student" , null ,values); |
52 | resultUri= ContentUris.withAppendedId(uri, id); |
53 | break ; |
54 | } |
55 |
56 | return resultUri; |
57 | } |
58 |
59 | <ahref= "http://home.51cto.com/index.php?s=/space/5017954" target= "_blank" > @Override </a> |
60 | public int delete(Uri uri, String selection, String[] selectionArgs) { |
61 | //TODO Auto-generated method stub |
62 | return 0 ; |
63 | } |
64 |
65 | <ahref= "http://home.51cto.com/index.php?s=/space/5017954" target= "_blank" > @Override </a> |
66 | public int update(Uri uri, ContentValues values, String selection, |
67 | String[]selectionArgs) { |
68 | //TODO Auto-generated method stub |
69 | return 0 ; |
70 | } |
71 |
72 | } |
01 | package cth.android.verifycontentprovider_insert; |
02 |
03 | import android.app.Activity; |
04 | import android.content.ContentResolver; |
05 | import android.content.ContentValues; |
06 | import android.net.Uri; |
07 | import android.os.Bundle; |
08 | import android.util.Log; |
09 | import android.view.View; |
10 | import android.view.View.OnClickListener; |
11 | import android.widget.Button; |
12 |
13 | public class MainActivity extends Activity{ |
14 |
15 | private Buttonbtn_insertData; |
16 | <ahref= "http://home.51cto.com/index.php?s=/space/5017954" target= "_blank" > @Override </a> |
17 | protected void 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( new OnClickListener(){ |
23 |
24 | <ahref= "http://home.51cto.com/index.php?s=/space/5017954" target= "_blank" > @Override </a> |
25 | public void onClick(View v) { |
26 | new Thread( new Runnable(){ |
27 |
28 | <ahref= "http://home.51cto.com/index.php?s=/space/5017954" target= "_blank" > @Override </a> |
29 | public void run() { |
30 | for ( int i= 1 ;i<= 1000 ;i++){ |
31 | StringuriString = "content://cth.android.verifycontentprovider.MyContentProvider/student/" ; |
32 | Uriurl = Uri.parse(uriString); |
33 | ContentValuesvalues = new ContentValues(); |
34 | values.put( "id" ,i); |
35 | values.put( "name" , "Mike" +i); |
36 | values.put( "age" ,i + 10 ); |
37 | ContentResolvercr = getContentResolver(); |
38 | try { |
39 | Thread.sleep( 100 ); |
40 | } catch (InterruptedExceptione) { |
41 | e.printStackTrace(); |
42 | } |
43 | UrirowNum = cr.insert(url, values); |
44 | Log.i( "cth" ,rowNum.toString()); |
45 | } |
46 | } |
47 | }).start();; |
48 |
49 | } |
50 | }); |
51 | } |
52 | } |
相关文章推荐
- 关于“运行在主线程的ContentProvider为什么不会影响主线程”的记录
- 关于Android中为什么主线程不会因为Looper.loop()里的死循环卡死?
- 关于子线程死循环为什么不起作用的原因or线程的阻塞能影响进程
- 关于Android中为什么主线程不会因为Looper.loop()里的死循环卡死?引发的思考,事实可能不是一个 epoll 那么 简单。
- <iOS>关于子线程和block中操作主线程界面的控件讨论
- 多线程以及主线程等待并发子线程运行
- 为什么WebClient在多线程中的操作会影响到UI线程(标题党)
- 为什么Android机子运行时会卡而IPhone却不会?
- java main 线程既然被interrupt中断 为什么还会运行后面的
- 关于c++ 线程创建的线程运行函数和线程运行函数的参数(即pthread_creat()第3,4个参数)
- 关于Wind2003下MSDTC对DTS运行的影响
- 关于界面刷新,一定要在主线程哦,要不会乱出一些问题
- 创建线程后为什么关闭了线程句柄,线程还是可以运行?
- c# 子线程运行完通知主线程
- 为什么在主线程的Looper.looper死循环不会卡死
- 主线程中的Looper.loop()一直无限循环为什么不会造成ANR?
- Android中为什么主线程不会因为Looper.loop()里的死循环卡死?
- 常年的疑惑:为什么在子线程中更新主线程的UI会崩溃,或者花屏?
- 创建线程后为什么关闭了线程句柄,线程还是可以运行?
- [iOS diary]iOS在非主线程运行主线程的方法