Android四大组件之Service,以及IntentService

@[toc]php

Service基本介绍

Android四大组件之一,没有界面的后台服务。咱们若是想要在后台执行一些任务,会用到Service。好比:后台下载更新;后台播放音乐等等。java

Service生命周期

  • Service有两种启动方式,经过两种不一样的启动方式,生命周期执行方法也是不同的:android

    1. startService:onCreate --> onStartCommand --> onStart ---> onDestroyapp

      相对应的中止方法为:stopService异步

    重复调用 startService 不会从新走 onCreate方法,只会走 onStartCommand --> onStartide

    1. bindService: onCreate --> onBind ---> onUnBind ---> onDestroyoop

      相对应的解绑方法为: unBindService源码分析

    重复调用 bindService 方法,不会再次走 onCreate 方法,只会走 onBind 方法布局

  • 混合启动:ui

    service的onCreate只会走一次。

    先调用 startService,再调用 bindService。 onCreate --> onStartCommand --> onStart --(此时调用 bindService )---> onBind。

    先调用 bindService,再调用 startService。 onCreate --> onBind --(此时调用 startService )---> onStartCommand --> onStart。

    混合启动想要销毁 Service 必须 stopService、unBindService 都调用,不然无效。

Service的基本用法

  • 首先建立一个class继承Service

    继承 service 的服务,在里面不能进行耗时操做,由于它自己也是依赖于主进程的,不是一个单独的线程,没法进行耗时操做。

public class MyService extends Service {
    public static final String TAG = "MyService";

    @Override
    public void onCreate() {
        Log.i(TAG, "onCreate: ");
        super.onCreate();
    }

    @Override
    public void onStart(Intent intent, int startId) {
        Log.i(TAG, "onStart: ");
        super.onStart(intent, startId);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand: ");
        //在这里建立一个子线程,睡眠5秒钟后,调用关闭 service 方法
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                    stopService1();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind: ");
        // 返回代理对象
        return new MyBinder();
    }

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

    public void stopService1() {
        Log.i(TAG, "中止服务");
        stopSelf();
    }
    
    public void receiveMsg(String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }
    
    @Override
    public void onDestroy() {
        Log.i(TAG, "onDestroy: ");
        super.onDestroy();
    }
    
    //建立一个Service的代理类,经过它能够调用Service中的方法。
    public class MyBinder extends Binder {

        public void sendMsg(String msg) {
            receiveMsg(msg);
        }
    }
}

复制代码
  • 在 AndroidManifest.xml 文件中注册:
<!-- enabled 是否能够被激活,若是设置为false,就没法激活Service-->
<!-- exported 是否能够被外部*进程*激活,-->
<service android:name=".service.MyService" android:enabled="true" android:exported="false" />
复制代码
  • 在Activity中启动,以及关闭,以及怎么调用Service中的方法:
public class ServiceActivity extends AppCompatActivity implements View.OnClickListener {

    private Button mBtnStartService;
    private Button mBtnStopService;
    private Button mBtnBindService;
    private Button mBtnUnbindService;
    private MyService.MyBinder myIBinder;
    private MyConnection myConnection;
    private Button mBtnCallService;//调用Service中的方法

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_service);
        initView();
        initAction();
        initData();
    }

    private void initView() {
        mBtnStartService = findViewById(R.id.btn_start_service);
        mBtnStopService = findViewById(R.id.btn_stop_service);
        mBtnBindService = findViewById(R.id.btn_bind_service);
        mBtnUnbindService = findViewById(R.id.btn_unbind_service);
        mBtnCallService = findViewById(R.id.btn_call_service);
    }

    private void initAction() {
        mBtnStartService.setOnClickListener(this);
        mBtnStopService.setOnClickListener(this);
        mBtnBindService.setOnClickListener(this);
        mBtnUnbindService.setOnClickListener(this);
        mBtnCallService.setOnClickListener(this);
    }

    private void initData() {
        myConnection = new MyConnection();
    }

    @Override
    public void onClick(View v) {
        Intent service = new Intent(this, MyService.class);
        switch (v.getId()) {
            case R.id.btn_start_service:
                startService(service);
                break;
            case R.id.btn_stop_service:
                stopService(service);
                break;
            case R.id.btn_bind_service:
                bindService(service, myConnection, BIND_AUTO_CREATE);
                break;
            case R.id.btn_unbind_service:
                unbindService(myConnection);
                break;
            case R.id.btn_call_service:
                myIBinder.sendMsg("我是Activity传来的消息");
                break;
            default:
                break;
        }
    }

    public class MyConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
        //获取Service的代理
            myIBinder = (MyService.MyBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }
}

