天天看点

Android Service & IntentService学习总结1. Service介绍2. Service生命周期3. 自定义Service例子4. IntentService

目录

1. Service介绍

1.1 Service是什么,有什么作用

2. Service生命周期

3. 自定义Service例子

3.1 观察Service生命周期

3.2 绑定Service例子

3.3 startService 与 bindService 的区别

4. IntentService

4.1 IntentService是什么

4.2 IntentService与Service的区别

4.3 IntentService例子Demo

1. Service介绍

Android 四大组件之Service(中译:服务)学习。

1.1 Service是什么,有什么作用

Service(中译:服务)是一个组件,用于在后台执行长时间运行的操作,如播放音乐、处理网络事务、交互内容提供者等。Service没有任何UI界面,所以不需要与用户交互,而且即使应用程序被破坏,它也能正常工作。

2. Service生命周期

Service有两种形式,分别是Start(启动)和Bound(绑定):

Android Service & IntentService学习总结1. Service介绍2. Service生命周期3. 自定义Service例子4. IntentService

左边是Start Service;右边为Bound Service

Start(启动):当app组件(如Activity)通过调用startService()来启动服务,服务一旦启动,就可以在后台无限期运行,即使启动它的组件(如Activity)被销毁。可以通过调用stopService()方法来停止服务,而且服务本身可以通过调用stopSelf()方法来自行停止。

Bounded(绑定):当app组件通过调用bindService()方法绑定到服务时,服务将被绑定。绑定服务提供了一个client-server interface(客户机-服务器接口),该接口允许组件与服务交互、发送请求、获取结果。在所有客户端解除服务绑定之前,无法停止服务。

public class ExampleService extends Service {
    int startMode;       //指示在服务被终止时如何行为
    IBinder binder;      //用于绑定客户的接口
    boolean allowRebind; //指示是否应该使用onRebind()
 
    /**
     * 在最初创建服务时(在调用onStartCommand()或onBind()之前),系统将调用此方法以执行一次性设置过程。
     * 如果服务已经在运行,则不会调用此方法。
     */
    @Override
    public void onCreate() {
        //正在创建服务
    }

    /**
     * 当另一个组件(例如活动)请求启动服务时,系统通过调用startService()来调用此方法。
     * 执行此方法时,服务将启动并可以无限期在后台运行。
     * 如果执行此操作,则 必须 通过调用stopSelf()或stopService()在服务完成后停止该服务。如果只想提供绑定,则不需要实现此方法。
     * @param intent
     * @param flags
     * @param startId
     * @return
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //调用startService(),服务正在启动 
        return mStartMode;
    }

    /**
     * 在call bindService()方法时调用。在此方法的实现中,必须提供一个接口,客户端可以通过返回IBinder使用该接口与服务进行通信。
     * 当你实现绑定时,必须始终实现此方法。但是,如果不允许绑定,则应返回null。
     * @param intent
     * @return
     */
    @Override
    public IBinder onBind(Intent intent) {
        //客户端使用bindService()来绑定到服务
        return mBinder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        //所有客户端都使用unbindService()来解除绑定
        return mAllowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        //重新绑定,指调用onUnbind()之后,客户端使用bindService()重新绑定到服务
    }

    /**
     * 当服务不再使用并被销毁时,系统将调用此方法,所以这是服务收到的最后一个呼叫。
     * 您的服务应实现此目的,以清理所有资源,例如线程,注册的侦听器或接收器。
     */
    @Override
    public void onDestroy() {
        //服务不再使用,正在被销毁
    }
}
           

3. 自定义Service例子

3.1 观察Service生命周期

startService 的周期为:开启 -> onCreate -> onStartCommand ,销毁 -> onDestry

简单的创建一个Service,然后启动它-然后销毁它,利用Toast显示状态,效果如下所示:

Android Service & IntentService学习总结1. Service介绍2. Service生命周期3. 自定义Service例子4. IntentService

start创建服务,stop停止服务

1. 创建MyService服务,添加Toast用于显示Service状态

