(二)Service

什么是Service
Service是一个长期运行在后台没有用户界面的Android组件。

在Android中后台是相对UI前台而言的,后台不是子线程。
ServiceThread没有任何关系
Service是运行在主线程中的,若直接在Service里面做耗时操作很容易造成ANR「Application Not Responding」,故在Service中不能直接做耗时操作,要想做耗时操作只能在Service中创建的子线程中进行。

  • Android中有两种Service
    1. Service
//AndroidManifest文件中注册service
 
  1.1 Service 是单向的  不受控的
@Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent intent = new Intent(MainActivity.this, MyService.class);
        //启动Service
        startService(intent);
    }
//这个Service 是单向的  不受控的
// Context.startService(...)之后,Service的 onCreate()和onStartCommand(...)会得到执行。
//之后Service会一直处于运行状态,但具体运行的是什么逻辑,Context就控制不了了。
// 这就好比Activity通知了服务一下:『喂,哥们你可以干活去了』,然后服务就去忙自己的事情了,
// 但Activity并不知道Service到底去做什么了,以及完成的如何。
// Service去干活怎么干不受Context控制,
// Service与Context没任何交流
public class MyService extends Service {
   @Override
   public IBinder onBind(Intent intent) {
       return null;
   }
//会在Service第一次创建时调用
// 若多次调用Context.startService(...)  此方法只会执行一次
   @Override
   public void onCreate() {
       super.onCreate();
   }
//每次启动Service时调用
   @Override
   public int onStartCommand(Intent intent, int flags, int startId) {
       //new MyAsyncTask().execute();
       //创建并开启子线程进行耗时任务
       new Thread(new Runnable() {
           @Override
           public void run() {
               //耗时操作。。。
               Log.i("创建并开启子线程进行耗时任务", "run");
               //耗时操作处理完毕后  不一定要停掉Service 否则会造成内存泄漏
               stopSelf();
           }
       }).start();
       return super.onStartCommand(intent, flags, startId);
   }
//会在Service销毁时调用
   @Override
   public void onDestroy() {
       super.onDestroy();
   }
}
public class MyAsyncTask extends AsyncTask {

    //在后台任务开始执行之前调用,用于进行一些界面上的初始化操作。(初始化工作)
    @Override
    protected void onPreExecute() {
        //显示进度对话框。。。
        super.onPreExecute();
    }

    /**
     * 这个方法中的代码都会在子线程中运行,在这里处理所有的耗时操作任务。
     * 这个方法中不可进行UI操作,可调用publishProgress(Progress...)来完成UI更新。
     * retun 返回任务的执行结果
     */
    @Override
    protected Boolean doInBackground(Void... voids) {
        //耗时操作
        return true;
    }

    /**
     * 调用publishProgress(...)方法后,onProgressUpdate这个方法就被调用,在这个方法中可以对UI进行操作
     */
    @Override
    protected void onProgressUpdate(Integer... values) {
        //更新UI   如进度条。。。
        super.onProgressUpdate(values);
    }

    /**
     * 当后台线程任务执行完毕并通过return进行返回时,
     * 这个方法就会被调用。在这个方法中根据传参(任务执行的结果)
     * 进行相应的UI及逻辑操作。
     */
    @Override
    protected void onPostExecute(Boolean aBoolean) {
        //关闭进度对话框  。。。
//此处 停止service
        super.onPostExecute(aBoolean);
    }
}
1.2  Service 是双向的  可控的
public class MyService2 extends Service {
    private static final String TAG = "MyService2";
    //Context通过Binder对Service进行控制
    private DownloadBinder downloadBinder = new DownloadBinder();

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

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    class DownloadBinder extends Binder {
        public void startDownload() {
            Log.i(TAG, "startDownload...");
        }

        public int getProgress() {
            Log.i(TAG, "getProgress...");
            return 0;

        }
    }
}

//MainActivity中
  private MyService2.DownloadBinder downloadBinder;
    private ServiceConnection serviceConnection;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                downloadBinder = (MyService2.DownloadBinder) service;
                downloadBinder.startDownload();
                downloadBinder.getProgress();
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                downloadBinder.stopDownload();
            }
        };
        Intent intent = new Intent(MainActivity.this, MyService2.class);
        //绑定Service   BIND_AUTO_CREATE ---> 绑定之后自动创建Service
        bindService(intent, serviceConnection, BIND_AUTO_CREATE);
        
        //解绑
        unbindService(serviceConnection);
    }

注意: 若同时调用了bindService(intent, serviceConnection, BIND_AUTO_CREATE)和startService(intent),相应就要同时stopService(intent)和unbindService(serviceConnection)

  1. IntentService(增强版的Service,集开启线程,以及任务完成后停止service于一身)
//用法和普通的Service一样   startService(...) 或 bindService(...)
public class MyIntentService extends IntentService {
    public MyIntentService() {
        super("MyIntentService");
    }

    //这个方法已经在子线程,无需担心ANR
    //Serive任务完成后会自动停止服务
    @Override
    protected void onHandleIntent(Intent intent) {
        //耗时操作
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
    }


    @Override
    public IBinder onBind(Intent intent) {
        return super.onBind(intent);
    }
}

使用场景

  1. 前台保活

    • 使用服务的原因:普通服务(后台服务)的优先级低,系统出现内存不足时,很容易回收掉正在后台运行的服务。「比如后台运行播放音乐,用着用着音乐服务没了」。若想让服务一直保持运行状态,而不会由于系统内存不中的原因导致被回收,就可以考虑使用前台服务。
  2. 普通服务与前台服务的区别

    • 一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏可以看到更加详细的信息,类似于通知的效果。
//只需要修改一下MyService类中的onCreate方法
@Override
  public void onCreate() {
      super.onCreate();
      Intent intent = new Intent(this, MainActivity.class);
      PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
      Notification notification = new NotificationCompat.Builder(this)
              .setContentTitle("this is 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();
      startForeground(1, notification);

  }

原理

参考:
https://developer.android.google.cn/guide/components/services#Foreground

你可能感兴趣的:((二)Service)