对于多数朋友来说Service都不会陌生,大名鼎鼎的安卓四大组件,主要在后台操作一些耗时的逻辑,或者去执行某些长期运行的任务,当我们退出程序的时候,程序还能在后台继续运行。
Service基本用法
要用肯定是要启动,service的启动和activity的类似
开启服务
startService(new Intent(ServiceActivity.this, MyService.class));
关闭服务
stopService(new Intent(ServiceActivity.this, MyService.class));
运行结果是:
当使用startService的时候,再次点击开启服务,只会走onStartCommand()方法, onCreate()方法不会再执行。
Service和Activity通信
当启动Service之后,就可以在onCreate()或者onStartCommand()方法中执行具体逻辑。
在代码中可以看到onBind()这个方法一直没有使用,这个方法其实就是用于和Activity建立关联的
注意:当通过startService和BinderService都启动了,想要销毁服务,不是说调用stopService和UnbinderService就销毁了,这只是停止了服务和解绑了服务,只有服务停止了和解绑的情况下服务才会被销毁。
Service和Thread的关系
首先Service是运行在主线程中的。也就是说在Service运行耗时操作一定会报ANR异常的。
如果是服务也需要创建子线程去耗时操作,为什么不直接在activity中去操作呢?这是因为activity很难对Thead进行控制,当activity销毁的时候就没有任何办法在获取到创建的子线程的实例,而且在activity中创建子线程实例,另外的activity无法对其操作。但是service不同,所有的Activity都可以与Service进行关联,然后通过ServiceConnect再次获取实例,因此activity可以放心的finish,完全不需要去控制。
public static class MyBinder extends Binder{
public void startDownload(){
//下载任务
new Thread(new Runnable() {
@Override
public void run() {
Logger.e("数据下载中。。。。。。。");
}
}).start();
}
}
另外一个进程运行服务
前面我们知道Service是运行在主线程中的,当我们的Service没有开启子线程,做延时操作的时候就会报ANR异常,如果我们在manifest中Service加:
运行后发现没有发生ANR异常,使用了远程service后,MyService已经在另外一个进程当中运行了,所有并不会阻塞主进程。在activity和service各自打印一个条日
Log.e("Tag", "current process ID"+Process.myPid());
发现打印出来的是不同的ID,说明他们不是运行在同一个进程中。
1、远程Service有好处也有坏处,当我们使用远程Service的时候,我们在刚才的代码中点击一下binderService按钮,然后就崩溃了,这是因为binderservice点击事件会让activity关联,但是service发现是一个远程的service,也就挂了
让activity和远程Service关联
要让activity和远程的service关联就要使用AIDL来跨进程通信。
AIDL是android的接口定义语言,他能让某个Service和多个应用程序之间进行跨进程通信,可以实现对个应用程序共享同一个Service的功能。
AIDL的用法:
1、先在android studio下创建一个MyAIDLService
// MyAIDLService.aidl
package com.example.hmh.firedemo;
// Declare any non-default types here with import statements
interface MyAIDLService {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
int plus(int a, int b);
}
2、添加一个Service,
public class MyService extends Service {
private MyBinder binder = new MyBinder();
private static final int NOTIFICATION_FLAG = 1;
@Override
public void onCreate() {
super.onCreate();
Logger.e("onCreate");
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Notification myNotify = new Notification();
myNotify.icon = R.mipmap.ic_launcher;
myNotify.tickerText = "TickerText:您有新短消息,请注意查收!";
myNotify.when = System.currentTimeMillis();
myNotify.flags = Notification.FLAG_NO_CLEAR;// 不能够自动清除
RemoteViews rv = new RemoteViews(getPackageName(),
R.layout.my_notification);
rv.setTextViewText(R.id.text_content, "hello wrold!");
myNotify.contentView = rv;
Intent intent = new Intent(Intent.ACTION_MAIN);
PendingIntent contentIntent = PendingIntent.getActivity(this, 1,
intent, 1);
myNotify.contentIntent = contentIntent;
manager.notify(NOTIFICATION_FLAG, myNotify);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Logger.e("Command");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Logger.e("ondestory");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mStub;
}
/**AIDL的使用*/
MyAIDLService.Stub mStub = new MyAIDLService.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public int plus(int a, int b) throws RemoteException {
return a + b;
}
};
}
3、在Manifest.xml中添加action
这里的action提供给外部的应用程序使用
4、写另外一个app,testApp,在MainActivity中添加链接
public class MainActivity extends AppCompatActivity {
private Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.binder);
/**绑定服务*/
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Intent intent = new Intent();
intent.setAction("com.example.hmh.firedemo.MyAIDLService");
final Intent eintent = new Intent(createExplicitFromImplicitIntent(MainActivity.this,intent));
bindService(eintent,conn, Service.BIND_AUTO_CREATE);
}
});
}
/*连接服务***/
private ServiceConnection conn = new ServiceConnection() {
private MyAIDLService myAIDLService;
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myAIDLService = MyAIDLService.Stub.asInterface(service);
try {
int plus = myAIDLService.plus(3, 5);
Log.e("fuck", plus+" // ");
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
/**android 21以后,调用隐士的服务会崩溃,所有调用这个方法**/
public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
PackageManager pm = context.getPackageManager();
List resolveInfo = pm.queryIntentServices(implicitIntent, 0);
if (resolveInfo == null || resolveInfo.size() != 1) {
return null;
}
ResolveInfo serviceInfo = resolveInfo.get(0);
String packageName = serviceInfo.serviceInfo.packageName;
String className = serviceInfo.serviceInfo.name;
ComponentName component = new ComponentName(packageName, className);
Intent explicitIntent = new Intent(implicitIntent);
explicitIntent.setComponent(component);
return explicitIntent;
}
}
利用serviceConnection来获取AIDL的代理对象,然后调用AIDL中的方法。
6、最后打印结果:3+5 = 8,结果正确
在平时服务用的不是很多,所以经常忘记就弄个复习文章来自郭大神的bolg,支持原创:http://blog.csdn.net/guolin_blog/article/details/9797169。