您的位置:首页 > 编程语言 > PHP开发

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

2017-08-30 23:59 549 查看
我们四大组件都是运行在UI线程上的,之前据我自己所看到的是主线程上有耗时的操作可能会造成ANR,今天做了一个实验,建立一个工程,主Activity有一个可以触发显示一个Toast的按钮,另外还有一个SQLiteOpenHelper的子类,另外一个继承ContentProvider,提供往数据库插入数据的操作:
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
}
然后我另外建一个工程,通过getContentResolver获得对象后利用ContentProvider往数据库插1000条数据:
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
}
在插入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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