public class MyService extends Service {
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(this, "Service onCreate", Toast.LENGTH_SHORT).show();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show();
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(this, "Service onDestroy", Toast.LENGTH_SHORT).show();
    }

}
           

2. 在AndroidManifest签单文件中定义声明我们刚刚创建的MyService。(当然这一步可以让Android Studio来帮我们完成)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.servicetest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        //声明我们的服务
        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true">
        </service>

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
           

关于 Service 在清单文件中的一些参数说明:

1. android: name:对应 Service 类名,必须填写。

2. android: enabled:是否可以被系统实例化,默认为 true。 

3.android: exported:代表是否能被其他应用所调用,如果将其设置为 false,则确保服务仅适用于您的应用。其默认值取决于定义的 Service 是否设置了 intent-filter,如果有 intent-filter,默认值为 true,否则为 false。为 false 的情况下,即使有 intent-filter 匹配,也无法打开,即无法被其他应用隐式调用。

3. 在我们的app组件-MainActivity.java文件中进行 Service 的操作,(启动服务,停止服务)

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button startBtn = findViewById(R.id.start_service_btn);
        startBtn.setOnClickListener(this);
        Button stopBtn = findViewById(R.id.stop_service_btn);
        stopBtn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.start_service_btn:
                //启动服务
                Intent intent = new Intent(this, MyService.class);
                startService(intent);
                break;
            case R.id.stop_service_btn:
                //停止服务
                Intent stopIntent = new Intent(this, MyService.class);
                stopService(stopIntent);
                break;
            default:
                break;
        }
    }
}
           

3.2 绑定Service例子

相对比与Start Service,bound service会相对复杂些,见下例所示:

Android Service &amp; IntentService学习总结1. Service介绍2. Service生命周期3. 自定义Service例子4. IntentService

具体代码如下:

public class MyBoundService extends Service {
    private final IBinder mBinder = new MyBinder();
    private final Random mGenerator = new Random();

    public MyBoundService() {
    }

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

    class MyBinder extends Binder {
        MyBoundService getService() {
            //返回MyBoundService的实例
            return MyBoundService.this;
        }
    }

    public int getRandomNumber() {
        return mGenerator.nextInt(100);
    }
}
           
public class BoundServiceTestActivity extends AppCompatActivity {
    private MyBoundService boundService;
    private boolean isBoundService = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bound_service_test);

        Button getRandomBtn = findViewById(R.id.get_number_btn);
        getRandomBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isBoundService) {
                    Toast.makeText(BoundServiceTestActivity.this,
                            "random Number is: " + boundService.getRandomNumber(),
                            Toast.LENGTH_SHORT)
                            .show();
                }
            }
        });

    }

    @Override
    protected void onStart() {
        super.onStart();
        Intent intent = new Intent(this, MyBoundService.class);
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (isBoundService) {
            unbindService(serviceConnection);
            isBoundService = false;
        }

    }

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            MyBoundService.MyBinder binder = (MyBoundService.MyBinder) service;
            boundService = binder.getService();
            isBoundService = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            isBoundService = false;
        }
    };
}
           

3.3 startService 与 bindService 的区别

从二者的生命周期上看:

startService 开启的 Service 的生命周期不与开启它的 Activity 的生命周期相关联,即使开启它的 Activity 销毁了,该 Service 还会一直运行,直到调用 stopService() 或 Service 自身调用 stopSelf(),该 Service 才会被销毁。

bindService 开启的 Service 的生命周期与开启它的 Activity 的生命周期相关联,如果开启它的 Activity 被销毁了,那该 Service 也就会被销毁。

4. IntentService

4.1 IntentService是什么

IntentService是Service的子类,继承于Service类,用于处理需要异步请求的任务。用户通过调用Context.StartService(Intent)发送请求,服务根据需要启动,使用工作线程依次处理每个Intent,并在处理完所有工作后自身停止服务。

使用时,扩展IntentService并实现onHandleIntent(android.content.Intent)。IntentService接收Intent,启动工作线程,并在适当时机停止服务。

所有的请求都在同一个工作线程上处理,一次处理一个请求,所以处理完所以的请求可能会花费很长的时间,但由于IntentService是另外创建的线程来工作,所以保证不会阻止App的主线程。

