Service是一个常用组件,为了简化service,google推出了service的一个子类IntentService,IntentService比着Service,在原先优势的基础了,多出了几个功能。
IntentService 位于主进程中,里面可以直接做耗时操作,不会阻塞UI线程。
IntentService 开启 n 次,会顺序执行功能,一个执行完了才执行第二个,直到结束。
IntentService 所有任务结束后,会自动关闭自己,提高内存使用率,不用自己手写方法关闭service。
IntentService的注册和Service的流程一样,都需要在配置清单中注册。
IntentService的开启方式和Service一样,区别就是IntentService自己里面如何实现数据的操作,和Service稍稍有些不同。写一个实现类继承IntentService,需要实现onHandleIntent(Intent intent)回调方法,在这个里面做一些耗时的操作,之所以不会阻塞UI线程,是因为这个方法是在子线程中,所以可以直接耗时。
开启IntentService时,传入的数据,可以在onHandleIntent(Intent intent)方法里,通过intent获取出来,做相应的操作。
public class IntentServiceDemo extends IntentService {
public IntentServiceDemo() {
//必须实现父类的构造方法
super("IntentServiceDemo");
}
@Override
protected void onHandleIntent(Intent intent) {
//Intent是从Activity发过来的
String action = intent.getExtras().getString("key");
System.out.println("action");
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void onDestroy() {
System.out.println("onDestroy");
super.onDestroy();
}
}
activity中的点击事件:
Intent startServiceIntent = new Intent("com.duan.intentservice");
Bundle bundle = new Bundle();
bundle.putString("key", "cn1");
startServiceIntent.putExtras(bundle);
startService(startServiceIntent);
Intent startServiceIntent2 = new Intent("com.duan.intentservice");
Bundle bundle2 = new Bundle();
bundle2.putString("key", "cn2");
startServiceIntent2.putExtras(bundle2);
startService(startServiceIntent2);
配置清单:
运行后,点击按钮,会发现先打印出了 "cn1" ,6秒后打印了 "cn2" ,又过了6秒,接着就打印了“onDestroy”。
由此可见,验证上述观点。
我们来看看IntentService的源码,只看核心的
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
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);
}
}
public IntentService(String name) {
super();
mName = name;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@WorkerThread
protected abstract void onHandleIntent(Intent intent);
}
我们启动了IntentServiceDemo后,程序先 执行onCreate()方法,重点在里面
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
创建了HandlerThread,并让它运行了起来。HandlerThread是Thread的子类。
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
创建了个Handler,并且把thread所包含的Looper通过构造方法传递给了Handler。
在使用Handler时,一般都是在UI线程中直接创建,所以默认使用的都是UI线程的Looper。如果直接在子线程中new一个Handler,会报错。官方推荐的解决方法是
* class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
*
* Looper.loop();
* }
实际上UI线程中可以使用是因为在程序启动时,UI线程中已经执行过了 Looper.prepare(false); Looper.loop();这两个方法。
言归正传,看看HandlerThread的方法,
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
发现,上述的looper操作,在run()方法里执行过了,再看看 IntentService的onCreate()方法
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
thread一旦执行,马上执行run()方法,到此就通了,接下来就是 创建了handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
把Looper传递给Hanlder构造方法,子线程中那个创建Handler也是经过方法调用,获取到子线程的looper。到此,
一个可以使用的Handler就创建成功了。但由于是用的子线程的Looper,所以Handler的handleMessage(Message msg)回调,处在子线程中,非UI线程。往下看
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
通过意图intent传递过来的参数,传递给了onStart(Intent intent, int startId)方法,方法的内容好理解,通过message把参数传递给了mServiceHandler回调方法,
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
里面有个抽象方法,也就是我们写IntentServiceDemo需要实现的方法。同时onStart(Intent intent, int startId)中的intent通过message传递到了onHandleIntent(Intent intent)中,所以该方法可以接受activity传递的参数。最终,onHandleIntent(Intent intent)里面执行完了耗时操作,会调用stopSelf(msg.arg1);,关闭自己。
很实用的一个类,都是一些基础知识点,但很巧秒组合起来。不得不感慨google工程师,真NB。