阅读本文需要先阅读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;
}
}
}

Android Service(下)的更多相关文章

  1. Android Service(上)

    一 Service简介 Service是Context的子类 Service是四大组件之一 用来在后台处理一些比较耗时的操作或者去执行某些需要长期运行的任务 二 注意 Service里面不能直接执行耗 ...

  2. Android Service完全解析,关于服务你所需知道的一切(下)

    转载请注册出处:http://blog.csdn.net/guolin_blog/article/details/9797169 在上一篇文章中,我们学习了Android Service相关的许多重要 ...

  3. 【转】Android Service完全解析,关于服务你所需知道的一切(下) ---- 不错

    原文网址:http://blog.csdn.net/guolin_blog/article/details/9797169 转载请注册出处:http://blog.csdn.net/guolin_bl ...

  4. Android Service(下)

    转载请注册出处:http://blog.csdn.net/guolin_blog/article/details/9797169 在上一篇文章中,我们学习了Android Service相关的许多重要 ...

  5. Android Service完全解析,关于服务你所需知道的一切(下) (转载)

    转自:http://blog.csdn.net/guolin_blog/article/details/9797169 转载请注册出处:http://blog.csdn.net/guolin_blog ...

  6. Android Service完全解析(下)

    转载http://blog.csdn.net/guolin_blog/article/details/9797169 在上一篇文章中,我们学习了Android Service相关的许多重要内容,包括S ...

  7. Android Service完全解析,关于服务你所需知道的一切(上)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11952435 相信大多数朋友对Service这个名词都不会陌生,没错,一个老练的A ...

  8. android service 的各种用法(IPC、AIDL)

    http://my.oschina.net/mopidick/blog/132325 最近在学android service,感觉终于把service的各种使用场景和用到的技术整理得比较明白了,受益颇 ...

  9. Android Service AIDL 远程调用服务 【简单音乐播放实例】

    Android Service是分为两种: 本地服务(Local Service): 同一个apk内被调用 远程服务(Remote Service):被另一个apk调用 远程服务需要借助AIDL来完成 ...

随机推荐

  1. 全部读取------------ 一次性全部读取的.read() VS 一行一行的for迭代

    全部读取 f = open("喜洋洋",mode= "r",encoding= "utf-8") 方法一:     一次性全部读取f = o ...

  2. 笔记本无密码连接wifi

    用手机可以用wifi万能钥匙破解wifi,就想找电脑版的wifi万能钥匙,然并卵. 就去寻找各种办法,最后找了个巧, 用手机下载wifi万能钥匙连接,并且使用数据线连接上笔记本. 然后手机设置中找到开 ...

  3. linux用户相关及/etc/passed,/etc/group,/etc/shadow

    useradd:新建用户 usermod:修改用户相关信息 userdel:删除用户分(-r选项) 组的操作与用户的操作类似 选项 userdel相关选项: -f:强制删除用户,即使用户已登录 -r: ...

  4. 多线程之Timer和TimerTask

    Timer是一种线程设施,用于安排以后在后台线程中执行的任务.可安排任务执行一次,或者定期重复执行,可以看成一个定时器,可以调度TimerTask.TimerTask是一个抽象类,实现了Runnabl ...

  5. 垂直方向兼容显示的内容多少的情况样式Flex布局

    使用flex弹性布局,无论里面的元素显示几个,都会居中显示,父元素设置成如下样式 display: flex; flex-direction: column; justify-content: cen ...

  6. Mac环境下安装配置Hadoop伪分布式

    伪分布式需要修改5个配置文件(hadoop2.x的配置文件$HADOOP_HOME/etc/hadoop) 第一个:hadoop-env.sh #vim hadoop-env.sh #第25行,由于新 ...

  7. Jenkins+github的一次定时构建示例

    首先说明,我的电脑环境是windows,所以以下的示例是基于windows10 X64. 一.新建任务,填写名称,选择类型,点击左下角的[确定] 二.配置 1.General 2.源码管理 之前在gi ...

  8. HDU 1203 01背包变形题,(新思路)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1203 I NEED A OFFER! Time Limit: 2000/1000 MS (Java/ ...

  9. MySql优化分析

    原理 MYSQL逻辑分层 :连接层 服务层 引擎层 存储层 InnoDB(默认) :事务优先 (适合高并发操作:行锁) MyISAM :性能优先 (表锁) SQL优化 编写过程: sql select ...

  10. vue中刷新页面时去闪烁,提升体验方法

    首先在最外层div添加v-if="isReloadAlive",并创建变量isReloadAlive = true 随后添加provide()以及reload方法,如下: expo ...