IntentService详解

xiaoxiao2021-02-27  138

Running in a Background Service

Service相信都很熟悉,Android四大组件之一,后台运行。但这里的后台运行并不是指Service在子线程中运行,而是指Service的运行是不依赖于UI的。Service是在主线程中运行的。


没关系,Google还提供了另外一个IntentService实现后台子线程运行。关于IntentService有几点需要注意的:

IntentService不能直接跟UI进行交互,必须将结果发送到UI中;请求是按顺序执行的,重复发送请求需要等待之前的执行完毕;IntentService中的操作不能被打断。

虽然IntentService局限较多,然而,在大多数情况下,IntentService是执行简单后台操作的首选方法。比如更新Apk,比如一些网络请求等等


创建一个IntentService

public class MyService extends IntentService{ public MyService() { super("MyService"); } @Override protected void onHandleIntent(@Nullable Intent intent) { String dataString = intent.getDataString(); Log.e(TAG,"dataString :" + dataString); //todo耗时操作 }

这里跟Service的创建还是有区别的,IntentService自动处理了onStartCommand() 之类的回调方法,在IntentService中要避免实现Service中的回调方法。 在AndroidMainfest.xml中注册Service

<service android:name=".service.MyService" android:exported="false"/>

开启一个IntentService

public void clickMy(View view){ Intent mServiceIntent = new Intent(this,MyService.class); mServiceIntent.setData(Uri.parse(dataUrl)); startService(mServiceIntent); }

通过创建一个Intent,实现发送IntentService,同时可以携带各类参数。


IntentService同UI交互

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。

转载请注明原文地址: https://www.6miu.com/read-15973.html

最新回复(0)