Android基础笔记:(2)四大组件 Service 详解【更新结束】

目录

一、Service简介

二、Service分类

1、Started Service

2、Bound  Service

 3、启动Service回调的方法

4、通过代码还原Service生命周期

三、使用IntentService

  1、为什么使用IntentService ?

  2、 IntentService服务为什么可以自动创建线程?为什么可以自动结束服务?


一、Service简介

        Service是Android的四大组件之一。

作用

        后台长期处理耗时的逻辑。

Service与Activity的区别

        不同点:Service与Activity功能大抵相同,区别在于Service不存在UI界面,Service在后台运行,不能与用户进行交互功能。

        相同点:都需要在清单文件中注册,且都有生命周期。

Service的特点

        (1)、在后台运行,即使应用退出,也不会停止服务,只有在杀死APP进程时,才会停止服务。

        (2)、Service运行在主线程中。所以,当我们执行一些耗时的操作时,可以在服务中创建子线程来处理耗时的操作。

        (3)、Service应用广泛,例如:音乐播放,下载文件等。

更多关于Service的内容详见官方文档:服务概览  |  Android 开发者  |  Android Developers

 对于Service服务我们都不陌生,它大概在我们手机中是这样的。

接下来开始学习如何使用Service服务吧。

二、Service分类

按照启动方式可以分为:

1、Started Service

        当组件通过调用 startService() 方法启动 Service ,这时,Service处于启动状态,可以在后台无限期的运行,只有自身调用stopSelf() 方法 或者 其他组件调用 stopService() 方法才会停止Service。

2、Bound  Service

        当组件通过调用 bindService() 方法绑定 Service,这时,Service处于绑定状态,多个组件可以绑定在一个Service上,当绑定Service的所有组件解绑之后,该Service被销毁。

        两种启动方式的生命周期如下:

 3、启动Service回调的方法

startService():启动服务

        (手动调用)不受调用组件的控制,可以在后台无限期的运行。

bindService():绑定服务

        (手动调用)将多个组件与服务绑定在一块,随着组件的消亡而消亡。

onCreate():创建服务

        (自动调用)无论是开启服务还是绑定服务,最开始的回调函数肯定是onCreate(),当第一次创建Service的时候调用该方法,多次调用startService()方法不会重复调用onCreate() 方法。适合做一些初始化操作。

onStartcommand():重复开始服务

        (自动调用)当多次执行startService()方法的时候,onStartcommand()都会执行。

onBind():绑定服务

        (自动调用)当一个组件想要通过bindService()绑定service时,系统会回调该方法。该方法需要实现一个接口,通过返回IBinder对象实现用户通信。若不需要绑定service则返回null,否则必须实现。

unbindService():解绑服务【相对于某个组件来说】

        (手动调用)当组件想要与该服务解绑时调用,只有在所有用户解绑之后才会调用onUnbind()回调函数。

onUnbind():解绑服务【相对于服务来说】

        (自动调用)当所有捆绑服务的组件解绑之后,系统自动调用onUnbind()函数,将服务解绑。

onDestroy():销毁服务

        (自动调用)当Service调用这个函数的时候,这个服务就销毁停止了。下次在用的时候只能执行onCreate()函数进行创建。

stopService():结束服务

        (手动调用)其他组件通过调用该函数,将以startService()启动的Service停止掉。

stopSelf():结束服务

        (手动调用)当前Service调用此方法来终结自己。

4、通过代码还原Service生命周期

        案例:在MainActivity中定义四个按钮,分别是:启动服务,绑定服务,解绑与结束服务。点击相应的按钮完成相应的功能。

activity_main.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"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="启动服务"
        android:id="@+id/start_button"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="绑定服务"
        android:id="@+id/bind_button"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="解除绑定"
        android:id="@+id/unbind_button"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="结束服务"
        android:id="@+id/stop_button"/>

    <TextView
        android:id="@+id/text"
        android:text="XXXXXX"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:textSize="28sp"/>

</LinearLayout>

AndroidManifest.xml

注册服务:<service>

        其中有两个属性:

1、android:enabled:表示指定的Service能否被实例化,true表示能,false表示不能。

2、android:exported:表示指定的其他组件能否调用Service或者与其交互,true表示能,false表示不能。当该值为false时,只有同应用的组件或者具有相同用户ID的程序才能启动或者绑定到Service 。

<!--    注册服务    -->
        <service android:name=".MyService"/>

MainActivity.java

