开发Android已经有一段时间了,反过来再看四大组件的时候又有不一样的理解,以前只是知道书本上的理论知识,当真正结合实战,你会对之认识更为深刻,当走到这里的时候,我是不是也在进阶高级程序猿了^_^!
照样上一张面试跟书本上经常出现的一张Service生命周期的图片。
如果我问Service的启动方式有哪些,想必大家都能很快的回答出来:
1、startService();
2、bindService();
我们接下来测试一下这两种方式,首先我们创建一个Service,叫MyService,然后创建一个布局,里面摆两个按钮,一个叫startService,一个叫stopService,我们对照着上面那种图,看看log是不是一致的。
测试的activity_main:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="startService"
android:onClick="startService"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="stopService"
android:onClick="stopService"
/>
</LinearLayout>
测试的MyService:
/**
* @author EX_YINQINGYANG
* @version [Android PABank C01, @2016-09-23]
* @date 2016-09-23
* @description
*/
public class MyService extends Service {
private static final String TAG ="MyService" ;
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate: ");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand: ");
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind: ");
return null;
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "onUnbind: ");
return super.onUnbind(intent);
}
@Override
public void onRebind(Intent intent) {
Log.e(TAG, "onRebind: ");
super.onRebind(intent);
}
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy: ");
super.onDestroy();
}
}
测试的MainActivity:
public void startService(View view){
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);
}
public void stopService(View view){
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);
}
最后一定记得要去ManiFest文件中配置Service:
<service android:name=".MyService"></service>
一、startService();
我们运行代码,然后点击“startService”按钮,看看log打印的情况:
09-23 13:23:03.340 13355-13355/com.example.servicedemo E/MyService: onCreate:
09-23 13:23:03.344 13355-13355/com.example.servicedemo E/MyService: onStartCommand:
Service第一次运行的时候会执行:onCreate—->onStartCommand
我们再次点击“startService”按钮:
09-23 13:23:03.340 13355-13355/com.example.servicedemo E/MyService: onCreate:
09-23 13:23:03.344 13355-13355/com.example.servicedemo E/MyService: onStartCommand:
09-23 13:24:27.611 13355-13355/com.example.servicedemo E/MyService: onStartCommand:
我们发现再次启动Service的时候不会再去执行onCreate了,而是再次调用了onStartCommand方法。
结论:
由于onCreate()方法只会在Service第一次被创建的时候调用,如果当前Service已经被创建过了,不管怎样调用startService()方法,onCreate()方法都不会再执行。因此你可以再多点击几次Start Service按钮试一次,每次都只会有onStartCommand()方法中的打印日志。
然后我们看看手机运行状态,可以看到我们的ServiceDemo中有一个服务跑在了手机后台了:
我们看到服务是启动了,然后我们关闭服务点击“stopService”按钮:
13:33:15.048 22150-22150/com.example.servicedemo E/MyService: onCreate:
09-23 13:33:15.056 22150-22150/com.example.servicedemo E/MyService: onStartCommand:
09-23 13:33:16.768 22150-22150/com.example.servicedemo E/MyService: onStartCommand:
09-23 13:33:17.688 22150-22150/com.example.servicedemo E/MyService: onDestroy:
我们上手机管理器看看我们的Service有没有干掉:
可以看到我们的服务已经被干掉了。
前面我们Service是启动了,但是我是在Activity中启动的,怎么才能发送指令让Service工作起来呢?这就牵扯到Activity与Service通信了,我们面试会被经常问到跨进程通信有哪些方式。
这里简单介绍下Android中跨进程通信方式,面试的时候经常考。
方式一:访问其他应用程序的Activity,也就是startActivity
方式二:广播
方式三:AIDL
方式四:contentProvide
观察MyService中的代码,你会发现一直有一个onBind()方法我们都没有使用到,这个方法其实就是用于和Activity建立关联的,修改MyService中的代码,如下所示:
**
* @author EX_YINQINGYANG
* @version [Android PABank C01, @2016-09-23]
* @date 2016-09-23
* @description
*/
public class MyService extends Service {
private static final String TAG ="MyService" ;
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate: ");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand: ");
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind: ");
return new MyBinder();
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "onUnbind: ");
return super.onUnbind(intent);
}
@Override
public void onRebind(Intent intent) {
Log.e(TAG, "onRebind: ");
super.onRebind(intent);
}
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy: ");
super.onDestroy();
}
class MyBinder extends Binder {
public void startDownload() {
Log.e(TAG, "startDownload() executed");
Toast.makeText(MyService.this, "startDownload", Toast.LENGTH_SHORT).show();
}
}
}
MainActivity中代码:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private ServiceConnection conn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void startService(View view){
Log.e(TAG, "startService click:" );
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);
}
public void stopService(View view){
Log.e(TAG, "stopService click:" );
Intent startIntent = new Intent(this, MyService.class);
stopService(startIntent);
}
public void bindService(View view){
Log.e(TAG, "bindService click:" );
Intent startIntent = new Intent(this, MyService.class);
bindService(startIntent, conn=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG, "onServiceConnected---->startDownload" );
((MyService.MyBinder)service).startDownload();
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG, "onServiceDisconnected:" );
}
}, Context.BIND_AUTO_CREATE);
}
public void unBindService(View view){
Log.e(TAG, "unBindService click:" );
Intent startIntent = new Intent(this, MyService.class);
unbindService(conn);
}
}
我们运行代码然后点击“bindService”按钮:
09-23 14:12:48.454 23506-23506/com.example.servicedemo E/MainActivity: bindService click:
09-23 14:12:48.474 23506-23506/com.example.servicedemo E/MyService: onCreate:
09-23 14:12:48.474 23506-23506/com.example.servicedemo E/MyService: onBind:
09-23 14:12:48.478 23506-23506/com.example.servicedemo E/MainActivity: onServiceConnected---->startDownload
09-23 14:12:48.478 23506-23506/com.example.servicedemo E/MyService: startDownload() executed
service中log打印了,Toast也提示了,也就是说我们通信成功了。
然后点击“onBindService”按钮:
09-23 14:13:46.501 23506-23506/com.example.servicedemo E/MainActivity: unBindService click:
09-23 14:13:46.505 23506-23506/com.example.servicedemo E/MyService: onUnbind:
09-23 14:13:46.505 23506-23506/com.example.servicedemo E/MyService: onDestroy:
我们先看一张Service生命周期图:
当Serivce正在运行,然后调用了bindService方法如果onUnbind返回了true就不会再走onBind了而是走的onRebind,下面我们来验证一下
我看到MyService中有这么一个方法,并且onBindService的时候也有调用了:
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "onUnbind: ");
return super.onUnbind(intent);
}
我们返回一个true,然后点击bindService—->unBindServce—->bindService(再启动Service)看看log打印:
09-23 15:06:10.500 26999-26999/com.example.servicedemo E/MainActivity: bindService click:
09-23 15:06:10.512 26999-26999/com.example.servicedemo E/MyService: onCreate:
09-23 15:06:10.512 26999-26999/com.example.servicedemo E/MyService: onBind:
09-23 15:06:10.520 26999-26999/com.example.servicedemo E/MainActivity: onServiceConnected---->startDownload
09-23 15:06:10.520 26999-26999/com.example.servicedemo E/MyService: startDownload() executed
09-23 15:06:11.968 26999-26999/com.example.servicedemo E/MainActivity: unBindService click:
09-23 15:06:11.968 26999-26999/com.example.servicedemo E/MyService: onUnbind:
09-23 15:06:11.968 26999-26999/com.example.servicedemo E/MyService: onDestroy:
09-23 15:06:12.904 26999-26999/com.example.servicedemo E/MainActivity: bindService click:
09-23 15:06:12.932 26999-26999/com.example.servicedemo E/MyService: onCreate:
09-23 15:06:12.936 26999-26999/com.example.servicedemo E/MyService: onBind:
09-23 15:06:12.948 26999-26999/com.example.servicedemo E/MainActivity: onServiceConnected---->startDownload
09-23 15:06:12.948 26999-26999/com.example.servicedemo E/MyService: startDownload() executed
我们发现,onRebind并没有执行,我们看看onRebind源码:
/**
* Called when new clients have connected to the service, after it had
* previously been notified that all had disconnected in its
* {@link #onUnbind}. This will only be called if the implementation
* of {@link #onUnbind} was overridden to return true.
*
* @param intent The Intent that was used to bind to this service,
* as given to {@link android.content.Context#bindService
* Context.bindService}. Note that any extras that were included with
* the Intent at that point will <em>not</em> be seen here.
*/
public void onRebind(Intent intent) {
}
注释有点多,大概就跟我们上面那张图解释是一样的,那么为什么onRebind不会执行呢?我们继续点击onBind:
09-23 15:11:40.396 26999-26999/com.example.servicedemo E/MainActivity: bindService click:
我们发现,什么都不执行了,这是为什么呢????? 为此我也困惑了很久很久。
首先我们看到上面那张图上写的Service Running的时候当有clients调用bindService时会判断unBind返回的是true还是false,如果是true就执行onRebind,false就执行onBind,这里说的Service is Running是调用了startService方法后才叫Running
我们再次测试 startService——->bindService—->unBindService—->bindService:
09-23 16:08:00.984 11664-11664/com.example.servicedemo E/MainActivity: startService click:
09-23 16:08:01.020 11664-11664/com.example.servicedemo E/MyService: onCreate:
09-23 16:08:01.032 11664-11664/com.example.servicedemo E/MyService: onStartCommand:
09-23 16:08:03.200 11664-11664/com.example.servicedemo E/MainActivity: bindService click:
09-23 16:08:03.204 11664-11664/com.example.servicedemo E/MyService: onBind:
09-23 16:08:03.212 11664-11664/com.example.servicedemo E/MainActivity: onServiceConnected---->startDownload
09-23 16:08:03.212 11664-11664/com.example.servicedemo E/MyService: startDownload() executed
09-23 16:08:05.156 11664-11664/com.example.servicedemo E/MainActivity: unBindService click:
09-23 16:08:05.164 11664-11664/com.example.servicedemo E/MyService: onUnbind:
09-23 16:08:06.308 11664-11664/com.example.servicedemo E/MainActivity: bindService click:
09-23 16:08:06.316 11664-11664/com.example.servicedemo E/MainActivity: onServiceConnected---->startDownload
09-23 16:08:06.316 11664-11664/com.example.servicedemo E/MyService: startDownload() executed
09-23 16:08:06.320 11664-11664/com.example.servicedemo E/MyService: onRebind:
看到这里的时候,是不是觉得以前对Service的理解还是太过肤浅了^_^~!
1. 首先要知道,同一个服务既可能被启动也可以被绑定;
Service中onRebind方法被调用,只要符合两个必要条件就行
(1)服务中onUnBind方法返回值为true
(2)服务对象被解绑后没有被销毁,之后再次被绑定
。下面举例说明:
例1:同一个Activity对象
先自启动服务(onCreate, onStartCommand);再绑定服务(onBind); 再解除绑定服务(onUnBind)(由于服务被启动过,所以Service中onDestroy不会被调用);再绑定服务, 这次绑定的服务对象是之前已经创建好的,所以这次绑定服务时就会调用onReBind方法了,并且本次不会调用onBind方法。
例2:不是同一个Activity对象
打开项目,启动MainActivity, 在Activity中启动服务(onCreate, onStartCommand),再绑定服务(onBind); 再解除绑定服务(onUnBind); 再接返回键销毁MainActivity对象(onUnBind);再打开项目启动MainActivity;再绑定服务,这次绑定服务时会调用onReBind方法
我们再来测试一下startService—->bindService—->stopService—>unBindService:
09-23 16:14:42.252 11664-11664/com.example.servicedemo E/MainActivity: startService click:
09-23 16:14:42.256 11664-11664/com.example.servicedemo E/MyService: onStartCommand:
09-23 16:15:13.704 11664-11664/com.example.servicedemo E/MainActivity: bindService click:
09-23 16:15:15.796 11664-11664/com.example.servicedemo E/MainActivity: stopService click:
09-23 16:15:23.420 11664-11664/com.example.servicedemo E/MainActivity: unBindService click:
09-23 16:15:23.432 11664-11664/com.example.servicedemo E/MyService: onUnbind:
09-23 16:15:23.432 11664-11664/com.example.servicedemo E/MyService: onDestroy:
当bindService了,如果还没有执行unBindService去执行stopService,Service不会销毁
最后一定要记住,我们应该始终记得在Service的onDestroy()方法里去清理掉那些不再使用的资源,防止在Service被销毁后还会有一些不再使用的对象仍占用着内存。
本文内容部分参考郭神博客http://blog.csdn.net/guolin_blog/article/details/11952435