Android Service全解析(一)

Service全解析(一)

==1.Service基本介紹==
==2.啓動模式下的Service==
==3.綁定模式下的Service==

==4.與Remote Service數據交互==

  首先看一下Service的生命週期,啓動模式(startService()/stopService)下的生命週期爲:
onCreate() —-> onStartCommand() —-> onDestroy() ;
綁定模式下:onCreate() —-> onBind() —->onBind() —-> onDestroy() ;
  啓動模式下不會執行onStartCommand()方法,所以邏輯處理放在onCreate()中。
需要注意的一點是5.0版本以上的隱式啓動,Intent需要setPackage,否則會報錯;


綁定模式下Service的onBind()方法會返回一個 Binder對象,在調用bindService()方法的地方得到這個Binder對象,從而實現與Service的交互。
Binder 繼承 IBinder。

代碼分析(省略了部分無關方法)

public class CountSumService extends Service {

    private ServiceBinder serviceBinder = new ServiceBinder();

    @Override
    public IBinder onBind(Intent intent) {
        Log.v("out","onBind()");
        return serviceBinder;
    }

    public void test(){
        Log.v("out","service test demo");
    }

    public class ServiceBinder extends Binder{
        public CountSumService getService(){
            return CountSumService.this;
        }
    }
}

Service內部創建了一個 了Binder的類,然後在onBind()方法中返回了這個類的實例,這個實例在創建ServiceConnection的onServiceConnected()方法中可以拿到。


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = this;
        setContentView(R.layout.activity_service_demo);
        conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.v("out",name.toString());
                IBinder temp = service;
                if(service!=null) {
                    countSumService = ((CountSumService.ServiceBinder) service).getService();
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                countSumService = null;
            }
        };
        mContext.bindService(new Intent(ServiceDemoActivity.this,CountSumService.class) ,conn,BIND_AUTO_CREATE);
        //countSumService.test();
        Log.v("out","斷點");
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (countSumService==null){
                    if(countSumService!=null){
                        countSumService.test();
                    }
                }
            }
        }).start();
    }

創建ServiceConnection的onServiceConnected()方法得到Service中返回的Binder對象。
這裏有一個坑:得到這個Binder對象是異步的不是同步的,所以你bindService()後不能直接得到binder對象,一般都是在onServiceConnected()方法中使用;如果非得在外面使用,可以像我這樣開一個線程來獲取。

Remote Service
上面講的都是與本地Service交互,那麼遠程Service呢,與Remote Service交互涉及到IPC, 通常有這3種方式實現:
==1.廣播==
==2.AIDL==
==3.Message==
這裏主要講後兩張方法。
先看AIDL方式的實現:
(1)創建一個Remote Service,AndroidManifest.xml文件配置Service屬性:兩種方式,第一:android:process = “remote”,這種方式創建的Service會運行在一個新進程中,但是這一個新的進程是公有的,也就是說其他的應用也可以運行在這個進程中;第二:android:process=”:任意字符”,(注意:號)這樣創建的是一個私有新程。
(2)與本地Service不同的地方在於,本地Service我們自己創建一個繼承與Binder的類,而遠程Service需要通過創建.aidl文件來自動爲我們生成一個Binder類。
(3)下面介紹在AS中創建aidl文件:
 a.切換到Project狀態
b.右鍵c/in/java目錄,new —-> AIDL文件,生成的aidl文件會自動放到與java同級的AIDL文件夾下。

import com.wangliang160616.androidtest.model.student;
interface IMyAidlInterface {

    void setStuInfo(in student stu);
    void setAge(int age);

}

注意:import需要手動寫。
你以爲這就完了,too yang too simple
傳遞基本數據類型和String,CharSequence,List,Map這些是ok的,但是如果是自己定義的Model,比如我碼中的student類,要跨進程傳遞,應該這樣做:
(1)自定義的類繼承Parcelable
(2)在你放這個model的包上右鍵new aidl,先隨便起一個名字,等他自動生成後將名字改成與你這個Model同名的名字。
(3)Build –> make project ,AS自動生成java文件,這個java 文件在哪呢,資料上都說在gen目錄下,但是在AS下面根本沒有gen目錄,在app/build/generate/source/aidl,題外話,R文件app/build/generate/source/r下面
(4)回到Service,onBind()方法返回根據AIDL文件自動生成的java類中的Stup對象即可。看代碼:

public class RemoteService extends Service {

    private student data;
    private int age;

    private IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub(){

        @Override
        public void setStuInfo(student stu) throws RemoteException {
            if(stu!=null){
                data = stu;
            }
            Log.v("out","當前Service pid:"+android.os.Process.myPid());
            Log.v("out","姓名:"+data.getStuName()+"/id:"+data.getStuId());
        }

        @Override
        public void setAge(int age) throws RemoteException {
            data.setStuId(age);
            Log.v("out","姓名:"+data.getStuName()+"/id:"+data.getStuId());
        }
    };

    public RemoteService() {
    }

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

(5)在activity中這樣
IMyAidlInterface Service = IMyAidlInterface.Stub.asInterface(service);
得到Binder對象。

==還有有一種通過Messenger方式來通信的,在(二)中我會介紹這種方法。==


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