package com.example.servicedemo1;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private Button start_button;
    private Button bind_button;
    private Button unbind_button;
    private Button stop_button;
    private TextView text;

    private static final String TAG1 = "serviceConnection";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //代码重构
        extracted();

        //创建Intent对象,用于服务相关操作
        Intent intent = new Intent(MainActivity.this, MyService.class);
        //启动服务
        startListener(intent);
        //绑定服务
        bindORunbindListener(intent);
        //结束服务
        stopListener(intent);

    }

    /**
     * 代码重构,获取控件
     */
    private void extracted() {
        start_button = this.findViewById(R.id.start_button);
        bind_button = this.findViewById(R.id.bind_button);
        unbind_button = this.findViewById(R.id.unbind_button);
        stop_button = this.findViewById(R.id.stop_button);
        text = this.findViewById(R.id.text);
    }

    /**
     * 点击启动服务按钮事件
     * @param intent
     */
    private void startListener(Intent intent) {
        //点击“启动服务”的事件处理
        start_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //startService():启动服务
                startService(intent);
                //将结果显示到页面
                text.setText("我已经启动服务啦!");
            }
        });
    }

    /**
     * 点击绑定与解绑服务的按钮事件
     *
     * @param intent
     */
    private void bindORunbindListener(Intent intent) {

        ServiceConnection serviceConnection = new ServiceConnection() {

            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.e(TAG1,"调用onServiceConnected");
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.e(TAG1,"调用onServiceDisconnected");
            }
        };

        点击“绑定服务”的事件处理
        bind_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //bindService():绑定服务
                bindService(intent,serviceConnection,BIND_AUTO_CREATE);
                text.setText("我已经绑定服务啦!");
            }
        });

        点击“解除绑定”的事件处理
        unbind_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //unbindService():解绑服务
                unbindService(serviceConnection);
                text.setText("解除绑定服务啦!");
            }
        });
    }

    /**
     * 结束服务按钮事件
     */
    private void stopListener(Intent intent) {
        //点击“结束服务”的事件处理
        stop_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //stopService():结束服务
                stopService(intent);
                text.setText("服务已经结束啦!");
            }
        });
    }

}

MyService.java

package com.example.servicedemo1;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service {

    private static final String TAG = "MyService";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "创建服务    ——>    onCreate()");
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "绑定服务    ——>    onBind()");
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "重启服务(首次为启动)    ——>    onStartCommand()");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(TAG, "解绑服务    ——>    onUnbind()");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "销毁服务    ——>    onDestroy()");
    }
}

结果:

        (1)、第一次点击“启动服务”时:onCreate() ——> onStartCommand()

        (2)、再次点击“启动服务”时:onStartCommand()

        (3)、点击“启动服务”后又点击“绑定服务”时:onCreate()  ——>  onBind()

        (4)、点击“解绑服务”时:onUnbind()

        (5)、点击“结束服务”时:onDestroy()

如图:

三、使用IntentService

  1、为什么使用IntentService ?

        由于Service不会专门启动一个线程执行一些耗时的操作,导致所有的操作都是在主线程中进行的,稍不留神就会造成ANR异常,所以需要手动来创建一个线程可供Service执行耗时操作。

        另一个原因就是:Service启动后不会停止,只有在自身调用 stopSelf() 方法或者其他组件调用 stopService() 方法时才停止。

        而IntentService很好的避免了这两个问题。

首先创建一个Service,让他继承IntentService类,然后在清单文件注册Service。

<service android:name=".MyIntentService"/>
public class MyIntentService extends IntentService {
}

然后在MainActivity.java 中启动MyIntentService

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

最后编写MyIntentService代码,使他完成一个耗时操作。

package com.example.servicedemo1;
import android.app.IntentService;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.Nullable;

/**
 * intentService服务完成一个耗时操作
 */
public class MyIntentService extends IntentService {
    private static final String TAG = "MyIntentService";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate");
    }
    //构造方法
    public MyIntentService() {
        super("MyIntentService");
    }

    //耗时任务
    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        int i = 10;
        Log.e(TAG,"IntentService服务启动");
        Toast.makeText(this, "IntentService服务启动", Toast.LENGTH_SHORT).show();
        while (i > 0) {
            Log.i(TAG, i + "");
            i--;
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Log.e(TAG,"IntentService服务结束");
        Toast.makeText(this, "IntentService服务结束", Toast.LENGTH_SHORT).show();
    }

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


    }
}

效果如下:

        当启动IntentService时,会自动开启一个Thread,进行耗时操作,当Thread运行结束之后,IntentService也会结束。

  2、 IntentService服务为什么可以自动创建线程?为什么可以自动结束服务?

        通过源码了解一下他的处理方式。

IntentService是一个抽象类,继承Service类,所以它是一种特殊的Service,因为它内部封装了handlerThread和handler的。

public abstract class IntentService extends Service

 下面看onCreate()方法。

    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;


@Override
    public void onCreate() {

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

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

        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); 创建了一个Handler线程,thread.start() 启动了这个线程。

        thread.getLooper()  获取这个线程的Looper对象。

        new ServiceHandler(mServiceLooper) 创建一个内部类ServiceHandler对象,将Looper对象传递给它。

下一步走到了 onStartCommand() 方法

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

        这个方法里第一件事做的就是,调用onStart() 方法。

接下来看onStart() 方法

@Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

         通过 mServiceHandler.sendMessage(msg) 将message发送到消息队列,消息处理又回到serviceHandler里面的handleMessage做。

紧接着回到内部类  ServiceHandler 中 执行 handleMessage() 方法。

    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);
        }
    }

        在这个方法中,调用了 onHandleIntent((Intent)msg.obj)  这个抽象方法,但它留给子类去实现。

@WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);

        最后调用  stopSelf(msg.arg1)  停止服务,给出的定义是立即停止,但是当有参数的时候,会等所有的任务都执行完,才停止服务。

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值