前言
Service服务是Android四大组件之一,在Android中有着举足重轻的作用。Service服务是工作的UI线程中,当你的应用需要下载一个文件或者播放音乐等长期处于后台工作而有没有UI界面的时候,你肯定要用到Service+Thread来实现。因此你需要自己在Service服务里面实现一个Thread工作线程来下载文件或者播放音乐。然而你每次都需要自己去写一个Service+Thread来处理长期处于后台而没有UI界面的任务,这样显得很麻烦,没必要每次都去构建一个Service+Thread框架处理长期处于后台的任务。Google工程师给我们构建了一个方便开发者使用的这么一个框架---IntentService(Service+Handler(Handler为HandlerThread的looper创建))
范例
IntentService本质也是Service,需要在AndroidManifest里面声明,并且创造一个无参的默认构造函数
//一个构造函数是必须的,并且你必须调用父类的IntentService(String)以传入工作线程的名字
public class TestIntentService extends IntentService {
public TestIntentService(){
super("TestIntentService");
}
public TestIntentService(String name) {
super(name);
}
@Override
public void onDestroy() {
Log.e("weijuncheng","onDestory called");
super.onDestroy();
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.e("weijuncheng","onStartCommand called, intent = "+intent);
return super.onStartCommand(intent, flags, startId);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
int key = intent.getIntExtra("key",0);
String task = intent.getStringExtra("value");
switch (key){
case 1:
//模拟耗时任务1
try {
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
case 2:
//模拟耗时任务2
try {
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
Log.e("weijuncheng", "\nthe current time is: " + System.currentTimeMillis()/1000
+ "\nthe Thread id is " + Thread.currentThread().getId()
+ "\nthe current task is " + task);
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent1 = new Intent(this,TestIntentService.class);
intent1.putExtra("key",1);
intent1.putExtra("value","task 1");
startService(intent1);
Intent intent2 = new Intent(this,TestIntentService.class);
intent2.putExtra("key",2);
intent2.putExtra("value","task 2");
startService(intent2);
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test.weijuncheng.testintentservice">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".TestIntentService">
</service>
</application>
</manifest>
如果没有声明Service会出现
Unable to start service Intent { cmp=com.test.weijuncheng.testintentservice/.TestIntentService (has extras) } U=0: not found;因为一开始Service是从AndroidManifest里面查找
相应log为
01-01 02:19:15.023 998 998 E weijuncheng: onStartCommand called, intent = Intent { cmp=com.test.weijuncheng.testintentservice/.TestIntentService (has extras) }
01-01 02:19:15.026 998 998 E weijuncheng: onStartCommand called, intent = Intent { cmp=com.test.weijuncheng.testintentservice/.TestIntentService (has extras) }
01-01 02:19:15.206 1268 1290 I ActivityManager: Displayed com.test.weijuncheng.testintentservice/.MainActivity: +533ms
01-01 02:19:18.024 998 1034 E weijuncheng:
01-01 02:19:18.024 998 1034 E weijuncheng: the current time is: 1230776358
01-01 02:19:18.024 998 1034 E weijuncheng: the Thread id is 690
01-01 02:19:18.024 998 1034 E weijuncheng: the current task is task 1
01-01 02:19:21.027 998 1034 E weijuncheng:
01-01 02:19:21.027 998 1034 E weijuncheng: the current time is: 1230776361
01-01 02:19:21.027 998 1034 E weijuncheng: the Thread id is 690
01-01 02:19:21.027 998 1034 E weijuncheng: the current task is task 2
01-01 02:19:21.030 998 998 E weijuncheng: onDestory called
IntentService源码
63public abstract class IntentService extends Service {
64 private volatile Looper mServiceLooper;
65 private volatile ServiceHandler mServiceHandler;
66 private String mName;
67 private boolean mRedelivery;
68
69 private final class ServiceHandler extends Handler {
70 public ServiceHandler(Looper looper) {
71 super(looper);
72 }
73
74 @Override
75 public void handleMessage(Message msg) {
76 onHandleIntent((Intent)msg.obj);
77 stopSelf(msg.arg1);
78 }
79 }
80
81 /**
82 * Creates an IntentService. Invoked by your subclass's constructor.
83 *
84 * @param name Used to name the worker thread, important only for debugging.
85 */
86 public IntentService(String name) {
87 super();
88 mName = name;
89 }
90
91 /**
92 * Sets intent redelivery preferences. Usually called from the constructor
93 * with your preferred semantics.
94 *
95 * <p>If enabled is true,
96 * {@link #onStartCommand(Intent, int, int)} will return
97 * {@link Service#START_REDELIVER_INTENT}, so if this process dies before
98 * {@link #onHandleIntent(Intent)} returns, the process will be restarted
99 * and the intent redelivered. If multiple Intents have been sent, only
100 * the most recent one is guaranteed to be redelivered.
101 *
102 * <p>If enabled is false (the default),
103 * {@link #onStartCommand(Intent, int, int)} will return
104 * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
105 * dies along with it.
106 */
107 public void setIntentRedelivery(boolean enabled) {
108 mRedelivery = enabled;
109 }
110
111 @Override
112 public void onCreate() {
113 // TODO: It would be nice to have an option to hold a partial wakelock
114 // during processing, and to have a static startService(Context, Intent)
115 // method that would launch the service & hand off a wakelock.
116
117 super.onCreate();
118 HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
119 thread.start();
120
121 mServiceLooper = thread.getLooper();
122 mServiceHandler = new ServiceHandler(mServiceLooper);
123 }
124
125 @Override
126 public void onStart(@Nullable Intent intent, int startId) {
127 Message msg = mServiceHandler.obtainMessage();
128 msg.arg1 = startId;
129 msg.obj = intent;
130 mServiceHandler.sendMessage(msg);
131 }
132
133 /**
134 * You should not override this method for your IntentService. Instead,
135 * override {@link #onHandleIntent}, which the system calls when the IntentService
136 * receives a start request.
137 * @see android.app.Service#onStartCommand
138 */
139 @Override
140 public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
141 onStart(intent, startId);
142 return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
143 }
144
145 @Override
146 public void onDestroy() {
147 mServiceLooper.quit();
148 }
149
150 /**
151 * Unless you provide binding for your service, you don't need to implement this
152 * method, because the default implementation returns null.
153 * @see android.app.Service#onBind
154 */
155 @Override
156 @Nullable
157 public IBinder onBind(Intent intent) {
158 return null;
159 }
160
161 /**
162 * This method is invoked on the worker thread with a request to process.
163 * Only one Intent is processed at a time, but the processing happens on a
164 * worker thread that runs independently from other application logic.
165 * So, if this code takes a long time, it will hold up other requests to
166 * the same IntentService, but it will not hold up anything else.
167 * When all requests have been handled, the IntentService stops itself,
168 * so you should not call {@link #stopSelf}.
169 *
170 * @param intent The value passed to {@link
171 * android.content.Context#startService(Intent)}.
172 * This may be null if the service is being restarted after
173 * its process has gone away; see
174 * {@link android.app.Service#onStartCommand}
175 * for details.
176 */
177 @WorkerThread
178 protected abstract void onHandleIntent(@Nullable Intent intent);
179}
IntentService源码分析
首先观察IntentService的onCreate
111 @Override
112 public void onCreate() {
113 // TODO: It would be nice to have an option to hold a partial wakelock
114 // during processing, and to have a static startService(Context, Intent)
115 // method that would launch the service & hand off a wakelock.
116
117 super.onCreate();
118 HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
119 thread.start();
120
121 mServiceLooper = thread.getLooper();
122 mServiceHandler = new ServiceHandler(mServiceLooper); //根据HandlerThread中的looper创建一个Handler
123 }
其中用到了HandlerThread
22/**
23 * Handy class for starting a new thread that has a looper. The looper can then be
24 * used to create handler classes. Note that start() must still be called.
25 */
26public class HandlerThread extends Thread {
参考 Android HandlerThread 总结使用
HandlerThread本质上就是一个普通Thread,只不过内部建立了Looper,普通线程默认是不建立looper的
HandlerThread的关键点
55 @Override
56 public void run() {
57 mTid = Process.myTid();
58 Looper.prepare(); //准备循环条件
59 synchronized (this) { //持有锁机制来获得当前线程的Looper对象
60 mLooper = Looper.myLooper(); //发出通知,当前线程已经创建mLooper对象成功,这里主要是通知getLooper方法中的wait
61 notifyAll();
62 }
63 Process.setThreadPriority(mPriority);
64 onLooperPrepared(); //该方法实现体是空的,子类可以实现该方法,作用就是在线程循环之前做一些准备工作,当然子类也可以不实现。
65 Looper.loop(); //启动loop
66 mTid = -1;
67 }
69 /**
70 * This method returns the Looper associated with this thread. If this thread not been started
71 * or for any reason isAlive() returns false, this method will return null. If this thread
72 * has been started, this method will block until the looper has been initialized.
73 * @return The looper.
74 */
75 public Looper getLooper() {
76 if (!isAlive()) { //如果线程不是存活的,则直接返回null
77 return null;
78 }
79
80 // If the thread has been started, wait until the looper has been created.
81 synchronized (this) {
82 while (isAlive() && mLooper == null) {
83 try {
84 wait(); //如果线程已经启动,但是Looper还未创建的话,就等待,直到Looper创建成功
85 } catch (InterruptedException e) {
86 }
87 }
88 }
89 return mLooper;
90 }
ServiceHandler是IntentService的内部类,在重写消息处理方法handlerMessage里面调用了onHandlerIntent抽象方法去处理异步任务intent的请求,当异步任务请求结束之后,调用stopSelf方法自动结束IntentService服务
69 private final class ServiceHandler extends Handler {
70 public ServiceHandler(Looper looper) {
71 super(looper);
72 }
73
74 @Override
75 public void handleMessage(Message msg) {
76 onHandleIntent((Intent)msg.obj);
77 stopSelf(msg.arg1);
78 }
79 }
一直知道stopself是停掉Service的方法,但是却不知道什么时候停止。以为调用了stopself就会马上停止,实际上我错了。
在onStartCommond方法里面调用stopself方法时,不会马上停止,而是onStartCommond方法执行结束才会停止。
还有一点,调用stopself方法之后,service会执行onDestory方法。
另外,如果onStartCommond中启动一个线程,调用stopself,线程也不会被杀死
145 @Override
146 public void onDestroy() {
147 mServiceLooper.quit();
148 }
looper quit,让当前工作线程HandlerThread退出当前Looper循环,进而结束线程。进而结束当前IntentService服务