转载:https://www.jianshu.com/p/4c798c91a613
第一种方式:通过StartService启动Service
通过startService启动后,service会一直无限期运行下去,只有外部调用了stopService()或stopSelf()方法时,该Service才会停止运行并销毁。
第二种方式:通过bindService启动Service
1.bindService启动的服务和调用者之间是典型的client-server模式。调用者是client,service则是server端。service只有一个,但绑定到service上面的client可以有一个或很多个。这里所提到的client指的是组件,比如某个Activity。
2.client可以通过IBinder接口获取Service实例,从而实现在client端直接调用Service中的方法以实现灵活交互,这在通过startService方法启动中是无法实现的。
3.bindService启动服务的生命周期与其绑定的client息息相关。当client销毁时,client会自动与Service解除绑定。当然,client也可以明确调用Context的unbindService()方法与Service解除绑定。当没有任何client与Service绑定时,Service会自行销毁。
例子
startService启动
创建步骤:
要创建一个这样的Service,你需要让该类继承Service类,然后重写以下方法:
onCreate()
1.如果service没被创建过,调用startService()后会执行onCreate()回调;
2.如果service已处于运行中,调用startService()不会执行onCreate()方法。
也就是说,onCreate()只会在第一次创建service时候调用,多次执行startService()不会重复调用onCreate(),此方法适合完成一些初始化工作。
onStartCommand()
如果多次执行了Context的startService()方法,那么Service的onStartCommand()方法也会相应的多次调用。onStartCommand()方法很重要,我们在该方法中根据传入的Intent参数进行实际的操作,比如会在此处创建一个线程用于下载数据或播放音乐等。
onBind()
Service中的onBind()方法是抽象方法,Service类本身就是抽象类,所以onBind()方法是必须重写的,即使我们用不到。
onDestory()
在销毁的时候会执行Service该方法。
创建TestOneService,并在manifest里注册。
在MainActivty中操作TestOneService,code如下:
/**
* Created by Kathy on 17-2-6.
*/
public class TestOneService extends Service{
@Override
public void onCreate() {
Log.i("Kathy","onCreate - Thread ID = " + Thread.currentThread().getId());
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("Kathy", "onStartCommand - startId = " + startId + ", Thread ID = " + Thread.currentThread().getId());
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i("Kathy", "onBind - Thread ID = " + Thread.currentThread().getId());
return null;
}
@Override
public void onDestroy() {
Log.i("Kathy", "onDestroy - Thread ID = " + Thread.currentThread().getId());
super.onDestroy();
}
}
在MainActivity中三次startService,之后stopService
/**
* Created by Kathy on 17-2-6.
*/
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("Kathy", "Thread ID = " + Thread.currentThread().getId());
Log.i("Kathy", "before StartService");
//连续启动Service
Intent intentOne = new Intent(this, TestOneService.class);
startService(intentOne);
Intent intentTwo = new Intent(this, TestOneService.class);
startService(intentTwo);
Intent intentThree = new Intent(this, TestOneService.class);
startService(intentThree);
//停止Service
Intent intentFour = new Intent(this, TestOneService.class);
stopService(intentFour);
//再次启动Service
Intent intentFive = new Intent(this, TestOneService.class);
startService(intentFive);
Log.i("Kathy", "after StartService");
}
}
打印出的Log如下:
02-06 15:19:45.090 8938-8938/? I/Kathy: Thread ID = 1
02-06 15:19:45.090 8938-8938/? I/Kathy: before StartService
02-06 15:19:45.233 8938-8938/? I/Kathy: onCreate - Thread ID = 1
02-06 15:19:45.234 8938-8938/? I/Kathy: onStartCommand - startId = 1, Thread ID = 1
02-06 15:19:45.234 8938-8938/? I/Kathy: onStartCommand - startId = 2, Thread ID = 1
02-06 15:19:45.235 8938-8938/? I/Kathy: onStartCommand - startId = 3, Thread ID = 1
02-06 15:19:45.236 8938-8938/? I/Kathy: onDestroy - Thread ID = 1
02-06 15:19:45.237 8938-8938/? I/Kathy: onCreate - Thread ID = 1
02-06 15:19:45.237 8938-8938/? I/Kathy: onStartCommand - startId = 1, Thread ID = 1
02-06 15:19:45.238 8938-8938/? I/Kathy: after StartService
分析:
1.主线程打印出是1,所有回调方法中打印出的执行线程ID都是1,证明回调方法都是在主线程中执行的。
2.三次调用startService,只触发一次onCreate回调,触发了三次onStartCommand回调,且startId分别为1,2,3。证明 多次startService不会重复执行onCreate回调,但每次都会执行onStartCommand回调。
bindService启动
A B
1.创建一个TestTwoService继承Service(Server)
2.创建ActivityA,可以通过bindService绑定服务(client)
3.创建ActivityB,可以通过bindService绑定服务(client)
4.ActivityA可以跳转到ActivityB
TestTwoService创建如下:
要想让Service支持bindService调用方式,需要做以下事情:
1.在Service的onBind()方法中返回IBinder类型的实例。
2.onBInd()方法返回的IBinder的实例需要能够返回Service实例本身。通常,最简单的方法就是在service中创建binder的内部类,加入类似getService()的方法返回Service,这样绑定的client就可以通过getService()方法获得Service实例了。
/**
* Created by Kathy on 17-2-6.
*/
public class TestTwoService extends Service{
//client 可以通过Binder获取Service实例
public class MyBinder extends Binder {
public TestTwoService getService() {
return TestTwoService.this;
}
}
//通过binder实现调用者client与Service之间的通信
private MyBinder binder = new MyBinder();
private final Random generator = new Random();
@Override
public void onCreate() {
Log.i("Kathy","TestTwoService - onCreate - Thread = " + Thread.currentThread().getName());
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("Kathy", "TestTwoService - onStartCommand - startId = " + startId + ", Thread = " + Thread.currentThread().getName());
return START_NOT_STICKY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i("Kathy", "TestTwoService - onBind - Thread = " + Thread.currentThread().getName());
return binder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.i("Kathy", "TestTwoService - onUnbind - from = " + intent.getStringExtra("from"));
return false;
}
@Override
public void onDestroy() {
Log.i("Kathy", "TestTwoService - onDestroy - Thread = " + Thread.currentThread().getName());
super.onDestroy();
}
//getRandomNumber是Service暴露出去供client调用的公共方法
public int getRandomNumber() {
return generator.nextInt();
}
}
client端要做的事情:
1.创建ServiceConnection类型实例,并重写onServiceConnected()方法和onServiceDisconnected()方法。
2.当执行到onServiceConnected回调时,可通过IBinder实例得到Service实例对象,这样可实现client与Service的连接。
3.onServiceDisconnected回调被执行时,表示client与Service断开连接,在此可以写一些断开连接后需要做的处理。
创建ActivityA,代码如下:
/**
* Created by Kathy on 17-2-6.
*/
public class ActivityA extends Activity implements Button.OnClickListener {
private TestTwoService service = null;
private boolean isBind = false;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
isBind = true;
TestTwoService.MyBinder myBinder = (TestTwoService.MyBinder) binder;
service = myBinder.getService();
Log.i("Kathy", "ActivityA - onServiceConnected");
int num = service.getRandomNumber();
Log.i("Kathy", "ActivityA - getRandomNumber = " + num);
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBind = false;
Log.i("Kathy", "ActivityA - onServiceDisconnected");
}
};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_a);
Log.i("Kathy", "ActivityA - onCreate - Thread = " + Thread.currentThread().getName());
findViewById(R.id.btnBindService).setOnClickListener(this);
findViewById(R.id.btnUnbindService).setOnClickListener(this);
findViewById(R.id.btnStartActivityB).setOnClickListener(this);
findViewById(R.id.btnFinish).setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btnBindService) {
//单击了“bindService”按钮
Intent intent = new Intent(this, TestTwoService.class);
intent.putExtra("from", "ActivityA");
Log.i("Kathy", "----------------------------------------------------------------------");
Log.i("Kathy", "ActivityA 执行 bindService");
bindService(intent, conn, BIND_AUTO_CREATE);
} else if (v.getId() == R.id.btnUnbindService) {
//单击了“unbindService”按钮
if (isBind) {
Log.i("Kathy",
"----------------------------------------------------------------------");
Log.i("Kathy", "ActivityA 执行 unbindService");
unbindService(conn);
}
} else if (v.getId() == R.id.btnStartActivityB) {
//单击了“start ActivityB”按钮
Intent intent = new Intent(this, ActivityB.class);
Log.i("Kathy",
"----------------------------------------------------------------------");
Log.i("Kathy", "ActivityA 启动 ActivityB");
startActivity(intent);
} else if (v.getId() == R.id.btnFinish) {
//单击了“Finish”按钮
Log.i("Kathy",
"----------------------------------------------------------------------");
Log.i("Kathy", "ActivityA 执行 finish");
this.finish();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i("Kathy", "ActivityA - onDestroy");
}
}
创建ActivityB,代码如下:
/**
* Created by Kathy on 17-2-6.
*/
public class ActivityB extends Activity implements Button.OnClickListener {
private TestTwoService service = null;
private boolean isBind = false;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
isBind = true;
TestTwoService.MyBinder myBinder = (TestTwoService.MyBinder)binder;
service = myBinder.getService();
Log.i("Kathy", "ActivityB - onServiceConnected");
int num = service.getRandomNumber();
Log.i("Kathy", "ActivityB - getRandomNumber = " + num);
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBind = false;
Log.i("Kathy", "ActivityB - onServiceDisconnected");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
findViewById(R.id.btnBindService).setOnClickListener(this);
findViewById(R.id.btnUnbindService).setOnClickListener(this);
findViewById(R.id.btnFinish).setOnClickListener(this);
}
@Override
public void onClick(View v) {
if(v.getId() == R.id.btnBindService){
//单击了“bindService”按钮
Intent intent = new Intent(this, TestTwoService.class);
intent.putExtra("from", "ActivityB");
Log.i("Kathy", "----------------------------------------------------------------------");
Log.i("Kathy", "ActivityB 执行 bindService");
bindService(intent, conn, BIND_AUTO_CREATE);
}else if(v.getId() == R.id.btnUnbindService){
//单击了“unbindService”按钮
if(isBind){
Log.i("Kathy", "----------------------------------------------------------------------");
Log.i("Kathy", "ActivityB 执行 unbindService");
unbindService(conn);
}
}else if(v.getId() == R.id.btnFinish){
//单击了“Finish”按钮
Log.i("Kathy", "----------------------------------------------------------------------");
Log.i("Kathy", "ActivityB 执行 finish");
this.finish();
}
}
@Override
public void onDestroy(){
super.onDestroy();
Log.i("Kathy", "ActivityB - onDestroy");
}
}
测试步骤1
step1: 点击ActivityA的bindService按钮
step2: 再点击ActivityA的unbindService按钮
Log输出:
02-07 14:09:38.031 1738-1738/com.demo.kathy.demo I/Kathy: ActivityA - onCreate - Thread = main
02-07 14:09:39.488 1738-1738/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:09:39.488 1738-1738/com.demo.kathy.demo I/Kathy: ActivityA 执行 bindService
02-07 14:09:39.496 1738-1738/com.demo.kathy.demo I/Kathy: TestTwoService - onCreate - Thread = main
02-07 14:09:39.497 1738-1738/com.demo.kathy.demo I/Kathy: TestTwoService - onBind - Thread = main
02-07 14:09:39.500 1738-1738/com.demo.kathy.demo I/Kathy: ActivityA - onServiceConnected
02-07 14:09:39.500 1738-1738/com.demo.kathy.demo I/Kathy: ActivityA - getRandomNumber = -1046987376
02-07 14:09:50.866 1738-1738/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:09:50.866 1738-1738/com.demo.kathy.demo I/Kathy: ActivityA 执行 unbindService
02-07 14:09:50.870 1738-1738/com.demo.kathy.demo I/Kathy: TestTwoService - onUnbind - from = ActivityA
02-07 14:09:50.871 1738-1738/com.demo.kathy.demo I/Kathy: TestTwoService - onDestroy - Thread = main
总结调用bindService之后发生的事情:
1.client执行bindService()
2.如果Service不存在,则Service执行onCreate(),onBind()
3.client实例ServiceConnection执行onServiceConnected()方法
总结调用unbindService之后发生的事情:
1.client执行unbindService()
2.client与Service解除绑定连接状态
3.Service检测是否还有其他client与其连接,如果没有Service执行onUnbind()和onDestroy()
测试步骤2
step1: 点击ActivityA的bindService按钮
step2: 再点击ActivityA的Finish按钮
Log 输出:
02-07 14:49:16.626 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - onCreate - Thread = main
02-07 14:49:18.102 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:49:18.102 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA 执行 bindService
02-07 14:49:18.105 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onCreate - Thread = main
02-07 14:49:18.110 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onBind - Thread = main
02-07 14:49:18.112 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - onServiceConnected
02-07 14:49:18.112 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - getRandomNumber = -318399886
02-07 14:49:19.540 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:49:19.540 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA 执行 finish
02-07 14:49:19.789 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - onDestroy
02-07 14:49:19.798 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onUnbind - from = ActivityA
02-07 14:49:19.798 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onDestroy - Thread = main
总结:如果client销毁,那么client会自动与Service解除绑定。
测试步骤3
step1: 点击ActivityA的bindService按钮
step2: 点击ActivityA的startActivity B按钮,切换到ActivityB
step3: 点击ActivityB中的bindService按钮
step4: 点击ActivityB中的unbindService按钮
step5: 点击ActivityB中的Finish按钮
step6: 点击ActivityA中的unbindService按钮
得到Log:
02-07 14:55:04.390 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - onCreate - Thread = main
02-07 14:55:08.191 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:55:08.191 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA 执行 bindService
02-07 14:55:08.197 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onCreate - Thread = main
02-07 14:55:08.198 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onBind - Thread = main
02-07 14:55:08.205 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - onServiceConnected
02-07 14:55:08.205 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - getRandomNumber = -706215542
02-07 14:55:23.261 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:55:23.261 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA 启动 ActivityB
02-07 14:55:29.239 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:55:29.239 12566-12566/com.demo.kathy.demo I/Kathy: ActivityB 执行 bindService
02-07 14:55:29.241 12566-12566/com.demo.kathy.demo I/Kathy: ActivityB - onServiceConnected
02-07 14:55:29.241 12566-12566/com.demo.kathy.demo I/Kathy: ActivityB - getRandomNumber = 1827572726
02-07 14:55:33.951 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:55:33.951 12566-12566/com.demo.kathy.demo I/Kathy: ActivityB 执行 unbindService
02-07 14:55:36.645 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:55:36.645 12566-12566/com.demo.kathy.demo I/Kathy: ActivityB 执行 finish
02-07 14:55:36.852 12566-12566/com.demo.kathy.demo I/Kathy: ActivityB - onDestroy
02-07 14:55:43.137 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:55:43.137 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA 执行 unbindService
02-07 14:55:43.143 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onUnbind - from = ActivityA
02-07 14:55:43.143 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onDestroy - Thread = main
总结bindService的生命周期:
1.点击ActivityA的bindService按钮
第一次调用bindService会实例化TestTwoService,然后执行其onBind()方法,得到IBinder类型的实例,将其作为参数传入ActivityA的ServiceConnection的onServiceConnected方法中,标志着ActivityA与TestTwoService建立了绑定。
2.点击ActivityB中的bindService按钮
由于TestTwoService已处于运行状态,所以再次调用bindService不会重新创建它的实例,所以也不会执行TestTwoService的onCreate()方法和onBind()方法。ActivityB与ActivityA共享IBinder实例。此时有两个client与TestTwoService绑定。
3.点击ActivityB中的unbindService按钮
ActivityB与TestTwoService解除了绑定,当没有任何client与Service绑定时,才会执行Service的onUnbind()方法。此时,ActivityA还在绑定连接中,所以不会执行Service的解绑方法。
4.点击ActivityA中的unbindService按钮
ActivityA执行unbindService之后,ActivityA与TestTwoService就解除绑定了,这样就没有client与TestTwoService绑定,这时候Android会销毁TestTwoService,在销毁前会先执行TestTwoService的onUnbind()方法,然后才会执行其onDestroy()方法,这样TestService就销毁了。
如何保证Service不被杀死?
1. onStartCommand方法中,返回指定的枚举值
START_NOT_STICKY:表示当Service运行的进程被Android系统强制杀掉之后,不会重新创建该Service
START_STICKY:表示Service运行的进程被Android系统强制杀掉之后,系统会重新启动,但是没有保存上次运行时的任务
START_REDELIVER_INTENT:同START_STICKY,不同的是保存了上次运行的任务
2.提高Service的优先级
在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。
3.提升Service进程的优先级
当系统进程空间紧张时,会依照优先级自动进行进程的回收。
Android将进程分为6个等级,按照优先级由高到低依次为:
前台进程foreground_app
可视进程visible_app
次要服务进程secondary_server
后台进程hiddena_app
内容供应节点content_provider
空进程empty_app
可以使用startForeground将service放到前台状态,这样低内存时,被杀死的概率会低一些。
4.在onDestroy方法里重启Service
当service走到onDestroy()时,发送一个自定义广播,当收到广播时,重新启动service。
5.系统广播监听Service状态
6.将APK安装到/system/app,变身为系统级应用
作者:Big不吃鱼
链接:https://www.jianshu.com/p/4c798c91a613
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。