Service 是 android的一个重要组建,用到的地方也比较多。
Service 上一章讲的是本地服务,现在讲讲远程服务,即跨进程服务。
如果是本地服务,按照下面的写法
public class MyService extends Service {
@Override
public void onCreate() {
super.onCreate();
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在activity中点击Start Service按钮,开启该服务,会发现,几秒钟后程序报出了ANR异常提示框。这是因为本地service也是在UI线程中,如果要做耗时操作,可以在里面开启一个子线程,在子线程中做耗时操作,操作完成后,可以和广播配合,把数据发回activity中。
把一个本地服务变成远程服务,很简单,在配置清单里面,服务配置的节点里,添加 <service android:process=":remote" > 即可。
我们重新点击Start Service按钮,发现没有ANR异常,因为该service和UI线程已经不在同一个进程中了,不会阻塞UI线程。有些app采用多进程方法,提高app的运行流畅度,但多进程用起来有一定难度,少不留神就出错了,主要原因为数据传递和共享问题。
多进程中,所谓的自定义单例模式 application 单例等等统统失效了,不能共享数据,因为没在一个进程中,所以数据处理是一个难题。
service还有一个问题,就是在绑定服务时,程序会报错,因为此时service已经是远程服务了,activity和service运行在两个不同的进程里面,传统的关联方式不适用了,所以报错。此时,一个技术就闪亮登场了,那就是AIDL。
我们可以手写一个aidl,用记事本写,像写接口一样,把.txt 后缀名 改为 .aidl即可。
interface AIDLService {
int add(int a, int b);
}
保存后,编译器会自动编译。
在上述service里面,绑定自己的bind。
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
AIDLService.Stub mBinder = new Stub() {
@Override
public int add(int a, int b) throws RemoteException {
return a + b;
}
};
}
Stub是Binder的子类,所以在onBind()方法中可以直接返回Stub的实现,进行绑定。
activity中,绑定的写法和参数不变,启动的方法也一样,只需要改写一点即可,即ServiceConnection
private AIDLService myAIDLService;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myAIDLService = AIDLService.Stub.asInterface(service);
try {
int result = myAIDLService.add(3, 5);
Log.d("TAG", "result " + result);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
如此,即可,其实跨进程看着也没什么难的。
以上是在自己的程序里调用,如果想让别的程序调用怎么办呢?就好把调用支付宝支付,其实就是支付宝的远程服务,封装好了,提供 .aidl文件,让我们调用。其实原理也间单
封装的service远程服务不用改写,在配置清单里,给服务的注册添加一个actiion数据,要保证这个action是独一无二的,
<service
android:name="com.example.cn.MyService"
android:process=":remote" >
<intent-filter>
<action android:name="com.example.cn.AIDLService"/>
</intent-filter>
</service>
然后再把我们编写的.aidl文件,大公无私的贡献出来就可以了,剩下的就是调用者的工作了。
在另一个程序B里,我们想调用上述的远程服务,要做几件事,首先要把.aidl文件拷到自己的项目里,注意,文件夹的名字也要与上述程序.aidl文件所在文件的名字相同。
ServiceConnection里面的写法不用修改,要改变的是启动service的方法,上述是直接启动,现在远程调用,需要用到隐式启动了,
Intent intent = new Intent("com.example.cn.AIDLService");
bindService(intent, connection, BIND_AUTO_CREATE);
如此,完工了。跨进程通讯完成了。还有另一种跨进程的方式,是使用Messenger,好奇的可以自己搜搜。
Service 上一章讲的是本地服务,现在讲讲远程服务,即跨进程服务。
如果是本地服务,按照下面的写法
public class MyService extends Service {
@Override
public void onCreate() {
super.onCreate();
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在activity中点击Start Service按钮,开启该服务,会发现,几秒钟后程序报出了ANR异常提示框。这是因为本地service也是在UI线程中,如果要做耗时操作,可以在里面开启一个子线程,在子线程中做耗时操作,操作完成后,可以和广播配合,把数据发回activity中。
把一个本地服务变成远程服务,很简单,在配置清单里面,服务配置的节点里,添加 <service android:process=":remote" > 即可。
我们重新点击Start Service按钮,发现没有ANR异常,因为该service和UI线程已经不在同一个进程中了,不会阻塞UI线程。有些app采用多进程方法,提高app的运行流畅度,但多进程用起来有一定难度,少不留神就出错了,主要原因为数据传递和共享问题。
多进程中,所谓的自定义单例模式 application 单例等等统统失效了,不能共享数据,因为没在一个进程中,所以数据处理是一个难题。
service还有一个问题,就是在绑定服务时,程序会报错,因为此时service已经是远程服务了,activity和service运行在两个不同的进程里面,传统的关联方式不适用了,所以报错。此时,一个技术就闪亮登场了,那就是AIDL。
我们可以手写一个aidl,用记事本写,像写接口一样,把.txt 后缀名 改为 .aidl即可。
interface AIDLService {
int add(int a, int b);
}
保存后,编译器会自动编译。
在上述service里面,绑定自己的bind。
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
AIDLService.Stub mBinder = new Stub() {
@Override
public int add(int a, int b) throws RemoteException {
return a + b;
}
};
}
Stub是Binder的子类,所以在onBind()方法中可以直接返回Stub的实现,进行绑定。
activity中,绑定的写法和参数不变,启动的方法也一样,只需要改写一点即可,即ServiceConnection
private AIDLService myAIDLService;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myAIDLService = AIDLService.Stub.asInterface(service);
try {
int result = myAIDLService.add(3, 5);
Log.d("TAG", "result " + result);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
如此,即可,其实跨进程看着也没什么难的。
以上是在自己的程序里调用,如果想让别的程序调用怎么办呢?就好把调用支付宝支付,其实就是支付宝的远程服务,封装好了,提供 .aidl文件,让我们调用。其实原理也间单
封装的service远程服务不用改写,在配置清单里,给服务的注册添加一个actiion数据,要保证这个action是独一无二的,
<service
android:name="com.example.cn.MyService"
android:process=":remote" >
<intent-filter>
<action android:name="com.example.cn.AIDLService"/>
</intent-filter>
</service>
然后再把我们编写的.aidl文件,大公无私的贡献出来就可以了,剩下的就是调用者的工作了。
在另一个程序B里,我们想调用上述的远程服务,要做几件事,首先要把.aidl文件拷到自己的项目里,注意,文件夹的名字也要与上述程序.aidl文件所在文件的名字相同。
ServiceConnection里面的写法不用修改,要改变的是启动service的方法,上述是直接启动,现在远程调用,需要用到隐式启动了,
Intent intent = new Intent("com.example.cn.AIDLService");
bindService(intent, connection, BIND_AUTO_CREATE);
如此,完工了。跨进程通讯完成了。还有另一种跨进程的方式,是使用Messenger,好奇的可以自己搜搜。