Android Service(下)

閱讀本文須要先閱讀Android Service(上)html

一 爲何須要bindService()java

綁定服務就是爲了和服務進行通信 能夠調用服務裏面的方法android

 

二 bindService()調用服務裏面方法的流程安全

1. 綁定服務app

2. 在onBind()方法返回加強IBinder對象ide

3. 把IBinder轉化爲接口對象ui

4. 調用服務裏面的方法this

 

三 bindService()之本地服務spa

調用者和Service在同一進程代理

彼此之間擁有共同的內存區域 因此對於某些數據的共享特別的方便和簡單

1. 新建一個Model 實現Parcelable接口

public class User implements Parcelable {

    public int id;
    public String name;

    public User() {}

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    protected User(Parcel in) {
        id = in.readInt();
        name = in.readString();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(id);
        dest.writeString(name);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    public static final Creator<User> CREATOR = new Creator<User>() {
        @Override
        public User createFromParcel(Parcel in) {
            return new User(in);
        }

        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };

}

2. 功能接口的抽取

public interface IUserDao {

    int selectUserCount();

    User selectUser(User user);

}

3. 新建一個IBinder

public class MyBinder extends Binder implements IUserDao {

    @Override
    public int selectUserCount() {
        return 20;
    }

    @Override
    public User selectUser(User user) {
        user.id = 4;
        return user;
    }

}

4. 新建一個Service

public class MyService extends Service {

    MyBinder mBinder = new MyBinder();

    @Nullable @Override
    public IBinder onBind(Intent intent) {
        Log.i("HUANG", "MyService pid=" + android.os.Process.myPid());
        return mBinder;
    }

}

5. AndroidManifest.xml application節點裏面配置service name屬性必須配置 其他可選

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

6. bindService()調用服務裏面方法

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    ServiceConnection mConnection; //服務的鏈接對象
    IUserDao mUserDao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i("HUANG", "MainActivity pid=" + android.os.Process.myPid());
        findViewById(R.id.count).setOnClickListener(this);
        findViewById(R.id.user).setOnClickListener(this);
        // bindService() 是須要時間的
        Intent service = new Intent(this, MyService.class);
        mConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                mUserDao = (IUserDao) service;
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {}
        };
        bindService(service, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mConnection);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.count:
                int count = mUserDao.selectUserCount();
                Log.i("HUANG", "count=" + count);
                break;

            case R.id.user:
                User user = mUserDao.selectUser(new User(1, "1"));
                Log.i("HUANG", "id=" + user.id);
                Log.i("HUANG", "name=" + user.name);
                break;
        }
    }

}

 

四 bindService()之遠程服務

調用者和Service在不一樣進程

由於Android系統安全的緣由 致使了咱們在不一樣進程間沒法使用通常方式共享數據

因此Android爲咱們提供了AIDL(Android Interface Definition Language)

AIDL是一種接口定義語言 用於約束兩個進程間的通信規則 供編譯器生成代碼 實現Android設備上的兩個進程間通訊(IPC)

進程之間的通訊信息 首先會被轉換成AIDL協議消息 而後發送給對方 對方收到AIDL協議消息後再轉換成相應的對象

因爲進程之間的通訊信息須要雙向轉換 因此Android採用代理類在背後實現了信息的雙向轉換 代理類由Android編譯器生成 對開發人員來講是透明的

AIDL自動生成Java文件後 開發人員使用Stub

注意: 實現調用者和Service在不一樣進程有兩種方式

1. 調用者和Service在同一個應用程序 配置Service時指定process屬性(必定要指定 不指定就在同一進程)

<service android:name=".service.MyService"
    android:process=":test" />

2. 調用者在一個應用程序 Service在另外一個應用程序

下面演示採用第二種方式 調用者做爲一個應用程序名叫Client Service做爲一個應用程序名叫Service

Service端

1. 新建一個Model 實現Parcelable接口 須要多加一個readFromParcel()方法 不加報錯

public class User implements Parcelable {

    public int id;
    public String name;

    public User() {}

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    protected User(Parcel in) {
        id = in.readInt();
        name = in.readString();
    }

    public void readFromParcel(Parcel in) {
        id = in.readInt();
        name = in.readString();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(id);
        dest.writeString(name);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    public static final Creator<User> CREATOR = new Creator<User>() {
        @Override
        public User createFromParcel(Parcel in) {
            return new User(in);
        }

        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };

}

2. 新建一個AIDL文件聲明Model(User.aidl) 注意包結構 要和Model的Java文件類路徑同樣 不然報錯

package com.hy.service.model;
parcelable User;

3. 功能接口的抽取(IUserDao.aidl) 注意包結構

package com.hy.service;

import com.hy.service.model.User;

interface IUserDao {

