Running in a Background Service
Service相信都很熟悉,Android四大组件之一,后台运行。但这里的后台运行并不是指Service在子线程中运行,而是指Service的运行是不依赖于UI的。Service是在主线程中运行的。
没关系,Google还提供了另外一个IntentService实现后台子线程运行。关于IntentService有几点需要注意的:
IntentService不能直接跟UI进行交互,必须将结果发送到UI中;请求是按顺序执行的,重复发送请求需要等待之前的执行完毕;IntentService中的操作不能被打断。虽然IntentService局限较多,然而,在大多数情况下,IntentService是执行简单后台操作的首选方法。比如更新Apk,比如一些网络请求等等
这里跟Service的创建还是有区别的,IntentService自动处理了onStartCommand() 之类的回调方法,在IntentService中要避免实现Service中的回调方法。 在AndroidMainfest.xml中注册Service
<service android:name=".service.MyService" android:exported="false"/>通过创建一个Intent,实现发送IntentService,同时可以携带各类参数。
IntentService在处理完耗时操作以后,如何跟Fragment或者Activity进行交互呢? 通过发送本地广播,IntentService可以将结果发送出去,在想要处理结果的Fragment或者Activity中注册本地广播,就可以实现IntentService和UI的交互。下面代码贴出完整的IntentService类,以及Activity中监听IntentService返回结果的处理。
IntentService
public class MyService extends IntentService{ private static final String TAG = "MyService"; private BroadcastNotifier mBroadcaster = new BroadcastNotifier(this); public MyService() { super("MyService"); } @Override protected void onHandleIntent(@Nullable Intent intent) { String dataString = intent.getDataString(); Log.e(TAG,"dataString :" + dataString); mBroadcaster.broadcastIntentWithState(Constants.STATE_ACTION_STARTED); //模拟耗时操作,更多时候是网络请求 try { mBroadcaster.broadcastIntentWithState(Constants.STATE_ACTION_DOING); Thread.sleep(5 * Integer.valueOf(dataString)); mBroadcaster.broadcastIntentWithState(Constants.STATE_ACTION_FINSHIED); } catch (InterruptedException e) { e.printStackTrace(); } } }这里通过BroadcastNotifier管理不同状态广播的发送
public class BroadcastNotifier { private LocalBroadcastManager mBroadcaster; public BroadcastNotifier(Context context){ mBroadcaster = LocalBroadcastManager.getInstance(context); } public void broadcastIntentWithState(int status){ // The Intent contains the custom broadcast action for this app Intent localIntent = new Intent(); localIntent.setAction(Constants.BROADCAST_ACTION); //将statue放入intent中 localIntent.putExtra(Constants.EXTENDED_DATA_STATUS,status); localIntent.addCategory(Intent.CATEGORY_DEFAULT); //发送广播 mBroadcaster.sendBroadcast(localIntent); } }通过LocalBroadcastManager发送一个本地广播,本地广播也就是只有当前应用能够监听的广播事件。
接下来看Activity中处理广播事件
public class MainActivity extends AppCompatActivity { private String dataUrl = "1000"; private static final String TAG = "MainActivity"; private DownloadStateReceiver mDownloadStateReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); IntentFilter statusIntentFilter = new IntentFilter( Constants.BROADCAST_ACTION); statusIntentFilter.addCategory(Intent.CATEGORY_DEFAULT); mDownloadStateReceiver = new DownloadStateReceiver(); LocalBroadcastManager.getInstance(this).registerReceiver(mDownloadStateReceiver,statusIntentFilter); } public void clickMy(View view){ Intent mServiceIntent = new Intent(this,MyService.class); mServiceIntent.setData(Uri.parse(dataUrl)); startService(mServiceIntent); } @Override protected void onDestroy() { if(mDownloadStateReceiver != null) LocalBroadcastManager.getInstance(this).unregisterReceiver(mDownloadStateReceiver); super.onDestroy(); } private class DownloadStateReceiver extends BroadcastReceiver{ public DownloadStateReceiver() { } @Override public void onReceive(Context context, Intent intent) { switch (intent.getIntExtra(Constants.EXTENDED_DATA_STATUS,Constants.STATE_ACTION_STARTED)){ case Constants.STATE_ACTION_STARTED: Log.e(TAG,"开始执行耗时任务"); break; case Constants.STATE_ACTION_DOING: Log.e(TAG,"正在执行耗时任务"); break; case Constants.STATE_ACTION_FINSHIED: Log.e(TAG,"完成耗时任务"); break; } } } }很简单,通过注册对应Action的广播,就可以监听IntentService中不同状态下发出的广播信息,在监听到状态后,进行了简单的日志打印.
08-30 14:35:50.148 26467-26467/? E/MainActivity: 开始执行耗时任务 08-30 14:35:50.148 26467-26467/? E/MainActivity: 正在执行耗时任务 08-30 14:35:55.149 26467-26467/? E/MainActivity: 完成耗时任务其中Constants用来存储一些广播的Action名称以及一些不同的Statue
public class Constants { public static final String BROADCAST_ACTION = "com.intentservice.service.BROADCAST"; public static final String EXTENDED_DATA_STATUS = "com.intentservice.service.STATUS"; public static final int STATE_ACTION_STARTED = 0; public static final int STATE_ACTION_DOING = 1; public static final int STATE_ACTION_FINSHIED = 2; }至此,IntentService相信已经掌握的差不多了。
记得之前参加过一个面试,面试官有问道是否了解IntentService,之前从来没有接触过这个类,因此无奈的回答了不了解。然后面试官又问我,那你们更新apk之类的后台服务是如何实现的,我的回答是通过在Service中开启子线程来实现异步方法处理,然后通过handler实现结果回调。
有毛病吗?没毛病。有毛病吗?当然有毛病啊。既然Google提供了IntentService,为何我还要多此一举呢。IntentService不仅实现了Service在子线程中执行,也完全跟UI脱离了关系,你可以再任何页面通过监听广播实现IntentService结果的监听。而且,你真的能保证自己实现的Service异步操作能比得过Google吗?
因此,强烈建议大家理解并真正使用IntentService。