IntentService详解

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。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值