IntentService,用完即走
IntentService
IntentService,可以看做是Service和HandlerThread的結合體,在完成了使命之後會自動停止,適合需要在工作執行緒處理UI無關任務的場景。
- IntentService 是繼承自 Service 並處理非同步請求的一個類,在 IntentService 內有一個工作執行緒來處理耗時操作。
- 當任務執行完後,IntentService 會自動停止,不需要我們去手動結束。
- 如果啟動 IntentService 多次,那麼每一個耗時操作會以工作佇列的方式在 IntentService 的 onHandleIntent 回撥方法中執行,依次去執行,使用序列的方式,執行完自動結束。
例子
下面是一個例子,點選開始啟動一個IntentService去更新進度條,更新完畢IntentService會自動結束。如果多次點選開始,就會執行多遍,多遍執行完之後IntentService才會執行onDestroy方法。
IntentService:
package com.bourne.android_common.ServiceDemo;
import android.app.IntentService;
import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager;
import com.bourne.common_library.utils.Logout;
public class MyIntentService extends IntentService {
/**
* 是否正在執行
*/
private boolean isRunning;
/**
*進度
*/
private int count;
/**
* 廣播
*/
private LocalBroadcastManager mLocalBroadcastManager;
public MyIntentService() {
super("MyIntentService");
Logout.e("MyIntentService");
}
@Override
public void onCreate() {
super.onCreate();
Logout.e("onCreate");
mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
}
@Override
protected void onHandleIntent(Intent intent) {
Logout.e("onHandleIntent");
try {
Thread.sleep(1000);
isRunning = true;
count = 0;
while (isRunning) {
count++;
if (count >= 100) {
isRunning = false;
}
Thread.sleep(50);
sendThreadStatus("執行緒執行中...", count);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 傳送進度訊息
*/
private void sendThreadStatus(String status, int progress) {
Intent intent = new Intent(IntentServiceActivity.ACTION_TYPE_THREAD);
intent.putExtra("status", status);
intent.putExtra("progress", progress);
mLocalBroadcastManager.sendBroadcast(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
Logout.e("執行緒結束執行..." + count);
}
}
- 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
啟動之後會先執行構造方法,然後執行onCreate方法,再到onHandleIntent方法。在onHandleIntent讓進度自增,每次自增睡眠50ms並向Activity傳送廣播並傳遞進度的資料。
IntentServiceActivity:
package com.bourne.android_common.ServiceDemo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.bourne.android_common.R;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class IntentServiceActivity extends AppCompatActivity {
/**
* 狀態文字
*/
@BindView(R.id.tv_status)
TextView tv_status;
/**
* 進度文字
*/
@BindView(R.id.tv_progress)
TextView tv_progress;
/**
* 進度條
*/
@BindView(R.id.progressbar)
ProgressBar progressbar;
private LocalBroadcastManager mLocalBroadcastManager;
private MyBroadcastReceiver mBroadcastReceiver;
public final static String ACTION_TYPE_THREAD = "action.type.thread";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intent_service);
ButterKnife.bind(this);
//註冊廣播
mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
mBroadcastReceiver = new MyBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_TYPE_THREAD);
mLocalBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);
initView();
}
public void initView() {
tv_status.setText("執行緒狀態:未執行");
progressbar.setMax(100);
progressbar.setProgress(0);
tv_progress.setText("0%");
}
@Override
protected void onDestroy() {
super.onDestroy();
//登出廣播
mLocalBroadcastManager.unregisterReceiver(mBroadcastReceiver);
}
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
case ACTION_TYPE_THREAD:
//更改UI
int progress = intent.getIntExtra("progress", 0);
tv_status.setText("執行緒狀態:" + intent.getStringExtra("status"));
progressbar.setProgress(progress);
tv_progress.setText(progress + "%");
if (progress >= 100) {
tv_status.setText("執行緒結束");
}
break;
}
}
}
@OnClick({R.id.btn_start})
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_start:
Intent intent = new Intent(IntentServiceActivity.this, MyIntentService.class);
startService(intent);
break;
}
}
}
- 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
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
點選開始按鈕,會啟動MyIntentService。mLocalBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter)註冊廣播,接收廣播訊息和資料,並時刻更改進度條進度。
註冊MyIntentService
<service
android:name=".ServiceDemo.MyIntentService">
</service>
- 1
- 2
- 3
IntentService原始碼分析
原始碼
package android.app;
import android.annotation.WorkerThread;
import android.annotation.Nullable;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
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);
}
}
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*/
public IntentService(String name) {
super();
mName = name;
}
/**
* Sets intent redelivery preferences. Usually called from the constructor
*/
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@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);
}
@Override
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
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
/**
* Unless you provide binding for your service, you don't need to implement this
*/
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
/**
*/
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
- 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
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
IntentService繼承自Service,內部有一個HandlerThread物件。
在onCreate的時候會建立一個HandlerThread物件,並啟動執行緒。緊接著建立ServiceHandler物件,ServiceHandler繼承自Handler,用來處理訊息。ServiceHandler將獲取HandlerThread的Looper就可以開始正常工作了。
每啟動一次onStart方法,就會把數訊息和資料發給mServiceHandler,相當於傳送了一次Message訊息給HandlerThread的訊息佇列。mServiceHandler會把資料傳個onHandleIntent方法,onHandleIntent是個抽象方法,需要在IntentService實現,所以每次onStart方法之後都會呼叫我們自己寫的onHandleIntent方法去處理。處理完畢使用stopSelf通知HandlerThread已經處理完畢,HandlerThread繼續觀察訊息佇列,如果還有未執行玩的message則繼續執行,否則結束。
啟動 IntentService 為什麼不需要新建執行緒?
IntentService內部的HandlerThread 繼承自 Thread,內部封裝了 Looper,在這裡新建執行緒並啟動,所以啟動 IntentService 不需要新建執行緒。
為什麼不建議通過 bindService() 啟動 IntentService?
@Override
public IBinder onBind(Intent intent) {
return null;
}
- 1
- 2
- 3
- 4
IntentService 原始碼中的 onBind() 預設返回 null;不適合 bindService() 啟動服務,如果你執意要 bindService() 來啟動 IntentService,可能因為你想通過 Binder 或 Messenger 使得 IntentService 和 Activity 可以通訊,這樣那麼 onHandleIntent() 不會被回撥,相當於在你使用 Service 而不是 IntentService。
為什麼多次啟動 IntentService 會順序執行事件,停止服務後,後續的事件得不到執行?
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
IntentService 中使用的 Handler、Looper、MessageQueue 機制把訊息傳送到執行緒中去執行的,所以多次啟動 IntentService 不會重新建立新的服務和新的執行緒,只是把訊息加入訊息佇列中等待執行,而如果服務停止,會清除訊息佇列中的訊息,後續的事件得不到執行。
參考文章
相關文章
- IntentServiceIntent
- IntentService小酌Intent
- 理解 IntentService 原理Intent
- IntentService的使用Intent
- Android IntentServiceAndroidIntent
- IntentService原始碼Intent原始碼
- IntentService簡介Intent
- Android 使用IntentServiceAndroidIntent
- 淺談IntentService原理分析Intent
- Android IntentService 工作原理AndroidIntent
- 從原始碼分析IntentService原始碼Intent
- Android面試相關 - IntentServiceAndroid面試Intent
- IntentService 和 HandlerThread 的原理Intentthread
- IO多路複用完全解析
- 毫不猶豫走來 Oracle即將釋出11g版Oracle
- HandlerThread和IntentService原始碼解析threadIntent原始碼
- Android中IntentService原始碼分析AndroidIntent原始碼
- Android IntentService 的使用和解析AndroidIntent
- Spring event 使用完全指南Spring
- Android ToolBar 使用完全解析Android
- 活兒好又不糾纏的 IntentServiceIntent
- Android多執行緒之IntentServiceAndroid執行緒Intent
- 用IntentService 與ResultReceiver連線web serviceIntentWeb
- Android中IntentService的原理及使用AndroidIntent
- Conflux Truffle 使用完全指南UX
- Vue環境搭建(使用完整框架)Vue框架
- 來晚了,IO多路複用完全解析
- 瞰見|即將上市的雲明星 HashiCorp 走過的開源之路
- Android IntentService完全解析 當Service遇到HandlerAndroidIntent
- MongoDB的mongo命令使用完整版MongoDB
- WindowsXP組策略應用完全手冊(轉)Windows
- 訊息稱網路支付清算平臺“網聯”即將成立 已在走程式
- Android後臺任務(HandlerThread、AsyncTask、IntentService)AndroidthreadIntent
- Android中IntentService的使用及其原始碼解析AndroidIntent原始碼
- 俄羅斯的 IT 危機:儲存快用完了
- ADG刪除應用完畢的日誌
- Linux桌上型電腦即將走紅?什麼催化了市場成熟(轉)Linux
- Android四大元件之Service,以及IntentServiceAndroid元件Intent