Android学习笔记之Service

一、服务的基本概念

1.服务是Android中实现程序后台运行的解决方案,它非常适合去执行那些不需要和用户交互而且要长时间运行的任务。

2.服务虽然不依赖于任何UI界面,但它依赖于创建服务时所在的应用程序进程。当某个应用程序进程被杀掉时,所有依赖于该进程的服务也会停止。

3.虽然服务运行在后台,但服务并不会自动开启线程,所有代码都是默认运行在主线程中的。换言之,如果我们没有在服务内部手动创建子线程,就有可能出现主线程被阻塞住的情况。

二、启动服务的两种方式

2.1.使用startService()方法启动服务

1.新建一个自定义的服务类去继承Service

public class MyService extends Service {
    private static final String TAG = "MyService";
    public MyService() {
    }
    //该方法是Service中唯一一个抽象方法,在下一种启动服务的方式中要用到,这里就简单的返回Null
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    //在服务创建的时候调用
    @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, "onDestroy: 服务被销毁,常用于回收那些不再使用的资源");
    }
}

2.编辑AndroidManifest.xml文件注册刚才的服务

<service
    android:name=".MyService"
    android:enabled="true"
    android:exported="true"></service>

其中enabled属性为true表示启用该服务,exported属性为true表示允许当前程序以外的其他程序访问该服务。

3.通过Context中的startService()方法启动服务,通过Context中的stopService()方法销毁活动

public void onClick(View v) {
    switch (v.getId()){
        case R.id.btn_start_service:
            Intent startIntent = new Intent(this,MyService.class);
            startService(startIntent);
            break;
        case R.id.btn_stop_service:
            Intent stopIntent = new Intent(this,MyService.class);
            stopService(stopIntent);
            break;
        default:
            break;
    }

如果想让服务自己决定销毁的时间点,可以在自定义服务MyService中任何一个位置调用stopSelf()方法来让其停止。

2.2.使用bindService()方法启动服务

1.在之前自定义的服务类中定义一个内部类去继承Binder(实现了IBinder接口)

class DownloadBinder extends Binder{
    /**
     * 获取Service实例
     * */
    public MyService getService(){
        return MyService.this;
    }
}

PS:这里给内部类DownloadBinder添加了一个获取MyService实例的方法,之后将通过该方法获取MyService实例,然后调用其内部方法(下载),从而实现活动与服务之间的通信。

2.编辑自定义服务类MyService,创建一个内部类DownloadBinder的实例,并在onBind()方法中返回该实例,最后添加内部方法(根据情况自行添加,这里以下载为例)

public class MyService extends Service {
    private static final String TAG = "MyService";
    private DownloadBinder mBinder = new DownloadBinder();
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
    ......
    class DownloadBinder extends Binder{
        /**
         * 获取Service实例
         * */
        public MyService getService(){
            return MyService.this;
        }
    }
    private void startDownload(){
        Log.d(TAG, "startDownload executed");
    }
    private int getProgress(){
        Log.d(TAG, "getProgress executed");
        return 0;
    }
}

3.在Activity中创建一个ServiceConnection的匿名类,并重写其onServiceConnected()方法以及onServiceDisconnected()方法(假设绑定成功后立即下载并返回下载进度)

private ServiceConnection connection = new ServiceConnection() {
    //与服务成功绑定时调用
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        MyService.DownloadBinder binder = (MyService.DownloadBinder) service;
        //获取MyService实例
        MyService myService = binder.getService();
        myService.startDownload();
        myService.getProgress();
    }
    //与服务解除绑定时调用
    @Override
    public void onServiceDisconnected(ComponentName name) {
    }
};

4.通过bindService()方法绑定服务,通过unbindService()方法解绑服务

case R.id.btn_bind_service:
    Intent bindIntent = new Intent(this,MyService.class);
    bindService(bindIntent,connection,BIND_AUTO_CREATE);
    break;
case R.id.btn_unbind_service:
    unbindService(connection);
    break;

其中BIND_AUTO_CREATE是Context中的字段,它表示活动和服务进行绑定后自动创建服务。这会使得MyService中的onCreate()方法得到执行,而onStartCommand()方法不会执行。

