前言
上一章我们介绍了HandlerThread组件可以使得子线程可以发消息给主线程,甚至线程之间也可以通信。那么本章要讲的IntentService也正是这个原理。
本章先讲解IntentService的简单使用,然后在从源码的角度对IntentService进行分析。
1.什么是IntentService,IntentService有什么作用?
* @see android.support.v4.app.JobIntentService
* @see android.os.AsyncTask
*/
public abstract class IntentService extends Service {
我们看到IntentService这个类,发现了IntentService继承了Service。所以说IntentService就是一个Service。Service我们都知道是安卓的四大组件之一,主要作用就是执行一些后台任务。和Activity不一样的是Service是看不见的,无法和用户交互。但是和Activity一样的是,当没有开启子线程的时候,执行的任务都是在UI线程中执行的。当我们在UI线程执行耗时任务的时候,会导致UI线程堵塞,接着会卡顿。所以IntentService正是用来解决这个问题,也就是说,IntentService执行的后台任务是在子线程中执行的。这样一来就不会导致UI线程堵塞。
2.IntentService的简单使用
public class MyIntentService extends IntentService {
private static final String TAG ="MyIntentService" ;
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate: ");
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
super.onStart(intent, startId);
Log.e(TAG, "onStart: " );
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand: " );
return super.onStartCommand(intent, flags, startId);
}
/**
* 刷新UI接口回调
*/
public interface UpdateUi {
void update(String url);
}
private static UpdateUi mUpdateUi;
public static void updateUi(UpdateUi updateUi) {
mUpdateUi = updateUi;
}
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
String url = intent.getStringExtra("url");
String result = downLoadPhoto(url);
mUpdateUi.update(result);
}
/**
* 在这里执行后台任务
* @param url
* @return
*/
private String downLoadPhoto(String url) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "下载成功:"+url;
}
}
首先我们新建一个MyIntentService 类继承IntentService 类并重写Service的生命周期方法onCreate、onDestroy、onStart、onStartCommand。以及最重要的onHandleIntent方法。重写生命周期方法主要是为了观察生命周期的变化。创建完MyIntentService 类之后,我们来看下具体的使用:
public class MainActivity extends AppCompatActivity implements MyIntentService.UpdateUi {
private static final String TAG = "MainActivity";
private TextView tvText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvText = (TextView) findViewById(R.id.tv_text);
final Intent intent = new Intent(this, MyIntentService.class);
tvText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for (int i = 0; i <5 ; i++) {
Log.e(TAG, "点击事件的线程:" + Thread.currentThread().getName());
intent.putExtra("url", "http://baidu.com");
startService(intent);
}
}
});
tvText.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Log.e(TAG, "onLongClick: 长按事件...");
return false;
}
});
MyIntentService.updateUi(this);
}
@Override
public void update(String url) {
Log.e(TAG, "返回结果的线程:" + Thread.currentThread().getName());
//Log.e(TAG, "update: " + url);
Message msg = Message.obtain();
msg.obj = url;
handler.sendMessage(msg);
}
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String url = (String) msg.obj;
//Log.e(TAG, "处理后的结果: "+url );
Log.e(TAG, "处理后的结果所在线程: "+Thread.currentThread().getName() );
}
};
}
使用方法很简单,首先创建Intent对象
final Intent intent = new Intent(this, MyIntentService.class);
在TextView的点击事件中我们循环了5次,调用startService(intent);
tvText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for (int i = 0; i <5 ; i++) {
Log.e(TAG, "点击事件的线程:" + Thread.currentThread().getName());
intent.putExtra("url", "http://baidu.com");
startService(intent);
}
}
});
执行了5次任务,我们来观察IntentService的生命周期的变化
08-22 15:21:39.008 4735-4735/com.mujin.keji.myapplication E/MyIntentService: onCreate:
onStartCommand:
onStart:
onStartCommand:
onStart:
onStartCommand:
onStart:
onStartCommand:
onStart:
onStartCommand:
onStart:
08-22 15:21:44.014 4735-4735/com.mujin.keji.myapplication E/MyIntentService: onDestroy:
onCreat、onDestroy只调用了一次,onStartCommand和onStart调用了5次,也就是说, startService(intent);一次就执行了一次任务,每次执行的后台任务都在同一个Service中。当全部任务执行完毕才会把Service销毁掉。接着会回调到
IntenetService中最重要的方法onHandleIntent:
@Override
protected void onHandleIntent(@Nullable Intent intent) {
String url = intent.getStringExtra("url");
String result = downLoadPhoto(url);
mUpdateUi.update(result);
}
在onHandleIntent方法中我们拿到intent对象,这个对象也就是在Activity中startService(intent)的那个intent。
在这个方法里我们可以执行相应的后台任务。在这里最重要的区别就是onHandleIntent方法执行的任务是在子线程中执行的。而startService(intent)是在UI线程中执行的。我们把onHandleIntent方法处理后的结果回调到Activity的update方法,我们把线程的名字打印出来:
@Override
public void update(String url) {
Log.e(TAG, "返回结果的线程:" + Thread.currentThread().getName());
//Log.e(TAG, "update: " + url);
Message msg = Message.obtain();
msg.obj = url;
handler.sendMessage(msg);
}
@Override
public void update(String url) {
Log.e(TAG, "返回结果的线程:" + Thread.currentThread().getName());
//Log.e(TAG, "update: " + url);
Message msg = Message.obtain();
msg.obj = url;
handler.sendMessage(msg);
}
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String url = (String) msg.obj;
//Log.e(TAG, "处理后的结果: "+url );
Log.e(TAG, "处理后的结果所在线程: "+Thread.currentThread().getName() );
}
};
08-22 15:29:07.428 4807-4831/com.mujin.keji.myapplication E/MainActivity: 返回结果的线程:IntentService[MyIntentService]
08-22 15:29:07.429 4807-4807/com.mujin.keji.myapplication E/MainActivity: 处理后的结果所在线程: main
08-22 15:29:08.432 4807-4831/com.mujin.keji.myapplication E/MainActivity: 返回结果的线程:IntentService[MyIntentService]
08-22 15:29:08.432 4807-4807/com.mujin.keji.myapplication E/MainActivity: 处理后的结果所在线程: main
08-22 15:29:09.432 4807-4831/com.mujin.keji.myapplication E/MainActivity: 返回结果的线程:IntentService[MyIntentService]
08-22 15:29:09.432 4807-4807/com.mujin.keji.myapplication E/MainActivity: 处理后的结果所在线程: main
08-22 15:29:10.435 4807-4831/com.mujin.keji.myapplication E/MainActivity: 返回结果的线程:IntentService[MyIntentService]
08-22 15:29:10.435 4807-4807/com.mujin.keji.myapplication E/MainActivity: 处理后的结果所在线程: main
08-22 15:29:11.436 4807-4831/com.mujin.keji.myapplication E/MainActivity: 返回结果的线程:IntentService[MyIntentService]
08-22 15:29:11.437 4807-4807/com.mujin.keji.myapplication E/MainActivity: 处理后的结果所在线程: main
我们通过Handler把update的结果发送到主线程,我们打印两个地方的线程名字。你会发现在IntentService中执行的任务是在名字为MyIntentService的线程中执行的。也就是在IntenetService中我们自定义的名字,由此可知在startService的时候,我们开启了一个线程。
public MyIntentService() {
super("MyIntentService");
}
而通过Handler处理的任务是在UI(名字为Main)线程。
综上可知我们就能知道,在我们调用startService(intent)的时候。IntentService会回调onHandleIntent方法,在这个方法中执行的任务是在子线程中执行的。我们可以通过Handler把消息发送到主线程,主线程再做相应的操作。这样一来我们就完成了在子线程中执行后台任务。避免UI线程的堵塞。
3.IntentService的源码分析
我们首先看下IntentService的onCreat方法:
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
在onCreat方法中,我们创建了HandlerThread 对象,并调用start()方法。开启一个子线程。获取Looper对象,然后创建处理消息的ServiceHandler mServiceHandler 对象。所以onCreat方法调用完之后,其实IntentService开启了一个子线程,并为当前线程设置了轮询机制。
接着再看onStart和onStartCommand方法。
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
/**
* You should not override this method for your IntentService. Instead,
* override {@link #onHandleIntent}, which the system calls when the IntentService
* receives a start request.
* @see android.app.Service#onStartCommand
*/
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
我们在上面调用startService(intent)的时候我们知道,调用了5次这两个方法就调用了5次。我们看到onStart方法,每次调用都创建了一条消息,并把intent对象设置到消息里面。然后调用mServiceHandler.sendMessage(msg);方法,发送消息。接着我们继续看mServiceHandler的实现。
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
看到这我们应该一目了然,在handleMessage方法中,调用了onHandleIntent方法
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
并且我们看到onHandleIntent方法是一个空方法,onHandleIntent就是由我们来实现的。
所以很容易得出结论就是:
在我们启动IntenetService的时候调用了startService(intent)方法,IntenetService内部会创建了HandlerThred和Handler机制。HandlerThred用来开启子线程并为当前线程设置Looper,轮询消息。Handler用来处理对应的消息并回调到onHandleIntent方法。我们在开发的时候便可以在onHandleIntent方法执行相应的任务,此时此刻的任务是在子线程中执行的。当任务执行完毕之后会调用onDestroy方法。我们不用手动关闭Service。
网友评论