Android开发

Android基础之Service

2019-05-23  本文已影响0人  不会游泳的金鱼_

本文的要点如下:

Service简介

定义:Service(服务)是Android中实现程序后台运行的解决方案,是Android四大组件之一, 属于计算型组件
作用:去执行那些不需要和用户交互而且还要求长期运行的任务(如:复杂计算、音乐播放、下载等)
特点:无用户界面

Service的生命周期

依旧先上经典图:

Service的生命周期
在Service的生命周期里,常用的有:
4个手动调用的方法:
手动调用方法 作用
startService() 启动服务
stopService() 关闭服务
bindService() 绑定服务
unbindService() 解绑服务

5个自动调用的方法:

内部自动调用方法 作用
onCreate() 创建服务
onStartCommand() 开始服务
onDestroy() 销毁服务
onBind() 绑定服务
onUnbind() 解绑服务

从上图可看到有两种方法可以启动Service:

第一种:其他组件调用Context的startService()方法可以启动一个Service,并回调服务中的onStartCommand()。如果该服务之前还没创建,那么回调的顺序是onCreate()->onStartCommand()。服务启动了之后会一直保持运行状态,直到stopService()(外部)stopSelf()(内部)方法被调用,服务停止并回调onDestroy()。另外,无论调用多少次startService()方法,只需调用一次stopService()或stopSelf()方法,服务就会停止了。

第二种:其它组件调用Context的bindService()可以绑定一个Service,并回调服务中的onBind()方法。类似地,如果该服务之前还没创建,那么回调的顺序是onCreate()->onBind()。之后,调用方可以获取到onBind()方法里返回的IBinder对象的实例,从而实现和服务进行通信。只要调用方和服务之间的连接没有断开,服务就会一直保持运行状态,直到调用了unbindService()方法服务会停止,回调顺序onUnBind()->onDestroy()。

注意,这两种启动方法并不冲突,当使用startService()启动Service之后,还可再使用bindService()绑定,只不过需要同时调用 stopService()和 unbindService()方法才能让服务销毁掉。

Service的基本用法

普通服务(不可通信)

  1. 新建子类继承Service类,必须重写父类的onBind()方法,可以根据需要重写onCreate()、onStartCommand()和onDestroy()方法
  2. 构建用于启动Service的Intent对象。
  3. 调用startService()启动Service、调用stopService()停止服务。
  4. 在AndroidManifest.xml里注册Service。
public class MyService extends Service {
    private static final String TAG = "MyService";
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG,"执行了onCreate()");
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG,"执行了onStartCommand()");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG,"执行了onDestory()");
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

不可通信的普通服务是最简单的服务,从工作流程也可以看出,其他组件只能对服务进行开启和关闭,并没有通信的方法。

普通服务(可通信)

要想服务和其他组件进行通信,组件指挥服务去干什么,服务就去干什么,这时就需要借助onBind方法了:

    private DownloadBinder mBinder = new DownloadBinder();
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
    class DownloadBinder extends Binder {
        public void startDownload(){
            Log.e(TAG,"startDownload");
        }
        public int getProgress(){
            Log.e(TAG,"getProgess");
            return 0;
        }
    }

在Activity通过调用DownloadBinder类中的public方法即可实现Activity与Service的通信。

      private MyService.DownloadBinder downloadBinder;
      private ServiceConnection connection = new ServiceConnection() {
        //服务成功绑定时调用
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            downloadBinder = (MyService.DownloadBinder) iBinder;
            downloadBinder.startDownload();
            downloadBinder.getProgress();
        }
        
        //服务解绑时调用
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
        }
      };

    @OnClick(R.id.bind_service)
    public void bindOnclick(){
        Intent bindIntent = new Intent(this,MyService.class);
        bindService(bindIntent,connection,BIND_AUTO_CREATE);//绑定服务
    }
    @OnClick(R.id.unbind_service)
    public void unbindOnclick(){
        unbindService(connection);//解绑服务
    }

可以看到,主要步骤就是创建了一个ServiceConnection匿名类,在里面重写了onServiceConnected()和onServiceDisconnected()方法。这两个方法光看名字也知道分别在Service成功绑定和解绑时调用,里面就可以通过向下转型获取Binder实例,调用Binder中的public方法即可完成Service和Activity的通信。

前台服务

前台Service和后台Service(普通)最大的区别就在于,前台Service在下拉通知栏有显示通知,但后台Service没有。因此,前台服务的优先级会高于后台服务,通常情况下不会被系统回收

前台服务的创建也和普通服务差不多,只需稍加修改即可:

 @Override
    public void onCreate() {//服务创建时调用
        Log.e(TAG,"MyFrontService onCreate");
        super.onCreate();
        Intent intent = new Intent(this,MainActivity.class);
        PendingIntent pi = PendingIntent.getActivity(this, 0 ,intent ,0);
        Notification notification = new NotificationCompat.Builder(this,"default")
                .setContentTitle("this ic content title")
                .setContentText("this is content text")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
                .setContentIntent(pi)
                .build();//构建Notification对象
        //让Service变成前台Service,并在系统的状态栏显示出来
        startForeground(1,notification);
    }

可以看到,仅仅只是多调用了一个startForeground方法,其第一个参数是Notification的id,第二个参数是Notification对象。

IntentService

我们都知道,Service是运行在主线程中的,因此其中不能做耗时操作,以免发生ANR情况。
为了可以更方便的创建一个异步的、可以自动停止的Service,Android中专门提供了一个IntentService类,继承自Service。
它的用法其实很简单:

  1. 新建类并继承IntentService,在这里需要提供一个无参的构造函数且必须在其内部调用父类的有参构造函数;
  2. 具体实现 onHandleIntent()方法,在里可以去处理一些耗时操作而不用担心 ANR的问题,因为这个方法已经是在子线程中运行的了。
  3. 在配置文件中进行注册。
  4. 在活动中利用Intent实现IntentService的启动,和Service用的方法是完全一样的。
public class MyIntentService extends IntentService {
    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        //打印当前线程的id,证明确实是在子线程中运行
        Log.d("MyIntentService","thread id is :"+ 
                        Thread.currentThread().getId());
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("MyIntentService","onDestory executed");
    }
}

总结

1. Service用于提供与UI无关的服务,是Android中的四大组件之一。
2. 服务大致可以分为两种类型:后台服务和前台服务,区别在于是否在通知栏有显示通知。
3. 服务的启动方法有两种:startService或bindService,这两种方法并不冲突,当使用startService()启动Service之后,还可再使用bindService()绑定,只不过需要同时调用 stopService()和 unbindService()方法才能让服务销毁掉。
4. 服务是运行在UI线程的,里面不能做耗时操作,为了可以更方便的创建一个异步的、可以自动停止的Service,Android中专门提供了一个IntentService类,继承自Service。

上一篇 下一篇

猜你喜欢

热点阅读