zoukankan      html  css  js  c++  java
  • Android Service(下)

    阅读本文需要先阅读Android Service(上)

    一 为什么需要bindService()

    绑定服务就是为了和服务进行通讯 可以调用服务里面的方法

    二 bindService()调用服务里面方法的流程

    1. 绑定服务

    2. 在onBind()方法返回增强IBinder对象

    3. 把IBinder转化为接口对象

    4. 调用服务里面的方法

    三 bindService()之本地服务

    调用者和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;
            }
        }
    }
  • 相关阅读:
    福大软工1816 · 第六次作业
    福大软工1816 · 第五次作业
    BETA 版冲刺前准备
    Alpha 事后诸葛亮(团队)
    Alpha 答辩总结
    Alpha 冲刺 (10/10)
    Alpha 冲刺 (9/10)
    Alpha 冲刺 (8/10)
    Alpha 冲刺 (7/10)
    Alpha 冲刺 (6/10)
  • 原文地址:https://www.cnblogs.com/huangyi-427/p/9599501.html
Copyright © 2011-2022 走看看