Android IntentService 异步 Service
程序员文章站
2022-08-13 21:04:47
当我们执行文件上传,文件下载等耗时任务时,为了保证 App 退回到后台而降低被系统干掉的概率,使得该任务仍然能继续执行,我们通常会将这些任务放在后台 Service 中去处理,但是...
当我们执行文件上传,文件下载等耗时任务时,为了保证 App 退回到后台而降低被系统干掉的概率,使得该任务仍然能继续执行,我们通常会将这些任务放在后台 Service 中去处理,但是,Service 是运行在主线程中(不能执行耗时操作),因此必须在 Service 中创建子线程来执行。Android SDK 提供了 IntentService 来简化了这个过程。
IntentService 特点:
IntentService 是继承自 Service 的抽象类,内部使用 HandlerThread + Handler 建立了异步线程来处理 后台 Service 耗时操作。 当耗时任务执行完后,IntentService 会自动停止,不需要手动去停止。 启动多次 IntentService ,每个耗时任务会在 onHandleIntent 中以队列形式依次执行。IntentService 常规使用套路
继承自 IntentService 类,重写构造函数和 onHandleIntent() 方法。 在 onHandleIntent() 方法中处理耗时任务,运行于子线程中。 通过 startService() 方式启动 IntentService, 不能通过 bindService() 方式启动,因为 IntentService 中的 onBind() 方法返回 null。以下代码,模拟每次点击按钮添加一个耗时任务到队列中,直到所有的任务执行完后,才自动停止 service。
/** * UploadLogService.java */ public class UploadLogService extends IntentService { public static final String ACTION_UPDATE_UI = "action_update_ui"; private static final String TAG = "UploadLogService"; public UploadLogService() { super("upload-log-service"); } @Override public void onCreate() { super.onCreate(); Log.d(TAG, "onCreate: "); } @Override public void onStart(@Nullable Intent intent, int startId) { super.onStart(intent, startId); Log.d(TAG, "onStart: "); } @Override public int onStartCommand(@Nullable Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand: "); return super.onStartCommand(intent, flags, startId); } @Nullable @Override public IBinder onBind(Intent intent) { Log.d(TAG, "onBind: "); return super.onBind(intent); } @Override public boolean onUnbind(Intent intent) { Log.d(TAG, "onUnbind: "); return super.onUnbind(intent); } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy: "); } /** * 运行于子线程中 * * @param intent */ @Override protected void onHandleIntent(@Nullable Intent intent) { if (intent != null) { String text = intent.getStringExtra("text"); Log.d(TAG, "onHandleIntent: " + text); SystemClock.sleep(3000); // 模拟耗时任务 // 任务执行完成,广播通知更新 ui Intent updateUiIntent = new Intent(); updateUiIntent.setAction(ACTION_UPDATE_UI); updateUiIntent.putExtra("text", text); LocalBroadcastManager.getInstance(this).sendBroadcast(updateUiIntent); } } }
/** * IntentServiceActivity.java **/ public class IntentServiceActivity extends AppCompatActivity { private int index; private LinearLayout linearLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_intent_service); linearLayout = findViewById(R.id.ll_layout); // 注册广播 registerBroadcastReceiver(); } // 注册本地广播 private void registerBroadcastReceiver() { IntentFilter filter = new IntentFilter(UploadLogService.ACTION_UPDATE_UI); LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter); } // 更新 UI 的本地广播 private BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String text = intent.getStringExtra("text"); TextView textView = linearLayout.findViewWithTag(text); textView.setText(text + ">>>>>>>> success"); } }; public void click(View view) { index++; String text = "uploading log = " + index; addTextView(text); // 开启异步任务service startService(text); } private void addTextView(String text) { TextView textView = new TextView(this); textView.setText(text); textView.setTag(text); linearLayout.addView(textView); } private void startService(String text) { Intent intent = new Intent(this, UploadLogService.class); intent.putExtra("text", text); startService(intent); } @Override protected void onDestroy() { super.onDestroy(); LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver); } }
由此得出结果:
(1)多次启动 IntentService ,onCreate() 只会执行一次,而 onStart() / onStartCommond() 会执行多次,异步任务会顺序执行,直到所有的任务执行完成才会执行 onDestroy() 停止 Service。
(2)onBind() / onUnbind() 没有执行,因为启动 IntentService 是通过 startService() 方式启动的,但是我们不能通过 bindService() 方式启动 IntentService,因为 IntentService 源码中的 onBind() 方法返回 null。
(3)停止服务后,后续的事件将不会执行,因为 IntentService 中的 onDestroy() 中调用了 looper 的 quit() 方法退出轮询。