4.2 IntentService与Service的区别

从何时使用,触发方法,运行环境,何时停止四个方面分析。

1、何时使用:

Service用于没有UI工作的任务,但不能执行长任务(长时间的任务),如果需要Service来执行长时间的任务,则必须手动开启一个线程来执行该Service。

IntentService可用于执行不与主线程沟通的长任务。

2、触发方法:

Service通过调用 startService() 方法来触发。

而IntentService通过Intent来触发,开启一个新的工作线程,并在线程上调用 onHandleIntent() 方法。

3、运行环境:

Service 在App主线程上运行,没有与用户交互,即在后台运行,如果执行长时间的请求任务会阻止主线程工作。

IntentService在自己单独开启的工作线程上运行,即使执行长时间的请求任务也不会阻止主线程工作。

4、何时停止

如果执行了Service,我们是有责任在其请求任务完成后关闭服务,通过调用 stopSelf() 或 stopService()来结束服务。

IntentService会在执行完所有的请求任务后自行关闭服务,所以我们不必额外调用 stopSelf() 去关闭它。

4.3 IntentService例子Demo

Android Service &amp; IntentService学习总结1. Service介绍2. Service生命周期3. 自定义Service例子4. IntentService

通过Android Studio来创建我们的MyIntentService。

public class MyIntentService extends IntentService {

    private static final String TAG = "MyIntentService";
    public static final String DOWNLOAD_ACTION = "DOWNLOAD_ACTION";
    public static final String READ_ACTION = "READ_ACTION";
    public static final String TEST_AUTHOR = "TEST_AUTHOR";

    public MyIntentService() {
        super("MyIntentService");
    }

    /**
     * 进行一些耗时操作
     * @param intent 通过startService(Intent intent)方法传入
     */
    @Override
    protected void onHandleIntent(Intent intent) {
        Log.e(TAG, "onHandleIntent: ");
        if (intent != null) {
            final String action = intent.getAction();
            String author = intent.getExtras().getString(TEST_AUTHOR);
            //模拟下载动作
            if (DOWNLOAD_ACTION.equals(action)) {
                for (int i = 0; i < 5; i++) {
                    try {
                        //线程等待1s,模拟耗时操作
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Log.e(TAG, author + " " + action + " " + i);
                }
            }
            //模拟读操作
            if (READ_ACTION.equals(action)) {
                for (int i = 0; i < 5; i++) {
                    try {
                        //线程等待2s,模拟耗时操作
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Log.e(TAG, author + " " + action + " " + i);
                }
            }
        }

    }

    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show();
        Log.e(TAG, "onCreate: ");
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show();
        Log.e(TAG, "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy: ");
        Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show();
    }
}
           

如果你是手动创建IntentService的,得在AndroidManifest.xml文件中注册该IntentService,如果通过Android Studio创建则免去这一步了。

<service
    android:name=".intentservice.MyIntentService"
    android:exported="false">
</service>
           

在主线程中通过调用 startService(Intent) 方法,发送请求给 Service。

public class IntentServiceActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_intent_service);

        //模拟 Jere 做下载动作
        Intent intent = new Intent(this, MyIntentService.class);
        intent.setAction(MyIntentService.DOWNLOAD_ACTION);
        intent.putExtra(MyIntentService.TEST_AUTHOR, "Jere");
        startService(intent);

        //模拟 James 做读取动作
        Intent jamesIntent = new Intent(this, MyIntentService.class);
        jamesIntent.setAction(MyIntentService.READ_ACTION);
        jamesIntent.putExtra(MyIntentService.TEST_AUTHOR, "James");
        startService(jamesIntent);
    }
}
           

打印 Log 信息如下所示: 

Android Service &amp; IntentService学习总结1. Service介绍2. Service生命周期3. 自定义Service例子4. IntentService

IntentService 的执行顺序是: onCreate() -> onStartCommand() -> onStart() -> onHandleIntent() -> ··· 执行完所有请求 ··· -> onDestroy()。

END~