复制代码
  • xml布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".service.ServiceActivity">

    <Button android:id="@+id/btn_start_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="start_service" />

    <Button android:id="@+id/btn_stop_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="stop_service" />

    <Button android:id="@+id/btn_bind_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="bind_service" />

    <Button android:id="@+id/btn_unbind_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="unbind_service" />

    <Button android:id="@+id/btn_call_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="调用Service内部方法" />

</LinearLayout>
复制代码
  • 实验结果:

    点击 bindService 绑定Service,而后点击 btn_call_service ,弹出吐司 “我是Activity传来的消息”,完成Activity和Service的调用

  • 注意: Service是有可能绑定失败的,具体缘由和解决方案:bindService不调用onServiceConnected的问题

  • onStartCommand:

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

    onStartComand使用时,返回的是一个(int)整形。

    这个整形能够有四个返回值:start_sticky、start_no_sticky、START_REDELIVER_INTENT、START_STICKY_COMPATIBILITY。

    它们的含义分别是:

    1. START_STICKY:若是service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试从新建立service,因为服务状态为开始状态,因此建立服务后必定会调用onStartCommand(Intent,int,int)方法。若是在此期间没有任何启动命令被传递到service,那么参数Intent将为null。

    2. START_NOT_STICKY:“非粘性的”。使用这个返回值时,若是在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务

    3. START_REDELIVER_INTENT:重传Intent。使用这个返回值时,若是在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。

    4. START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后必定能重启。

    flags表示启动服务的方式:

    Additional data about this start request. Currently either 0,START_FLAG_REDELIVERY,or START_FLAG_RETRY。

    1. START_FLAG_REDELIVERY:若是你实现onStartCommand()来安排异步工做或者在另外一个线程中工做, 那么你可能须要使用START_FLAG_REDELIVERY来让系统从新发送一个intent。这样若是你的服务在处理它的时候被Kill掉, Intent不会丢失.

    2. START_FLAG_RETRY:表示服务以前被设为START_STICKY,则会被传入这个标记。

IntentService:

  • 介绍

    相对于Service而言,IntentService自己拥有一个子线程,能够进行耗时操做,在任务代码完成后,会自动销毁服务,不用手动调用。

  • 代码:

public class MyIntentService extends IntentService {
    private static final String TAG = "MyIntentService";

    public MyIntentService() {
        super("MyIntentService");
    }
多出一个onHandleIntent方法,能够在里面作耗时操做
    @Override
    protected void onHandleIntent(Intent intent) {
        try {
            Thread.sleep(5000);
            Log.i(TAG, "onHandleIntent: 睡了5秒");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void onDestroy() {
        Log.i(TAG, "onDestroy: ");
        super.onDestroy();
    }
}

复制代码
  • 步骤:和Service同样,在 Activity 中调用 startService 方法开启服务。只不过 IntentService 在开启后,onHandleIntent 中的代码执行完后,会自动销毁服务。

  • 实验结果:

    2019-03-05 00:26:14.972 16106-16106/com.sjc.myapplication I/MyIntentService: onCreate: 
    2019-03-05 00:26:14.981 16106-16106/com.sjc.myapplication I/MyIntentService: onStart: 
    2019-03-05 00:26:19.983 16106-17272/com.sjc.myapplication I/MyIntentService: onHandleIntent: 睡了52019-03-05 00:26:19.985 16106-16106/com.sjc.myapplication I/MyIntentService: onDestroy: 
    
    复制代码
  • 源码分析: IntentService源码并不长。

//自己是一个抽象类,继承与Service
public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;
    //在内部建立了一个 Handler对象
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            //执行完 onHandleIntent 方法后,调用了stopSelf方法,销毁服务。
            onHandleIntent((Intent)msg.obj);
            //销毁服务
            stopSelf(msg.arg1);
        }
    }

   
    public IntentService(String name) {
        super();
        mName = name;
    }

   
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

    @Override
    public void onCreate() {
      
        super.onCreate();
        //在onCreate 中建立了一个 HandlerThread 线程
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        //开启线程
        thread.start();

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

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
    //onStrat 中发送消息,而后回调ServiceHandler 的 handleMessage 方法
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

 
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
    //退出Looper
        mServiceLooper.quit();
    }

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

    //抽象方法,在子类中重写。
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}

复制代码
  • 总结: IntentService 只能经过 startService 方式开始有用,才会回调 onHandleIntent 方法。且执行完子线程中的任务后,自动销毁。若是使用 bindService 方式开启,和普通 Service 没有差异。

参考文章:

相关文章
相关标签/搜索