    int selectUserCount();

    // in 服務端能夠收到調用者傳遞的完整數據 服務端修改傳參不會影響調用者中的對象(形參改變對實參沒有任何影響)
    User inUser(in User user);

    // out 服務端能夠收到調用者傳遞的空數據 服務端修改傳參會影響調用者中的對象(形參改變對實參有直接影響)
    User outUser(out User user);

    // inout 服務端能夠收到調用者傳遞的完整數據 服務端修改傳參會影響調用者中的對象(形參改變對實參有直接影響)
    User inoutUser(inout User user);

    // in out inout 用來修飾引用類型參數 必填 不填報錯
    // 基本類型參數不須要指定in out inout 默認是而且只能是in
}

4. Build -> Make Project 生成Java文件

5. 新建一個IBinder

public class MyBinder extends IUserDao.Stub {

    @Override
    public int selectUserCount() throws RemoteException {
        return 15;
    }

    @Override
    public User inUser(User user) throws RemoteException {
        Log.i("HUANG", "MyService inUser id=" + user.id);
        user.id = 4;
        return user;
    }

    @Override
    public User outUser(User user) throws RemoteException {
        Log.i("HUANG", "MyService outUser id=" + user.id);
        user.id = 5;
        return user;
    }

    @Override
    public User inoutUser(User user) throws RemoteException {
        Log.i("HUANG", "MyService inoutUser id=" + user.id);
        user.id = 6;
        return user;
    }

}

6. 新建一個Service

public class MyService extends Service {

    MyBinder mBinder = new MyBinder();

    @Nullable @Override
    public IBinder onBind(Intent intent) {
        Log.i("HUANG", "MyService pid=" + android.os.Process.myPid());
        return mBinder;
    }

}

7. AndroidManifest.xml application節點裏面配置service name屬性必須配置 其他可選

<service android:name=".service.MyService">
    <intent-filter>
        <action android:name="com.hy.service.action.TEST" />
    </intent-filter>
</service>

Client端

1. 把Service端User.aidl IUserDao.aidl User.java 文件和包結構一塊兒拷貝過來

2. Build -> Make Project 生成Java文件

3. bindService()調用服務裏面方法

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    ServiceConnection mConnection; //服務的鏈接對象
    IUserDao mUserDao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i("HUANG", "MainActivity pid=" + android.os.Process.myPid());
        findViewById(R.id.count).setOnClickListener(this);
        findViewById(R.id.in).setOnClickListener(this);
        findViewById(R.id.out).setOnClickListener(this);
        findViewById(R.id.inout).setOnClickListener(this);
        // bindService() 是須要時間的
        Intent service = new Intent();
        service.setAction("com.hy.service.action.TEST");
        service.setPackage("com.hy.service"); //兼容Android 5.0
        mConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                // service是一個代理對象 代理對象不能直接使用
                mUserDao = IUserDao.Stub.Stub.asInterface(service); //把代理對象變爲真實對象
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {}
        };
        bindService(service, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mConnection);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.count:
                try {
                    int count = mUserDao.selectUserCount();
                    Log.i("HUANG", "MainActivity count=" + count);

                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;

            case R.id.in:
                try {
                    User rawUser = new User(1, "1");
                    User user = mUserDao.inUser(rawUser);
                    Log.i("HUANG", "MainActivity rawUser inUser id=" + rawUser.id);
                    Log.i("HUANG", "MainActivity user inUser id=" + user.id);

                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;

            case R.id.out:
                try {
                    User rawUser = new User(2, "2");
                    User user = mUserDao.outUser(rawUser);
                    Log.i("HUANG", "MainActivity rawUser outUser id=" + rawUser.id);
                    Log.i("HUANG", "MainActivity user outUser id=" + user.id);

                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;

            case R.id.inout:
                try {
                    User rawUser = new User(3, "3");
                    User user = mUserDao.inoutUser(rawUser);
                    Log.i("HUANG", "MainActivity rawUser inoutUser id=" + rawUser.id);
                    Log.i("HUANG", "MainActivity user inoutUser id=" + user.id);

                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
        }
    }
}
相關文章
相關標籤/搜索