Service看过很多遍,今天尝试着自己实践和总结一下。主要总结Service的启动方式(同一个进程和不同进程)以及特点,交互(包括AIDL)
一:Service的启动方式有两种,一种是startService,另一种是bindService
1.创建一个Service
public class MyStartService1 extends Service {
int count=0;
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 100:
count+=1;
Log.e("TAG","MyStartService1正在执行:"+count);
sendEmptyMessageDelayed(100,3000);
break;
case 200:
break;
}
}
};
@Override
public void onCreate() {
super.onCreate();
Log.e("TAG", "MyStartSerice1--onCreate--当前进程:"+getCurProcessName(this) );
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("TAG", "MyStartSerice1--onStartCommand-starttId:" + startId);
if (intent != null) {
String extra = intent.getStringExtra("extra");
Log.e("TAG", "MyStartSerice1--intent参数:" + extra);
} else {
Log.e("TAG", "MyStartSerice1--intent参数:null!!!");
}
handler.removeCallbacksAndMessages(null);
Message obtain = Message.obtain();
obtain.what=100;
handler.sendMessage(obtain);
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
Log.e("TAG", "MyStartSerice1--onDestroy");
}
public String getCurProcessName(Context context) {
int pid = android.os.Process.myPid();
ActivityManager mActivityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo appProcess : mActivityManager
.getRunningAppProcesses()) {
if (appProcess.pid == pid) {
return appProcess.processName;
}
}
return "";
}
}
2.启动和停止方式
同一个进程中:直接startService
intentService = new Intent(TestActivity1.this, MyStartService1.class);
intentService.putExtra("extra","我是参数,test1");
startService(intentService);
不同进程中:需要通过包名,类名进行开启setComponent(new ComponentName(包名,类名))
intentService = new Intent();
intentService.putExtra("extra","test2参数");
intentService.setComponent(new ComponentName("com.example.liukang.mykuajincheng",MyStartService2.class.getName()));
startService(intentService);
3.两个APP之间,如果一个A应用去启动B应用的Service,而此时B应用已经被杀死了。那如何启动:
a. B应用的Service 需要做的是 :
android:exported="true"
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
b. A应用需要开启一个Servivce,然后在此Service里面用
startForegroundService(intent1);
方式去启动B应用的Service。
c. 在B应用的这个Service中需要开启一下消息通知,否则会抛异常。(android O 开始已经不允许开一个后台服务了)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { setForeground(); }
@TargetApi(26) private void setForeground(){ NotificationManager manager=(NotificationManager)getSystemService (NOTIFICATION_SERVICE); NotificationChannel channel=new NotificationChannel (ID,NAME,NotificationManager.IMPORTANCE_HIGH); manager.createNotificationChannel (channel); Notification notification=new Notification.Builder (this,ID) .setContentTitle ("收到一条重要通知") .setContentText ("这是重要通知") .setSmallIcon (R.mipmap.ic_launcher) .setLargeIcon (BitmapFactory.decodeResource (getResources (),R.mipmap.ic_launcher)) .build (); startForeground (1,notification); }
关闭Service: stopService(intentService)和stopSelf(startId)
stopService(intentService);
二:startService周期:
onCreate-->onStartCommand-->onDestroy 如果是已经开启的startservice,无论startService多少次,都不会再去oncre,而是一直调用onStartCommand方法
可以被很多个Activity开启,也可以在任意一个Acivity里通过stopService(intent)进行结
在startCommand中返回的三种Int类型的返回值意义:
1.START_NOT_STICKY = 2 被杀后不重启。服务被启动之后,当服务所在进程被杀死,并且当前没有新的Intents等待发送给它,那么不再新建服务,并被标记为非启动状态,直至下一个明确启动调用—startService()。
2.START_STICKY = 1 被杀后自动重启,保持启动状态,不保持Intent,重新调用onStartCommand,无新Intent则为空Intent—杀死重启后,不继续执行先前任务,能接受新任务
3.START_REDELIVER_INTENT =3 如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
startService的特点:
1.他开启的是一个服务,他的优先级,前台进程>可见进程>服务进程>后台进程>空进程,所以在资源不足的情况下会尽量存活。
2.当资源不足,服务被杀死之后,当资源充裕的时候又可以重新启动,根据startCommmand()返回类型决定。
3.多次启动,只会执行一次onCreate(),多次执行startCommand()
4. 当启动服务的界面,类Destroy()的时候,他仍然会继续运行,另外可以在任意其他界面通过调用stopService(intent)结束它
,对于一些长时间运行的任务可以放在服务里面,比如心跳之类的网络请求。
二 BindService绑定服务,这是一个重头戏,因为他涉及到交互包括跨进程的AIDL,由浅入深的说到说到。
简述:生命周期 onCreate()--> onBind()-->onUnbind()-->onDestroy()
1.在同一个进程中,先创建Service1: onBind()返回一个Binder对象并重写了几个方法
package com.example.liukang.mykuajincheng.bindservice;
import android.app.Service;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.support.annotation.Nullable;
import android.util.Log;
public class MyBindService1 extends Service {
int count=0;
Handler handler=new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what){
case 1000:
Log.e("TAG","MyBindService1服务开启了:"+count);
count+=1;
handler.sendEmptyMessageDelayed(1000,3000);
break;
}
return true;
}
});
MyBinder1 myBinder1 = new MyBinder1();
class MyBinder1 extends Binder implements Iterface {
public MyBindService1 getService() {
return MyBindService1.this;
}
@Override
public void start() {
handler.sendEmptyMessage(1000);
}
@Override
public void stop() {
handler.removeCallbacksAndMessages(null);
}
@Override
public String open(String ss) {
return "result=" + ss;
}
}
@Override
public void onCreate() {
super.onCreate();
Log.e("TAG", "MyBindService1:onCre");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e("TAG", "MyBindService1:onBind");
return myBinder1;
}
@Override
public boolean onUnbind(Intent intent) {
Log.e("TAG", "MyBindService1:onUnbind");
return super.onUnbind(intent);
}
@Override
public void unbindService(ServiceConnection conn) {
super.unbindService(conn);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e("TAG", "MyBindService1:onDestroy");
handler.removeCallbacksAndMessages(null);
}
interface Iterface {
void start();
void stop();
String open(String ss);
}
}
2.启动
先创建一个ServiceConnection对象,这个对象里面可以获取Binder对象,拿到他就可以操作服务里面的方法了,让服务去执行我们控制的命令
通过bindService(intent, myConnection, BIND_AUTO_CREATE);去启动服务,如下:
这样便绑定了服务,并在onServiceConnected()方法中持有服务的Binder代理对象从而实现了对服务中任务的控制。
结束服务:当启动此服务的宿主Activity销毁的时候,或者调用unbindService(myConnection),便可以结束改服务。
注意:
2.上面的只是实现了单向的通信,即是Activity-->Service发出指令。 要想实现交互的通信就需要借助Messenger,另外他还可以应用在跨进程中使用,同一个应用中的不同进程,或者不同的应用之间的进程都可以进行相互通信。
创建一个Service的主要步骤:
先创建handler对象并构造生成Messenge对象
然后在onBind()中去返回一个代理,和之前的代理不同,这个代理是从messenger中拿到的
然后看如何启动它
首先创建ServiceConnection对象,然后通过IBinder对象去获取服务中的Messenger对象
bindService(intent, myConnection, BIND_AUTO_CREATE) 绑定该服务
Activity中调用服务的方法:创建一个message消息,然后通过获取到的Service中的Messenge对象将其发送给服务,Messenger.send(msg)
此时服务中的Messenger中的handler会收到刚才Activity中发送来的消息,就可以根据参数或者标识进行处理实现了Activity-->Service的通信。
那如何让Service对Activity进行通信呢?我们可以猜想一下:如果Activity也有一个Messenge对象,并且让Service去持有它那么不是一样可以通过Messende.send(msg)给Activity发送消息实现通讯么?
首先,Activity中创建handler对象,并且用它去构造一个Messenge对象,如下:
然后,将上面的cMessenger对象放到msg消息包中,这样发送给Service服务的Message中就包含有Activity的Messenge对象了,如下:
最后在Service中接到消息后,取出Activity中的Messenge,此时便持有Activity中的cMessenge对象了,便也可以给Activity发送消息了,如下:
到此BindService也整理完了
三.下面再聊聊AIDL远程服务的调用,直观点说,就是我们通过aidl文件去绑定一个远程的服务,成功之后我们可以得到一个代理对象 IMyAidlInterface,然后通过这个对象去调用远程服务的方法,处理任务。
服务端
1.首先在服务端创建一个aidl文件:
2.然后编译一下:
3.在服务端创建Service,实现aidl的接口,如下:
客户端
1.我们将aidl文件复制过来放到客户端,包名要一样,如下:
2.最后创建ServiceConnection对象并绑定该服务,绑定成功的时候会获取IMyAidlInterface对象,便可以远程操作服务端的方法了。
3.调用如下:
对于一些大的APP 有些操作需要AIDL调用服务的 登录,校验之类的可能会用到。
到这里也就基本结束了,比较肤浅,但是了解一点 在读一些大型的项目的时候可能会遇到。哈哈