Android四大组件之Service,以及IntentService

版权声明:转载请标明出处! https://blog.csdn.net/baidu_36619149/article/details/88149473

Service基本介绍

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

Service生命周期

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

    1. startService:onCreate --> onStartCommand --> onStart —> onDestroy

      相对应的停止方法为:stopService

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

    1. bindService: onCreate --> onBind —> onUnBind —> onDestroy

      相对应的解绑方法为: unBindService

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

  • 混合启动:

    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 没有差别。

参考文章:

猜你喜欢

转载自blog.csdn.net/baidu_36619149/article/details/88149473