IntentService

Android中的Service是用于后台服务的,当应用程序被挂到后台的时候,为了保证应用某些组件仍然可以工作而引入了Service这个概念,那么这里面要强调的是Service不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,也就是说,在更多时候不建议在Service中编写耗时的逻辑和操作,否则会引起ANR。

 

那么我们当我们编写的耗时逻辑,不得不被service来管理的时候,就需要引入IntentService,IntentService是继承Service的,那么它包含了Service的全部特性,当然也包含service的生命周期,那么与service不同的是,IntentService在执行onCreate操作的时候,内部开了一个线程,去执行你的耗时操作。


Service中提供了一个方法:

public int onStartCommand(Intent intent, int flags, int startId) {  
         onStart(intent, startId);  
         return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;  
     }



这个方法的具体含义是,当你的需要这个service启动的时候,或者调用这个servcie的时候,那么这个方法首先是要被回调的。

同时IntentService中提供了这么一个方法:

protected abstract void onHandleIntent(Intent intent);



这是一个抽象方法,也就是说具体的实现需要被延伸到子类。

子类的声明:

public class ChargeService extends IntentService

上面提到过IntentService是继承Service的,那么这个子类也肯定继承service,那么onHandleIntent()方法是什么时候被调用的呢?让我们具体看IntentService的内部实现:

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);  
        }  
    }  
      
    /** 
     * Creates an IntentService.  Invoked by your subclass's constructor. 
     * 
     * @param name Used to name the worker thread, important only for debugging. 
     */  
    public IntentService(String name) {  
        super();  
        mName = name;  
    }  
      
    /** 
     * Sets intent redelivery preferences.  Usually called from the constructor 
     * with your preferred semantics. 
     * 
     * <p>If enabled is true, 
     * {@link #onStartCommand(Intent, int, int)} will return 
     * {@link Service#START_REDELIVER_INTENT}, so if this process dies before 
     * {@link #onHandleIntent(Intent)} returns, the process will be restarted 
     * and the intent redelivered.  If multiple Intents have been sent, only 
     * the most recent one is guaranteed to be redelivered. 
     * 
     * <p>If enabled is false (the default), 
     * {@link #onStartCommand(Intent, int, int)} will return 
     * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent 
     * dies along with it. 
     */  
    public void setIntentRedelivery(boolean enabled) {  
        mRedelivery = enabled;  
    }  
      
    @Override  
    public void onCreate() {  
        // TODO: It would be nice to have an option to hold a partial wakelock  
        // during processing, and to have a static startService(Context, Intent)  
        // method that would launch the service & hand off a wakelock.  
      
        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);  
    }



在这里我们可以清楚的看到其实IntentService在执行onCreate的方法的时候,其实开了一个线程HandlerThread,并获得了当前线程队列管理的looper,并且在onStart的时候,把消息置入了消息队列,

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



在消息被handler接受并且回调的时候,执行了onHandlerIntent方法,该方法的实现是子类去做的。

 

结论:

IntentService是通过Handler looper message的方式实现了一个多线程的操作,同时耗时操作也可以被这个线程管理和执行,同时不会产生ANR的情况。

例子:两个按钮,一个启动普通Service,一个启动IntentService。



TestActivity.java


public class TestActivity extends Activity {
	private Button  serviceBtn;
	private Button  intentServiceBtn;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        serviceBtn = (Button)findViewById(R.id.button1);
        intentServiceBtn = (Button)findViewById(R.id.button2);
        serviceBtn.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				Intent intent = new Intent(TestActivity.this,MyService.class);
				startService(intent);
			}
		});
        intentServiceBtn.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				Intent intent = new Intent(TestActivity.this,MyIntentService.class);
				startService(intent);
			}
		});
    }
}

MyService.java


public class MyService extends Service {

	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// TODO Auto-generated method stub
		//执行耗时任务,可能造成anr
				long endTime = System.currentTimeMillis()+20*1000;
				while(System.currentTimeMillis()<endTime){
					synchronized(this){
						try{
							wait(endTime - System.currentTimeMillis());
						}catch(Exception e){
							
						}
					}
				}
		return super.onStartCommand(intent, flags, startId);
	}
}



MyIntentService.java


public class MyIntentService extends IntentService{

	public MyIntentService() {
		super("MyIntentService");
		// TODO Auto-generated constructor stub
	}

	@Override
	protected void onHandleIntent(Intent intent) {
		// TODO Auto-generated method stub
		long endTime = System.currentTimeMillis()+20*1000;
		while(System.currentTimeMillis() <endTime){
			synchronized(this){
				try{
					wait(endTime - System.currentTimeMillis());
				}catch(Exception e){
					
				}
			}
		}
		System.out.print("耗时任务完成");
	}

}



AndroidManifest.xml 中注册service组件


<service android:name=".MyService">
            
</service>
<service android:name=".MyIntentService">
            
</service>



结论:普通service会报ANR错误,IntentService执行耗时任务不会阻塞主线程。