Android Service使用

Service是Android四大组件之一,与Activity的职责相反,Service一般在后台处理一些耗时任务,或者一直执行某个任务。

Service使用

新建一个计时Service。

public class TimerService extends Service {

    private static String TAG = TimerService.class.getName();
    private static final long LOOP_TIME = 1; //循环时间
    private static ScheduledExecutorService mExecutorService;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate");

        mExecutorService = Executors.newScheduledThreadPool(2);
        mExecutorService.scheduleAtFixedRate(mRunnable, LOOP_TIME, LOOP_TIME, TimeUnit.SECONDS);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind");
        return null;
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy");
        super.onDestroy();
        mExecutorService.shutdown();
        mExecutorService = null;
        mRunnable = null;
    }

    private int count = 0;
    private Runnable mRunnable = new Runnable() {
        @Override
        public void run() {
            count++;
            Log.d(TAG, "=== count:" + count);
        }
    };
}

四大组件都需要在manifest中注册

   <service android:name=".service.TimerService"/>   

声明Service的时候还有一些属性可以一起配置。需要的话

  <service android:name=".service.TimerService"
                 android:enabled="true"
                 android:exported="true"
                 android:icon="@mipmap/ic_launcher"
                 android:label="string"
                 android:process="string"
                 android:permission="string"
            >
            <!--设置service优先级,最大1000-->
            <intent-filter android:priority="100"/>
        </service>
  • android:enabled 是否允许除了当前程序之外的其他程序访问这个服务

  • android:exported 是否启用这个服务

  • android:process 是否需要在单独的进程中运行,当设置为android:process=”:remote”时,代表Service在单独的进程中运行。注意“:”很重要,它的意思是指要在当前进程名称前面附加上当前的包名,所以“remote”和”:remote”不是同一个意思,前者的进程名称为:remote,而后者的进程名称为:App-packageName:remote。

  • android:permission 权限声明

我们知道Service的使用方式有两种,我们分别使用不同的方式进行使用。

1、使用startService()方法启动服务

  Intent intent = new Intent(ServiceActivity.this, TimerService.class);
  //使用Intent传值
  intent.putExtra("key","value");
  startService(intent);

启动任务,查看控制台我们输出的Log

TimerService: onCreate
TimerService: onStartCommand
TimerService: === count:1
TimerService: === count:2
......

可以看见,Service被创建,并且计时任务在后台执行。

如果我们不小心多点了次启动按钮,会发生什么事呢?会有两个计时任务一起执行么?我们将APP卸载重新运行可以试着多点几次启动,查看控制台输出日志:

TimerService: onCreate
TimerService: onStartCommand
TimerService: === count:1
TimerService: onStartCommand
TimerService: onStartCommand
TimerService: onStartCommand
TimerService: === count:2
......

从日志上可以看见,我们连续点击启动按钮启动服务,服务并不会重新创建 ,而是执行onStartCommand方法,因为我们计时任务的初始化和启动都是放在onCreate方法中的,所以不会启动多个计时任务。

停止服务
服务一旦启动,除非我们手动关闭服务,否则服务会一直在后台运行,直到系统资源不足的时候,系统主动杀死服务。

使用stopService停止服务。

stopService(new Intent(ServiceActivity.this, TimerService.class));

控制台输出如下:

TimerService: onDestroy

所以使用startService方式启动服务的service生命周期为:

oncreate --> onStartCommand --> onDestroy

  • onCreate:服务创建的时候调用一次,如果已经创建了,则不会再调用。
  • onStartCommand : 当通过startService() 启动服务时,系统将调用此方法。一旦执行此方法,服务即会启动并可在后台无限期运行。
  • onDestroy:当服务不再使用且将被销毁时,系统将调用此方法。

多次启动服务会重复执行onStartCommand 方法。

2、使用bindService 绑定服务

bindService和startService的最大区别是,客户和服务绑定在一起了,客户可以通过binder获得Service实例,从而达到交互的目的。

bindService()方法有三个参数。Intent,ServiceConnection,flags

创建Intent和ServiceConnection

 private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder iBinder) {
            Log.d("tag", "onServiceConnected");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d("tag", "onServiceDisconnected");
        }
    };

通过绑定服务启动服务和unbindService解绑服务

   Intent intent = new Intent(ServiceActivity.this, TimerService.class);
   //BIND_AUTO_CREATE 自动创建Service。
   bindService(intent, mServiceConnection, BIND_AUTO_CREATE);

运行结果如下:

TimerService: onCreate
TimerService: onBind
   //解除绑定
   unbindService(mServiceConnection);

运行结果如下:

TimerService: onCreate
TimerService: onBind
TimerService: onUnbind
TimerService: onDestroy

可以看出通过bindService方式启动服务,完整生命周期方法为:
onCreate() --> onBind() --> onUnbind -->onDestroy()

此时我们的onBind方法返回的还是一个空的IBinder。

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind");
        return null;
    }

创建一个IBinder实例,返回此TimerService。

    public class MyBinder extends Binder{
        TimerService getService(){
            return TimerService.this;
        }
    }

修改onBind返回值。在 onServiceConnected(ComponentName name, IBinder iBinder)方法中通过IBinder 获得

    private MyBinder mMyBinder = new MyBinder();
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind");
        return mMyBinder;
    }

修改mServiceConnection,onServiceConnected方法中的IBinder对象就是上面onBinder()方法中返回的对象

    private TimerService timerService;
    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder iBinder) {
            TimerService.MyBinder myBinder = (TimerService.MyBinder) iBinder;
            timerService = myBinder.getService();
            mCounterTv.setText(timerService.getCount() + "");
            Log.d("tag", "onServiceConnected");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d("tag", "onServiceDisconnected");
        }
    };

再次执行bindService();运行结果如下

TimerService: onCreate
TimerService: onBind
D/tag: onServiceConnected

可以看出当service中的onBind()方法返回一个不为空的IBinder对象时,onServiceConnected方法被执行,表示activity和service已经成功连接。我们也已经通过IBinder 成功获得TimerService对象实例,从而对service进行操作。

通过两种启动方式启动同一个Service

当我们通过两种方式启动同一个service,此时service的生命周期如何?

TimerService: onCreate
TimerService: onStartCommand
TimerService: onBind
 D/ServiceActivity: onServiceConnected
TimerService: === count:1
 D/ServiceActivity: 调用了stopService()
TimerService: === count:2
TimerService: === count:3
 D/ServiceActivity: 调用了unbindService()
TimerService: onUnbind
TimerService: onDestroy

可以看到,当使用两种方式启动同一个服务时,只用一种方式是取消不了服务的,要同时调用stop和unbind方法才行。

猜你喜欢

转载自blog.csdn.net/sjdjdjdjahd/article/details/94165145