Android进阶之(Service详解一)

开发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. 首先要知道,同一个服务既可能被启动也可以被绑定;

  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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值