IntentService 的使用和原理讲解

来源:互联网 发布:免费推广淘宝店铺 编辑:程序博客网 时间:2024/06/16 14:52
Service是一个常用组件,为了简化service,google推出了service的一个子类IntentService,IntentService比着Service,在原先优势的基础了,多出了几个功能。
IntentService 位于主进程中,里面可以直接做耗时操作,不会阻塞UI线程。
IntentService 开启 n 次,会顺序执行功能,一个执行完了才执行第二个,直到结束。
IntentService 所有任务结束后,会自动关闭自己,提高内存使用率,不用自己手写方法关闭service。

IntentService的注册和Service的流程一样,都需要在配置清单中注册。

IntentService的开启方式和Service一样,区别就是IntentService自己里面如何实现数据的操作,和Service稍稍有些不同。写一个实现类继承IntentService,需要实现onHandleIntent(Intent intent)回调方法,在这个里面做一些耗时的操作,之所以不会阻塞UI线程,是因为这个方法是在子线程中,所以可以直接耗时。
开启IntentService时,传入的数据,可以在onHandleIntent(Intent intent)方法里,通过intent获取出来,做相应的操作。

public class IntentServiceDemo extends IntentService {
  public IntentServiceDemo() {
    //必须实现父类的构造方法
    super("IntentServiceDemo");
  }
  @Override
  protected void onHandleIntent(Intent intent) {
    //Intent是从Activity发过来的
    String action = intent.getExtras().getString("key");
    System.out.println("action");
    try {
      Thread.sleep(6000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
@Override
  public void onDestroy() {
    System.out.println("onDestroy");
    super.onDestroy();
  }
}


activity中的点击事件:
Intent startServiceIntent = new Intent("com.duan.intentservice");
    Bundle bundle = new Bundle();
    bundle.putString("key", "cn1");
    startServiceIntent.putExtras(bundle);
    startService(startServiceIntent);
    
    Intent startServiceIntent2 = new Intent("com.duan.intentservice");
    Bundle bundle2 = new Bundle();
    bundle2.putString("key", "cn2");
    startServiceIntent2.putExtras(bundle2);
    startService(startServiceIntent2);

配置清单:
<service android:name=".IntentServiceDemo">
      <intent-filter >
          <action android:name="com.duan.intentservice"/>
      </intent-filter>
</service>


运行后,点击按钮,会发现先打印出了 "cn1" ,6秒后打印了 "cn2" ,又过了6秒,接着就打印了“onDestroy”。
由此可见,验证上述观点。

我们来看看IntentService的源码,只看核心的
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;
    }
    @WorkerThread
    protected abstract void onHandleIntent(Intent intent);
}

我们启动了IntentServiceDemo后,程序先 执行onCreate()方法,重点在里面
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
创建了HandlerThread,并让它运行了起来。HandlerThread是Thread的子类。
mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
创建了个Handler,并且把thread所包含的Looper通过构造方法传递给了Handler。
在使用Handler时,一般都是在UI线程中直接创建,所以默认使用的都是UI线程的Looper。如果直接在子线程中new一个Handler,会报错。官方推荐的解决方法是
  *  class LooperThread extends Thread {
  *      public Handler mHandler;
  *
  *      public void run() {
  *          Looper.prepare();
  *
  *          mHandler = new Handler() {
  *              public void handleMessage(Message msg) {
  *                  // process incoming messages here
  *              }
  *          };
  *
  *          Looper.loop();
  *      }

实际上UI线程中可以使用是因为在程序启动时,UI线程中已经执行过了  Looper.prepare(false); Looper.loop();这两个方法。
言归正传,看看HandlerThread的方法,
public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
@Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
    
发现,上述的looper操作,在run()方法里执行过了,再看看 IntentService的onCreate()方法
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
thread一旦执行,马上执行run()方法,到此就通了,接下来就是 创建了handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
把Looper传递给Hanlder构造方法,子线程中那个创建Handler也是经过方法调用,获取到子线程的looper。到此,
一个可以使用的Handler就创建成功了。但由于是用的子线程的Looper,所以Handler的handleMessage(Message msg)回调,处在子线程中,非UI线程。往下看
@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }
 @Override
    public void onStart(Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }
通过意图intent传递过来的参数,传递给了onStart(Intent intent, int startId)方法,方法的内容好理解,通过message把参数传递给了mServiceHandler回调方法,
 @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
里面有个抽象方法,也就是我们写IntentServiceDemo需要实现的方法。同时onStart(Intent intent, int startId)中的intent通过message传递到了onHandleIntent(Intent intent)中,所以该方法可以接受activity传递的参数。最终,onHandleIntent(Intent intent)里面执行完了耗时操作,会调用stopSelf(msg.arg1);,关闭自己。

很实用的一个类,都是一些基础知识点,但很巧秒组合起来。不得不感慨google工程师,真NB。


0 0
原创粉丝点击