关于郭神Service的讲解的学习总结,想看郭神原版请看该链接http://blog.youkuaiyun.com/guolin_blog/article/details/9797169
远程Service
远程Service,它现在运行在与主线程不同的线程当中,所以我们不能在ServiceConnected方法里面对它的public方法进行调用,只能是通过AIDL来进行通信,与此同时远程Service还可以实现进程间的通信。
步骤一:首先你要在注册Service的Application中将其注册为远程Service,并且指定一个action给Service,以便于其他进程与之进行通信。
Mainfest.xml文件实例代码如下:
<service android:name=".MyService"
android:process=":remote">
<intent-filter>
<action android:name="com.glimmer.myapplication.MyAIDLService"/>
</intent-filter>
</service>
步骤二:在MyApplication中新建一个名为MyAIDLService的AIDL接口。
MyAIDLService的实例代码如下:
interface MyAIDLService {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
int plus(int a, int b);
String toUpperCase(String str);
}
步骤三:在MyService里面实现AIDL的接口,具体的做法如下:
/**
* 用来建立 Service 和 Activity之间的联系
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
MyAIDLService.Stub binder = new MyAIDLService.Stub() {
@Override
public int plus(int a, int b) throws RemoteException {
return a + b;
}
@Override
public String toUpperCase(String str) throws RemoteException {
if (str != null) {
return str.toUpperCase();
}
return null;
}
};
在IBinder方法里返回的就是实现接口的binder,这样在绑定的Activit里面,无论是同一个进程还是不同的进程,都可以调用这两个public方法。
步骤四:在(同一进程下的)MainActivity当中对Service进行绑定,首先就是ServiceConnnection里面的onServiceConnected的方法不同了,它要通过我们定义好的AIDL接口去进行方法的调用,代码如下:
public void onServiceConnected(ComponentName name, IBinder service) {
myAIDLService = MyAIDLService.Stub.asInterface(service);
try {
int result = myAIDLService.plus(3,5);
String upperStr = myAIDLService.toUpperCase("hello world");
Log.d(TAG, "onServiceConnected: result:"+result);
Log.d(TAG, "onServiceConnected: upperStr:"+upperStr);
} catch (RemoteException e) {
e.printStackTrace();
}
}
在同一进程中,调用bindService的方法与之前一样,可以看一下我的上一篇总结 点击打开链接,现在主要来讲一下不同进程之间的调用方式。
步骤五:在HappyBirthday的应用中将MyApplication的AIDL的文件整个粘贴过来,如下图:
注意:一定要整个文件夹都粘贴过来
步骤六:接下来我们就可以调用我们的Service里面的方法啦,像步骤四一样在(不同进程下的)SecondActivity中生成ServiceConnect的对象connection。代码如下:
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myAIDLService = MyAIDLService.Stub.asInterface(service);
try {
int result = myAIDLService.plus(3, 9);
String upperStr = myAIDLService.toUpperCase("aaa");
Log.d(TAG, "Result: " + result);
Log.d(TAG, "UpperStr:" + upperStr);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
与步骤四没有任何的区别,接下来就是重点要区分的。
步骤七:如何将Service和Activity联系在一起?这里需要注意的是,在不同进程中,我们只能通过action的name来进行意图的指定在Android 5.0版本之前,我们可以直接用这种方式:
Intent intent = new Intent("com.glimmer.myapplication.MyAIDLService");
/* intent.setAction("com.glimmer.myapplication.MyAIDLService");
intent.setPackage("com.glimmer.myapplication");*/
bindService(intent, connection, BIND_AUTO_CREATE);
但是在实践的过程中,我发现用5.0的系统的手机去启动该应用会出现如下的错误:
java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=com.glimmer.myapplication.MyAIDLService }
经过查资料得知,在Android 5.0版本之后不支持Service的隐式意图启动,并给出了如下解决方案:
Intent intent = new Intent();
intent.setAction("com.glimmer.myapplication.MyAIDLService");
intent.setPackage("com.glimmer.myapplication");
bindService(intent, connection, BIND_AUTO_CREATE);
这样我们就实现了Service的进程间通信,运行结果如下:
END