一.关于Service的启动模式对比
1.startService方式
首先先来个总结性图片:
接下来我们开始根据日志进行分析:
(1)新建一个类(TestStartService)继承Service,并在Manifest文件中进行注册
public class TestStartService extends Service {
private static final String TAG = "TestStartService";
@Override
public void onCreate() {
Log.e(TAG,"<onCreate>Thread Id="+Thread.currentThread().getId());
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG,"<onStartCommand>Thread Id="+Thread.currentThread().getId()+",startId="+startId);
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG,"<onBind>Thread Id="+Thread.currentThread().getId());
return null;
}
@Override
public void onDestroy() {
Log.e(TAG,"<onDestroy> Thread Id="+Thread.currentThread().getId());
super.onDestroy();
}
}
(2)在Activity中,
a.进行3次启动操作,调用startService
b.执行1次停止操作,调用stopService()
c.再次启动,调用Service
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.e(TAG, "主线程id=" + Thread.currentThread().getId());
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//3次启动
Intent intent1 = new Intent(this, TestStartService.class);
startService(intent1);
Intent intent2 = new Intent(this, TestStartService.class);
startService(intent2);
Intent intent3 = new Intent(this, TestStartService.class);
startService(intent3);
//停止
Intent intent4 = new Intent(this, TestStartService.class);
stopService(intent4);
//再启动
Intent intent5 = new Intent(this, TestStartService.class);
startService(intent5);
}
}
执行结果Log信息如下:
E/TestStartService: <onCreate>Thread Id=2
E/TestStartService: <onStartCommand>Thread Id=2,startId=1
E/TestStartService: <onStartCommand>Thread Id=2,startId=2
E/TestStartService: <onStartCommand>Thread Id=2,startId=3
E/TestStartService: <onDestroy> Thread Id=2
E/TestStartService: <onCreate>Thread Id=2
E/TestStartService: <onStartCommand>Thread Id=2,startId=1
进行分析:我们进行了3次启动service方法,却只执行了1次onCreate方法,执行了3次onStartCommand;当进行stopService,会执行Service中的onDestory();再次启动service,执行了
onCreate和onStartCommand方法;打印出的threadId一直是2。
得出结论:①onCreate()只有第一次startService会执行,而后执行多少次startService都会执行多少次onStartCommand()②只有执行stopService,service才会被停止(仅对于此案例),证明service生命周期不是随组件而变化③一直运行在主线程中,故不要在service做过多耗时任务
2.bindService方式
再来一个总结性的图片
(1)和上面的方式一样,新建个类(TestBindService)继承Service
public class TestBindService extends Service {
private static final String TAG = "TestBindService";
//用于client中建立和service的连接,可以获取到service中方法
public class MyBinder extends Binder{
public TestBindService getService(){
return TestBindService.this;
}
}
private MyBinder myBinder=new MyBinder();
private final Random generator = new Random();
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "<onCreate> name=" + Thread.currentThread().getName());
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "<onStartCommand> name=" + Thread.currentThread().getName());
return START_NOT_STICKY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "<onBind> name=" + Thread.currentThread().getName());
return myBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "<onUnbind> from=" + intent.getStringExtra("from"));
return false;
}
@Override
public void onDestroy() {
Log.e(TAG, "<onDestroy> name=" + Thread.currentThread().getName());
super.onDestroy();
}
//getRandomNumber是Service暴露出去供client调用的公共方法
public int getRandomNumber() {
return generator.nextInt();
}
}
(2)新建一个Activity(ActivityA)
(3)布局中只是放入了线性排列的4个button
(4)由于此案例我们想要调用bindService方式启动,会发现需要需要3个参数:(android.content.Intent service, android.content.ServiceConnection conn, int flags) ,所以我们new一个ServiceConnection ,其中有两个方法:onServiceConnected()和onServiceDisconnected(),分别是service绑定成功和取消绑定执行的,附上这个类代码
public class ActivityA extends Activity implements View.OnClickListener {
private static final String TAG = "ActivityA";
private TestBindService bindService;
private boolean isBind = false;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_a);
findViewById(R.id.btnBindService).setOnClickListener(this);
findViewById(R.id.btnUnbindService).setOnClickListener(this);
findViewById(R.id.btnStartActivityB).setOnClickListener(this);
findViewById(R.id.btnFinish).setOnClickListener(this);
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e(TAG, "onServiceConnected");
isBind = true;
TestBindService.MyBinder myBinder = (TestBindService.MyBinder) iBinder;
bindService = myBinder.getService();
//证明可以再activity中调到service中方法:
int num = bindService.getRandomNumber();
Log.e(TAG, num + "");
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.e(TAG, "onServiceDisconnected");
isBind = false;
}
};
@Override
public void onClick(View v) {
Intent intent;
switch (v.getId()) {
case R.id.btnBindService:
Log.e(TAG,"ActivityA 点击 bindService");
intent = new Intent(ActivityA.this, TestBindService.class);
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
//flag值:控制需要绑定的Service的行为和运行模式
break;
case R.id.btnUnbindService:
if(isBind){
Log.e(TAG,"ActivityA 点击 unbindService");
unbindService(serviceConnection);
}
break;
case R.id.btnStartActivityB:
Log.e(TAG,"ActivityA 点击启动 ActivityB");
intent=new Intent(ActivityA.this,ActivityB.class);
startActivity(intent);
break;
case R.id.btnFinish:
Log.e(TAG,"ActivityA 点击执行 finish");
finish();
break;
}
}
@Override
protected void onDestroy() {
Log.e(TAG,"ActivityA onDestroy");
super.onDestroy();
}
}
(5)ActivityB布局和代码基本同ActivityA,只缺少一个跳转
public class ActivityB extends Activity implements Button.OnClickListener {
private static final String TAG = "ActivityB";
private TestBindService bindService;
private boolean isBind = false;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e(TAG, "onServiceConnected");
isBind = true;
TestBindService.MyBinder myBinder = (TestBindService.MyBinder) iBinder;
bindService = myBinder.getService();
//证明可以再activity中调到service中方法:
int num = bindService.getRandomNumber();
Log.e(TAG, num + "");
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.e(TAG, "onServiceDisconnected");
isBind = false;
}
};
@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) {
Intent intent;
switch (v.getId()) {
case R.id.btnBindService:
Log.e(TAG, "ActivityB 点击 bindService");
intent = new Intent(ActivityB.this, TestBindService.class);
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
//flag值:控制需要绑定的Service的行为和运行模式
break;
case R.id.btnUnbindService:
if (isBind) {
Log.e(TAG, "ActivityB 点击 unbindService");
unbindService(serviceConnection);
}
break;
case R.id.btnFinish:
Log.e(TAG, "ActivityB 点击执行 finish");
finish();
break;
}
}
@Override
protected void onDestroy() {
Log.e(TAG, "ActivityB onDestroy");
super.onDestroy();
}
}
下面开始按步骤总体分析:
a.ActivityA首次调用bindService:会回调Service的onCreate()、onBind(),ActivityA的ServiceConnection中的onServiceConnected()。因为这是service首次运行
b.ActivityA再次调用bindService:什么都不会执行。因为此时已经运行了
c.ActivityA执行unbindService:会执行onUnbind()和onDestroy()。Service检测是否还有其他client与其连接,如果没有Service执行onUnbind()和onDestroy()
d.ActivityA调用bindService后调用finish:会执行onUnbind()和onDestroy()。如果client销毁,那么client会自动与Service解除绑定。
e.销毁APP。重新进入ActivityA首次调用A的bindService,然后跳转到ActivityB,然后执行B的bindService:ActivityA的bindService执行onCreate()、onBind(),B的bindService只会执行onServiceConnected。原因在于此时Service已经运行起来了
f.ActivityB执行unbind():什么都不会执行。因为当前一共有client和service建立了连接,都finish或都解绑了才会回调
g.ActivityA执行unbind():会执行onUnbind()和onDestroy()。Service检测是否还有其他client与其连接,如果没有Service执行onUnbind()和onDestroy()
得出结论:①通过bindService方式建立的是client-service之间的一对多的关系,即一个service对应多个Acivitiy。只有对应的client都销毁或者调用了unbind(),service才会回调onUnbind()和onDestroy();②service生命周期受宿主client影响;③service依然运行在主线程中④不会回调onStartCommand()方法
二.关于onStartCommend的返回值
start_sticky、start_no_sticky、START_REDELIVER_INTENT、START_STICKY_COMPATIBILITY。
START_STICKY: 如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由 于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传 递到service,那么参数Intent将为null;
START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务;
START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入;
START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。
三.几个小练习问题
1.Service 的 start 和 bind 状态有什么区别?
eg:start方式,生命周期不受组件的影响,有独立的生命周期。多次startService(),只有第一次会执行onCreate(),多次调用onStartCommand()。
bind方式,生命周期会受组件的影响。一个service可以被多个组件绑定。oncreate和onbind只有第一次创建会被调用。全部组件都执行了onUnbindService,才会回调onUnbind方法。
2.同一个 Service,先 startService,然后再 bindService,如何把它停止掉?
eg:执行1次stopService和多次unbindService(每个绑定的Activity需执行一次)。这两个过程没有顺序
3.Service 的生命周期方法 onCreate、onStart、onBind 等运行在哪个线程?
eg:主线程。所以不能做过多的耗时任务,否则会ANR,可以使用广播或IntentService
简单描述IntentService:①它继承于Service,用于处理异步请求的类。因为它内部有一个HandlerThread处理耗时线程,而且会在执行完成后,自动调用结束方法,不需要stopService();②内部通过消息的方式发送给HandlerThread的,然后又Handler中的Looper来分发处理消息。是采用队列的形式,消息全部处理完毕后会自动调用销毁操作③优先级高不容易被杀死
三.Activity与Service之间如何传值?
//2018-12-20
1.利用ServiceConnection(bindService方式)
service(注意不要忘了在manifest中注册):
public class MyService extends Service {
private static final String TAG = "MyService";
private MyBinder myBinder = new MyBinder();
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return myBinder;
}
class MyBinder extends Binder {
public void setData(String value) {
Log.e(TAG, value);
}
}
}
Activity中:
public class MainActivity extends AppCompatActivity {
private MyService.MyBinder myBinder;
private ServiceConnection myServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (MyService.MyBinder) service;
myBinder.setData("方式1发送");
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, MyService.class);
bindService(intent, myServiceConnection, BIND_AUTO_CREATE);
}
}
2.利用Intent传值(startService方式)
service(注意不要忘了在manifest中注册):
public class MyService2 extends Service {
private static final String TAG = "MyService2";
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String value = intent.getStringExtra("key");
Log.e(TAG, value);
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
Activity中:
public class IntentWayActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intent_way);
findViewById(R.id.btStart).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(IntentWayActivity.this, MyService2.class);
intent.putExtra("key", "方式2");
startService(intent);
}
});
}
}
3.callback回调方式,感觉略微繁琐
更多IntentService可以参考https://www.jianshu.com/p/8a3c44a9173a
四.新增IntentService
//2019.01.15
IntentService 继承Service,故作用同Service
IntentService 的onCreate()中包含了HandlerThread
特点
:
1.按顺序执行发送的service
2.所有的service执行完成后会自动销毁,不需要调用stop
3.只能用startService()方式,不能用bindService(),因为只有startService()会回调onStartCommand(),通过onStartCommand()传递的Intent,并将此传递给onHandleIntent(),在这里面根据不同传值处理逻辑
4.继承Service,写构造方法时,需要super(name),这个name是我们自定义的,为什么这里需要个name呢?因为IntentService包含了HandlerThread,HandlerThread的初始化需要传入一个name,用于标识线程,所以这个name是给HandlerThread
使用步骤
:
1.新建继承IntentService,重写各个方法
2.注册到Manifest文件中
3.在需要发送地方,使用startService()方式发送
完整代码
:
public class MyIntentService extends IntentService{
private static final String TAG = "MyIntentService";
public MyIntentService() {
//由于IntentService内部含有HandlerThread,
//HandlerThread初始化要传个名字用来标识线程
super("danny");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
int type=intent.getIntExtra("type",0);
switch (type){
case 1:
Log.e(TAG,"this is type1");
break;
case 2:
Log.e(TAG,"this is type2");
break;
}
}
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG,"onCreate");
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.e(TAG,"onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.e(TAG,"onDestroy");
super.onDestroy();
}
}
public class IntentServiceActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intent_service);
Intent intent = new Intent(this, MyIntentService.class);
intent.putExtra("type", 1);
startService(intent);
Intent intent2 = new Intent(this, MyIntentService.class);
intent2.putExtra("type", 2);
startService(intent2);
}
}
此项目中案例讲的非常好,强烈建议跟随例子自己敲一遍,会有更多发现,本文案例出自于此https://www.jianshu.com/p/4c798c91a613