在Activity中,启动Service有两种方式:startService方式,bindService方式。
如果想要调用Service中的方法,只能使用bindService方式。因为这种方式可以拿到Service的Binder对象,从而可以调用Service中的方法。
这里,我们不说怎么调用,只是来验证一个问题:ServiceConnection接口中的onServiceConnected方法执行在哪个线程(另一种问法是:在onServiceConnected方法中是否可以直接更新UI)。
结论:执行在主线程,也就是说,在这个方法中可以直接进行UI更新。
下面,用一个例子来证明上面的结论。
自定义Service类
public class SevenService extends Service {
private int progress = 0;
private OnProgressListener mOnProgressListener;
public interface OnProgressListener{
void onProgress(int progress);
}
public void setOnProgressListener(OnProgressListener listener){
mOnProgressListener = listener;
}
public class SevenBinder extends Binder {
public SevenService getService(){
return SevenService.this;
}
}
public int getProgress(){
return progress;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new SevenBinder();
}
//模拟下载
public void startDownload(){
new Thread(new Runnable() {
@Override
public void run() {
Log.e("startDownload()","Thread: " + Thread.currentThread().getName());//Thread: Thread-9945
while (progress < 100){
progress += 10;
//通知调用方
if(null!= mOnProgressListener){
mOnProgressListener.onProgress(progress);
}
try{
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
}
}
}).start();
}
public void startSetText(){
progress = 19;
if(null!= mOnProgressListener){
mOnProgressListener.onProgress(progress);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
Service是四大组件之一,记得在清单文件中注册。
Activity类
public class ServiceActivity extends AppCompatActivity {
private SevenService mSevenService;
private int progress;
private TextView service_text;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_service);
service_text = (TextView) findViewById(R.id.service_text);
Log.e("ServiceActivity","Thread: " + Thread.currentThread().getName());//Thread: main
//
Intent intent = new Intent(this, SevenService.class);
// 标志位BIND_AUTO_CREATE使得服务中onCreate得到执行,onStartCommand不会执行
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
//点击按钮
public void bt_download(View view){
// mSevenService.startDownload();//这个方法内部开启了子线程
mSevenService.startSetText();
}
/***
* 通过一系列验证,终于确定了:ServiceConnection的onServiceConnected方法是运行在主线程的,可以直接更新UI,
*/
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//绑定成功,回调这个方法
mSevenService = ((SevenService.SevenBinder)service).getService();
Log.e("onServiceConnected","Thread: " + Thread.currentThread().getName());//Thread: main
mSevenService.setOnProgressListener(new SevenService.OnProgressListener() {
@Override
public void onProgress(final int progress) {
Log.e("setOnProgressListener","Thread: " + Thread.currentThread().getName());//Thread: Thread-9894
//如果点击按钮调用的是startSetText()方法,这里就可以在回调中直接更新UI。
service_text.setText(""+progress);
//这里不能直接更新UI的原因是:在SevenService中,startDownload()方法开启了子线程,所以mOnProgressListener.onProgress(progress);是在子线程中执行的
//android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
// service_text.setText(""+progress);
// }
// });
}
});
}
@Override
public void onServiceDisconnected(ComponentName name) {
//如果Service中途挂掉,client端也能通过onServiceDisconnected感知到(通过Binder的linkToDeath实现)
}
};
@Override
protected void onDestroy() {
unbindService(conn);//解绑
super.onDestroy();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
从打印的日志也可以得到上述结论:
这里写图片描述
---------------------
作者:唐人小调
来源:CSDN
原文:https://blog.csdn.net/gengbaolong/article/details/78574225
版权声明:本文为博主原创文章,转载请附上博文链接!