Android Service 複習總結 下

上一篇總結了Service常用的一些方法,不過還有一個用法就是AIDL。那什麼是AIDL呢,給一個定義吧。

AIDL:aidl是 Android Interface definition language的縮寫,一看就明白,它是一種android內部進程通信接口的描述語言,通過它我們可以定義進程間的通信接口(偷懶網上抄別人的,哈哈)

不多說了,直接看看怎麼用吧。

首選,建立一個aidl文件
目錄結構
這裏寫圖片描述
接口文件代碼:

// ICalcAIDL.aidl
package com.yx.calc.aidl;

// Declare any non-default types here with import statements

interface ICalcAIDL {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

            int add(int x , int y);
            int min(int x , int y );
}

這裏有3個方法,一個是創建時自動生成的,暫時不用理會。第二個是我們測試用是方法,輸入2個int值做加法運算。第三個是做減法運算(爲什麼是這個兩個方法?學習時別人就是這麼用的,照抄嘍,呵呵)

創建完接口文件,我們就要去創建一個具體的Service類了

package aidl.tongbu.com.aidl;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

import com.yx.calc.aidl.ICalcAIDL;


public class CalcService extends Service {

    @Override
    public IBinder onBind(Intent intent)
    {
        return mBinder;
    }


    private final ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub()
    {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
                        double aDouble, String aString)
        {

        }


        @Override
        public int add(int x, int y) throws RemoteException
        {
            return x + y;
        }

        @Override
        public int min(int x, int y) throws RemoteException
        {
            return x - y;
        }

    };
}

這個Service裏最主要的就是要自己實現一個Binder的類也就是ICalcAIDL.Stub這個Binder的子類。(如果大家像我一樣這麼寫的時候會提示找不到我們剛纔創建的接口文件,不用急。從新編譯一下項目就好了)。這個類裏就是實現接口文件的方法,一個加法,一個減法,很簡單。
還有一點就是把我們實例化的BInder對象在onBind()方法裏返回,這點很重要,不然白弄了。
還有就是去註冊這個Service。

<service android:name=".CalcService">
            <intent-filter>
                <action android:name="com.yx.aidl.calc" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </service>

這裏面配置了一個action,目的是爲了客戶端連接的時候方便。

到此服務端就沒什麼了,接下來去看看客戶端。

客戶端也是一樣去創建一個一模一樣的aidl接口文件。
這裏寫圖片描述

然後就是去activity裏去連接服務端的Service了,代碼如下:

package adil.example.com.client;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.yx.calc.aidl.ICalcAIDL;

public class MainActivity extends ActionBarActivity {

    private ICalcAIDL mCalcAidl;

    private ServiceConnection mServiceConn = new ServiceConnection()
    {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service)
        {
            Log.e("client", "onServiceConnected");
            mCalcAidl = ICalcAIDL.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name)
        {
            Log.e("client", "onServiceDisconnected");
            mCalcAidl = null;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    /**
     * 點擊BindService按鈕時調用
     * @param view
     */
    public void bindService(View view)
    {
        Intent intent = new Intent();
        intent.setAction("com.yx.aidl.calc");
        bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);
    }
    /**
     * 點擊unBindService按鈕時調用
     * @param view
     */
    public void unbindService(View view)
    {
        unbindService(mServiceConn);
    }
    /**
     * 點擊12+12按鈕時調用
     * @param view
     */
    public void addInvoked(View view) throws Exception
    {

        if (mCalcAidl != null)
        {
            int addRes = mCalcAidl.add(12, 12);
            Toast.makeText(this, addRes + "", Toast.LENGTH_SHORT).show();
        } else
        {
            Toast.makeText(this, "服務器被異常殺死,請重新綁定服務端", Toast.LENGTH_SHORT)
                    .show();

        }

    }

    /**
     * 點擊50-12按鈕時調用
     * @param view
     */
    public void minInvoked(View view) throws Exception
    {

        if (mCalcAidl != null)
        {
            int addRes = mCalcAidl.min(58, 12);
            Toast.makeText(this, addRes + "", Toast.LENGTH_SHORT).show();
        } else
        {
            Toast.makeText(this, "服務端未綁定或被異常殺死,請重新綁定服務端", Toast.LENGTH_SHORT)
                    .show();

        }

    }
}

首選這個activity裏有一個綁定服務的bindService方法,目的就是去綁定服務端的服務。Intent的配置就是通過隱式調用,進行綁定的。

這個ServiceConnection的實現就是爲了連接成功後拿到服務端的AIDL的對象也就是mCalcAidl,這樣就可以用他去調用對應的方法,實現進程間的通信目的。

private ServiceConnection mServiceConn = new ServiceConnection()
    {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service)
        {
            Log.e("client", "onServiceConnected");
            mCalcAidl = ICalcAIDL.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name)
        {
            Log.e("client", "onServiceDisconnected");
            mCalcAidl = null;
        }
    };

剩下的就很簡單了,用mCalcAidl進行想要的通信結束後就是unbindService的解綁定方法。
到此,整個AIDL的通信就完成了,還是很簡單的。

接下來再說說Service的一個子類,IntentService

調用方通過 startService(Intent)啓動服務,IntentService爲每一個Intent開啓一個單獨的工作線程,並且在任務完成時自動終止服務

這種“工作隊列處理器”模式通常用於某個程序主線程之外的後臺任務。IntentService類簡化了這種機制。要使用這種工作隊列模式,只使用繼承IntentService並實現onHandleIntent(Intent)方法。IntentService會接受Intents,啓動工作線程,並在合適的時候終止服務。

代碼很短,主要就是繼承IntentService,然後複寫onHandleIntent方法,根據傳入的intent來選擇具體的操作。

public class MyIntentService extends IntentService {  

    public MyIntentService(String name) {  
        super(name);  
    }  
    public MyIntentService() {  
        super("MyIntentService");  
    }  

    @Override  
    protected void onHandleIntent(Intent arg0) {  
        try {  
            //做一些耗時操作,比如上傳圖片等 
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }  
}  

看起來好像很厲害的樣子是吧,咱們看看鴻祥哥對於這個的分析(學習嘛,原帖的地址

http://blog.csdn.net/lmj623565791/article/details/47143563

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;
    }


    protected abstract void onHandleIntent(Intent intent);
}

可以看到它在onCreate裏面初始化了一個HandlerThread,就是每次調用onStartCommand的時候,通過mServiceHandler發送一個消息,消息中包含我們的intent。然後在該mServiceHandler的handleMessage中去回調onHandleIntent(intent);就可以了。

當任務完成銷燬Service回調onDestory,可以看到在onDestroy中釋放了我們的Looper:mServiceLooper.quit()。

主要就是利用了一下HandlerThread,那麼這個又是怎麼回事,下回複習的時候就在總結一下HandlerThread。

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