PS:任何一个服务在整个应用程序范围内都是通用的,即MyService不急可以和这里的MainActivity绑定,还可以和任何一个其他的活动进行绑定,而且在绑定完成后它们都可以获取到相同的DownloadBinder实例。

三、服务的生命周期

3.1.如果是bindService()方法启动服务

通过Context的bindService()方法来启动服务时,所有的生命周期方法均只会被执行一次,执行顺序如下:

onCreate -> onBind -> onUnbind -> onDestroy

一旦我们调用bindService()方法获取一个服务的持久连接,就会回调服务中的onBind()方法。如果这个服务之前还没有创建过,onCreate()方法便会先于onBind()方法执行。与此同时,调用者会和Service绑定在一起,调用者退出了或者调用了Context的unbindService()方法,Srevice就会调用onUnbind->onDestroy相应退出。

3.2.如果是startService()方法启动服务

通过Context的startService()方法来启动服务时,onStartCommond()方法可以被反复执行许多次,执行顺序如下:

onCreate -> onStartCommond -> onDestroy

一旦我们调用startService()方法,相应的服务就会启动起来,并回调onStartCommond()方法。如果这个服务之前还没有创建过,onCreate()方法便会先于onStartCommond()方法执行。服务启动之后便会一直保持运行状态,直到stopService()或者stopSelf()方法被调用。注意在这里,虽然每调用一次startService()方法,onStartCommond()方法就会执行一次,但实际上每个服务都只会存在一个实例,也就是说,不管我们调用了多少次onStartCommond()方法,只需要调用一次stopService()或者stopSelf()方法,服务便会停止。

PS:我们完全有可能对一个服务既调用了startService()方法,又调用了bindService()方法,这种时候,我们需要同时调用stopService()方法和unbindService()方法才能使服务的onDestory()方法执行。

四、如何使用前台服务

所谓前台服务,它和普通服务的最大区别就在于,它会一直有一个正在运行的图标在系统的状态栏上显示,下拉状态栏后可以看到更加详细的信息,类似于通知的效果。

1.打开之前自定义的服务类MyService,为其onCreate()方法中添加如下代码:

NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String channelId = "service";
String channelName = "服务";
int importance = NotificationManager.IMPORTANCE_HIGH;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
    NotificationChannel notificationChannel = new NotificationChannel(channelId,channelName,importance);
    notificationManager.createNotificationChannel(notificationChannel);
}
Intent intent = new Intent(this,MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(this,0, intent,0);
Notification notification = new NotificationCompat.Builder(this,channelId)
        .setContentTitle("This is content title")
        .setContentText("This is content text")
        .setWhen(System.currentTimeMillis())
        .setSmallIcon(R.mipmap.ic_launcher_round)
        .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_round))
        .setContentIntent(pi)
        .build();
startForeground(1,notification);

其实这里的操作步骤和我之前有关Notification的学习笔记是差不多的,总的步骤为:先创建通知管理器,然后创建通知渠道,再创建通知,最后一步不同之前,调用了startForeground()方法,该方法接收两个参数:通知的id、通知notification对象。

五、能够自动停止的异步的服务IntentService

1.新建一个自定义的类去继承IntentService

public class MyIntentService extends IntentService

2.提供一个无参构造器,并在其内部调用父类的有参构造器

public MyIntentService() {
    super("MyIntentService");
}

3.重写onHandleIntent()这个抽象方法,在这个方法中可以处理一些具体的逻辑(这里只是简单的打印了下当前线程ID)

@Override
protected void onHandleIntent(@Nullable Intent intent) {
    //打印当前线程ID
    Log.d(TAG, "Thread id is: "+Thread.currentThread().getId());
}

4.启用IntentService

Intent intentService = new Intent(this,MyIntentService.class);
startService(intentService);

5.最后别忘了在AndroidManifest.xml文件中注册服务

<service
    android:name=".MyIntentService"
    android:enabled="true"
    android:exported="true"></service>

猜你喜欢

转载自blog.csdn.net/Ein3614/article/details/81808877
今日推荐