Service的异步版本IntentService:

IntentService是Service的子类,因此它不是普通的Service,由于Service本身存在的两个问题:
1.Service不会专门启动一条单独的进程,因此它与应用是处在同一进程中的
2.Service也不是专门一条新的线程,因此不应该在Service中直接处理耗时任务,不然会出现ANR异常

IntentService的特性

因此IntentService它比普通的Service增加了额外的功能:
1.它会创建单独的worker线程来处理所有的Intent请求
2.会创建单独的worker线程来处理onHandleIntent方法实现的代码,因此开发者无需处理多线程问题
3.当所有的请求处理完成之后,IntentService会自动停止,因此开发者无需调用stopSelf()方法来停止Service
4.onBind方法提供了默认的实现,默认返回null,同样onStartCommand方法也是提供了默认的实现,实现会将Intent添加到队列中
创建一个IntentService的方法和Service的一样,因此不再赘述,我们在继承IntentService的时候只需要实现onHandleIntent方法即可
对于上面的一些特性我们需要通过源代码来看一下是为什么会有这样的特性:

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);
        }
    }
    public IntentService(String name) {
        super();
        mName = name;
    }
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
    @Override
    public void onStart(Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    protected abstract void onHandleIntent(Intent intent);

重点从onCreate看起,我们知道Service的启动的时候首先会调用onCreate函数,因此我们发现了new HandlerThread 因此我们大概就知道了实现方式就是通过HandlerThread来处理多个Intent的请求,由于只有一个HandlerThread对象,因此我们可以知道IntentService只是创建了一条线程来处理所有的请求,

HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);

由上面的code我们得到ServiceHandler处理消息的时候是用子线程来处理的(looper
决定了程序运行在什么线程中,如果是主线程中我们应该使用getMainLooper()),
因此这里我们获取了一个looper,这个是每个线程MessageQueue中的管家,thread.start()函数调用之后code内部会调用Looper的loop()方法,进入了一个无线循环中,当队列中的消息轮到的时候我们会调用mServiceHandler 去处理这个消息因此这里就实现了我们一个线程处理多个intent请求的功能,结合了Looper MessageQueue Handler 。
在Service的时候我们onCreate启动之后会去调用onStartCommand,因此这里我们接下来看这个函数,里面调用了onStart(Intent intent, int startId),intent是我们的请求Intent,而startId是 A unique integer representing this specific request to start.
我们可以在Service中调用多次startService然后得到如下图:
这里写图片描述
因此这里是表示请求的序号,是一个自增长的数字
在onStart中我们发送了startId和intent给我们的mServiceHandler处理,
然后查看处理消息我们可以看到:

 @Override
   public void handleMessage(Message msg) {
       **onHandleIntent((Intent)msg.obj);**
       stopSelf(msg.arg1);
   }

我们重写的onHandleIntent里面会去操作实际的耗时动作,最后调用stopSelf(int)去结束指定的第几个Intent请求,当startId < 0 或者startId == 最后一次请求的startId,说明队列任务完成,则service自动关闭(这一句自己没有验证过),因此不用我们自己调用stopSelf()函数关闭
简单的分析完了IntentService的特性,下面我们简单的通过一个例子看一下IntentService的使用方法:
参考鸿洋的例子,只是他用的广播方式,我用的是消息方式,实现模拟图片的下载,大家可以作为参考:

MyIntentService的实现:

public class MyIntentService extends IntentService {
    private Messenger messenger ;
    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        messenger = (Messenger) intent.getExtras().get("Messenger");
        int count = intent.getIntExtra("count",0);
        downLoadImage(count);
    }

    private void downLoadImage(int count){
        try {
            Thread.sleep(3000);
            Message msg = Message.obtain();
            msg.what= 1;
            msg.arg1=count;
            msg.arg2=(int) Thread.currentThread().getId();
            messenger.send(msg);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Override
    public void onDestroy() {
        System.out.println("onDestory()");
        super.onDestroy();
    }
}

MainActivity函数的实现:

public class MainActivity extends Activity {

    private static int count=1;
    private LinearLayout layout ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        layout=(LinearLayout) findViewById(R.id.layout);
    }
    //点击一个task添加一个任务,模拟图片下载
    public void addTask(View v)
    {
        createTextView(count);
        Intent intent = new Intent(this,MyIntentService.class);
        intent.putExtra("count", count);
        intent.putExtra("Messenger", new Messenger(myHandler));
        startService(intent);
        count++;
    }
    //创建一个textView控件,模拟图片任务的添加
    public void createTextView(int count){
        TextView textView = new TextView(this);
        textView.setText("第"+count+"张图片正在下载中....");
        textView.setTag(count);
        textView.setTextSize(20f);
        layout.addView(textView);
    }

    private Handler myHandler = new Handler(){
        public void handleMessage(Message msg) {
            if(msg.what==1){
                int pass_count = msg.arg1;
                TextView v = (TextView) layout.findViewWithTag(pass_count);
                v.setText("线程"+msg.arg2+"成功下载第"+pass_count+"张图片!");
            }
        };
    };
}

实现的效果:
这里写图片描述
这里写图片描述
注意的是113 114两个线程出现了,是因为113我们三个线程执行完了之后调用了,结束了Service,然后我们再次点击addTask开启的是新的线程
就先到这了,不对请拍砖!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值