Android Service & 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(綁定):

左邊是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顯示狀態,效果如下所示:

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會相對複雜些,見下例所示:

具體代碼如下:

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 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 信息如下所示: 

IntentService 的執行順序是: onCreate() -> onStartCommand() -> onStart() -> onHandleIntent() -> ··· 執行完所有請求 ··· -> onDestroy()。

 

 

END~

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章