android IntentService的深入理解

什麼是IntentService?

IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests through android.content.Context.startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work. 

This "work queue processor" pattern is commonly used to offload tasks from an application's main thread. The IntentService class exists to simplify this pattern and take care of the mechanics. To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate. 

All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop), but only one request will be processed at a time.

意思是說:IntentService是一個通過Context.startService(Intent)啓動可以處理異步請求的Service,使用時你只需要繼承IntentService和重寫其中的onHandleIntent(Intent)方法接收一個Intent對象,當線程執行完畢會停止自己(一般在工作完成的時候). 所有的請求的處理都在一個工作線程中完成,它們會交替執行(但不會阻塞主線程的執行),一次只能執行一個請求.

下面我們看下源代碼是怎麼實現的

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;//這是Looper
    private volatile ServiceHandler mServiceHandler;//這是Handler
    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);//hook鉤子函數
            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.
     *
     */
    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 + "]");//這裏我們創建了一個HandlerThread,意思是創建了一個        //線程
        thread.start();
        mServiceLooper = thread.getLooper();//這裏的Looper對象時從線程中拿到的,這和主線程的Looper是不一樣的
        mServiceHandler = new ServiceHandler(mServiceLooper);//把Looper對象配置到Handler,說明這個Looper循環的是子線程HandlerThread 中的消息,所以mServiceHandler 發送的消息HandlerThread會處理的
    }


    @Override
    public void onStart(Intent intent, int startId) {                                                                                       //這裏是UI主線程,發送消息,等於主線程向子線程發送了一個消息。
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }


    /**
     * You should not override this method for your IntentService. Instead,
     * override {@link #onHandleIntent}, which the system calls when the IntentService
     * receives a start request.
     * @see android.app.Service#onStartCommand
     */
    @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();
    }


    /**
     * Unless you provide binding for your service, you don't need to implement this
     * method, because the default implementation returns null. 
     * @see android.app.Service#onBind
     */
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    /**
     * This method is invoked on the worker thread with a request to process.
     * Only one Intent is processed at a time, but the processing happens on a
     * worker thread that runs independently from other application logic.
     * So, if this code takes a long time, it will hold up other requests to
     * the same IntentService, but it will not hold up anything else.
     * When all requests have been handled, the IntentService stops itself,
     * so you should not call {@link #stopSelf}.
     *
     * @param intent The value passed to {@link
     *               android.content.Context#startService(Intent)}.
     */
    protected abstract void onHandleIntent(Intent intent);
}
HandlerThread是什麼呢

源代碼:

/**
 * Handy class for starting a new thread that has a looper. The looper can then be 
 * used to create handler classes. Note that start() must still be called.
 */
public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
    /**
     * Constructs a HandlerThread.
     * @param name
     * @param priority The priority to run the thread at. The value supplied must be from 
     * {@link android.os.Process} and not from java.lang.Thread.
     */
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    
    /**
     * Call back method that can be explicitly overridden if needed to execute some
     * setup before Looper loops.
     */
    protected void onLooperPrepared() {
    }

    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
    
    /**
     * This method returns the Looper associated with this thread. If this thread not been started
     * or for any reason is isAlive() returns false, this method will return null. If this thread 
     * has been started, this method will block until the looper has been initialized.  
     * @return The looper.
     */
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
    
    /**
     * Ask the currently running looper to quit.  If the thread has not
     * been started or has finished (that is if {@link #getLooper} returns
     * null), then false is returned.  Otherwise the looper is asked to
     * quit and true is returned.
     */
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
    
    /**
     * Returns the identifier of this thread. See Process.myTid().
     */
    public int getThreadId() {
        return mTid;
    }
}

HandlerThread就是一個線程,而且是一個LooperThread,這個Looper我們可以創建Handler對象,Thread的start()方法必須被執行。

有了looper就可以消息查詢了。
針對IntentService的用法我們舉例說明:

MainAcitivity中

</pre><pre name="code" class="java">@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		Log.d("intent", "MainActivity.onCreate");
		count++;
		startService(count);
		LinearLayout layoutg = (LinearLayout) findViewById(R.id.rootview);
		layoutg.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				count++;
				startService(count);
			}
		});
	}
	
	public void startService(int flag){
		Intent service = new Intent(MainActivity.this,MyIntentService.class);
		service.putExtra("flag", flag);
		startService(service);
	}

MyIntenteService代碼

public class MyIntentService extends IntentService {

	
	
	public MyIntentService() {
		super("myIntentService");
		Log.d("intent", "MyIntentService----name:myIntentService");
	}


	@Override
	public void onCreate() {
		Log.d("intent", "MyIntentService----onCreate");
		super.onCreate();
	}


	@Override
	protected void onHandleIntent(Intent intent) {
		// TODO Auto-generated method stub
		Log.d("intent", "MyIntentService----flag:"+intent.getIntExtra("flag", 0));
		try {
			Log.d("intent", "MyIntentService----task running");
			int count = 0;
			while(count<5){
				count++;
				Log.d("intent", "MyIntentService----"+count);
				TimeUnit.SECONDS.sleep(1);
			}
			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}


	@Override
	public void onDestroy() {
		Log.d("intent", "MyIntentService----onDestroy");
		super.onDestroy();
	}
	
	
}

main_layout.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent" 
    android:layout_height="match_parent"
    tools:context="com.example.heraracky.MainActivity"
    tools:ignore="MergeRootFrame" >
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/rootview"
        android:orientation="vertical"
        android:background="@android:color/darker_gray">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_launcher"/>
        <TextView
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:text="textView"/>
    </LinearLayout>
</FrameLayout>


這時候我們點擊下linearlayout的觸發事件,flag爲2,在task running執行的時候,在點擊一次linearlayout的觸發事件,看運行結果


小結:

flag爲1時,HandlerThread執行完畢後,intentService就自己onDestroy了;flag爲2時,當HandlerThread還未執行完畢時,有發送一次intent,這時flag爲3,但是並沒有立即執行,而是等到flag爲2的線程執行完成後,才繼續執行flag爲3的請求,執行完成後才調用service的onDestroy方法。

這樣就不用我們自己來控制Service的生命週期了。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章