盒子
盒子
文章目录
  1. 基本使用
    1. 启动服务
    2. Service与Activity的通信
  2. Service生命周期
  3. 后台服务
    1. IntentService
      1. IntentService源码分析
  4. JobScheduler
    1. JobService
    2. JobInfo
    3. AlarmManager
    4. PedingIntent

Service详解

Service

Service与Thread?

两者毫无关系,Thread是一个子线程,而Service是运行在主线程中的,所以要在服务中进行耗时操作,需要另开一个Thread子线程,否则容易出现ARN异常

基本使用

启动服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
public class Servicer extends Service {
private static final String TAG=Servicer.class.getSimpleName();
public Servicer() {
super();
Log.i(TAG,"Servicer");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG,"onStartCommand");
stopService(intent);
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.i(TAG,"onDestroy");
super.onDestroy();
}
}

  • 显式启动
  • 1
    2
    Intent intent=new Intent(MainActivity.this, Servicer.class);
    startService(intent);

  • 隐式启动
  • 1
    2
    3
    4
    Intent intent=new Intent();
    intent.setPackage(getPackageName());
    intent.setAction("test");
    startService(intent);

    AndroidManifest.xml:

    1
    2
    3
    4
    5
    <service android:name=".ServerTest">
    <intent-filter>
    <action android:name="test"/>
    </intent-filter>
    </service>

    Service与Activity的通信

    用Service而不用Thread的一大原因就是Activity能方便地与Service联系,可以操控管理Service

    客户端:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    private ServiceConnection connection=new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
    Log.d("SERVER_DEBUG","onServiceConnected");
    ((ServerTest.MyBinder)service).test();
    }

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

    Intent intent=new Intent();
    intent.setPackage(getPackageName());
    intent.setAction("test");
    //startService(intent);
    bindService(intent,connection,BIND_AUTO_CREATE);

    服务端:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    public class ServerTest extends Service {
    private final String TAG="SERVER_DEBUG";

    public ServerTest() {
    super();
    }
    @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");
    }

    @Override
    public boolean onUnbind(Intent intent) {
    Log.d(TAG,"onUnbind");
    return super.onUnbind(intent);
    }

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

    class MyBinder extends Binder{
    public void test(){
    Log.d(TAG,"test");
    }
    }
    }

    分别触发启动服务,绑定服务和解绑服务:

    SERVER_DEBUG: onCreate

    SERVER_DEBUG: onStartCommand

    SERVER_DEBUG: onBind

    SERVER_DEBUG: onServiceConnected

    SERVER_DEBUG: test

    值得注意的是:

    1. 第一次启动服务会创建一个服务,即调用Binder的构造方法,当再次启动服务,则不会调用该构造方法,而是直接调用onStartCommand

    2. 当绑定了一个服务,然后stop该服务,在没有解绑该服务前,是不会调用onDestory方法,需要解绑后才会调用。

    3. 当在启动服务前,就直接绑定服务,由于绑定服务方法第三个参数为BIND_AUTO_CREATE,所以会自动创建一个服务

    Service生命周期

    Service生命周期

    参考:

    Android组件系列—-Android Service组件深入解析

    后台服务

    IntentService

    IntentService是Service的基类,可根据需要处理异步请求。客户端通过Context.startService(Intent)呼叫发送请求

    需重写两个方法:

    1
    2
    3
    4
    5
    6
    7
    8
    //此处注意,Android studio导出的默认构造器为public ServiceIntent(String name),这会报错
    public ServiceIntent() {
    super("ServiceIntent");
    }
    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
    Log.i(TAG,"onHandleIntent");
    }

    该类是通过HandleThread和Handler进行异步操作,具有较高的优先级,其每次进行异步操作都是将任务加入消息队列,通过HandleThread和Handler来进行异步操作

    使用实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class ServiceIntent extends IntentService {
    private static final String TAG=ServiceIntent.class.getSimpleName();
    public ServiceIntent() {
    super("ServiceIntent");
    }
    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
    Log.i(TAG,"onHandleIntent");
    }
    public static Intent newInstance(Context context){
    return new Intent(context,ServiceIntent.class);
    }
    public static boolean isOn(Context context){
    Intent intent=ServiceIntent.newInstance(context);
    PendingIntent pi=PendingIntent.getService(context,0,intent,PendingIntent.FLAG_NO_CREATE);
    return pi!=null;
    }
    }

    //启动服务
    Intent intent=ServiceIntent.newInstance(this);
    startService(intent);

    IntentService源码分析

    IntentService的onHandleIntent是运行在工作线程而主线程中的,故用户可在该线程直接执行耗时操作

    当启动继承了IntentService的服务时,IntentService的构造方法和onCreate方法会分别执行:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public IntentService(String name) {
    super();
    mName = name;
    }

    @Override
    public void onCreate() {
    // TODO: It would be nice to have an option to hold a partial wakelock
    // during processing, and to have a static startService(Context, Intent)
    // method that would launch the service & hand off a wakelock.

    super.onCreate();
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();

    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    在构造方法中会传入name参数,用于作为后期创建工作线程名,在onCreate中创建并开启了一个工作线程,再获取该线程的Looper,再以此looper作为参数创建一个Handler对象,用于处理消息。而消息的发送则在onStart方法中完成:

    1
    2
    3
    4
    5
    6
    7
    @Override
    public void onStart(@Nullable Intent intent, int startId) {
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    msg.obj = intent;
    mServiceHandler.sendMessage(msg);
    }

    通过Handler接收消息在handleMessage中调用onHandleIntent方法,即我们重写的那个运行在工作线程的方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    private final class ServiceHandler extends Handler {
    public ServiceHandler(Looper looper) {
    super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
    onHandleIntent((Intent)msg.obj);
    stopSelf(msg.arg1);
    }
    }

    JobScheduler

    用于根据将在应用程序自己的进程中执行的框架来安排各种类型的作业

    JobService

    需要手动开线程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class JobSchedulerService extends JobService {
    @Override
    public boolean onStartJob(JobParameters params) {
    return false;
    }
    @Override
    public boolean onStopJob(JobParameters params) {
    return false;
    }
    }

  • onStartJob
  • 当任务开始时调用,如果返回false的话,系统会自动结束本job

  • onStopJob
  • 当任务被取消时调用,jobFinished方法导致的任务结束不算在内

    当返回值为true表示任务应该计划在下次继续即可在被强制停止后再度启动起来,返回false表示不管怎样,到此结束,不要计划下次

  • jobFinished
  • final void jobFinished(JobParameters params, boolean wantsReschedule)

    当完成任务时调用该方法通知系统,该方法执行完后不会回调onStopJob(),但是会回调onDestroy()

    wantsRescheduletrue则表示这次事情做不完了,请计划下次继续

    JobInfo

    JobInfo.Builder构建一个JobInfo对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    JobInfo jobInfo = new JobInfo.Builder(i, mServiceComponent)
    //设置任务允许最少延迟时间
    .setMinimumLatency(2000)
    //设置deadline,若到期还没有到达规定的条件也会执行
    .setOverrideDeadline(50000)
    //设置网络条件,非蜂窝数据的
    .setRequireNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
    //设置充电条件
    .setRequiresCharging(true)
    //设置手机是否idle状态
    .setRequiresDeviceIdle(false)
    .build();

    启动一个JobService:

    1
    2
    3
    final JobScheduler scheduler = context.getSystemService(JobScheduler.class);
    final JobInfo.Builder builder = new JobInfo.Builder(MyJobService.ELLISONS_JOB_ID,new ComponentName(context, MyJobService.class));
    builder.setOverrideDeadline(1000);

    JobInfo.Builder(int jobId, ComponentName jobService)

    JobService和Service的多角度对比

    AlarmManager

    参考:

    AlarmManager使用

    PedingIntent

    一种特殊的,携带有Intent和Context,不会立即执行的意图

    常通过以下静态方法获取实例:

  • getActivity
  • getBroadcast
  • getService
  • 方法参数均为:

    1
    Context context, int requestCode, Intent intent, int flags

    第一个为上下文,第二个为请求码,第三个为具体意图,第四个为内部属性

    常用属性为:

    FLAG_NO_CREATE,即使不存在也不创建,运用如下:

    1
    2
    3
    //判断PendingIntent是否存在,若不存在pi=null
    PendingIntent pi=getService(content,0,intent,FLAG_NO_CREATE);
    boolean isOn=(pi!=null);

    该类常用于状态栏通知,定时器设置

    支持一下
    扫一扫,支持Grooter
    • 微信扫一扫
    • 支付宝扫一扫