Service的使用

轉載請標明出處:http://blog.csdn.net/wu_wxc/article/details/51377512
本文出自【吳孝城的CSDN博客】

關於Service的生命週期,可以看:Services的生命週期

IntentService

如果程序不需要同時處理多個請求,IntentService將是最好的選擇。

可以啓動IntentService多次,每一次耗時操作都會以隊列的形式在IntentService的onHandleIntent回調方法中執行,每次只執行一個工作線程,執行完再執行下一個。這種單線程形式保證了主線程(UI線程)不會被阻塞

處理完所有的啓動請求後,IntentService會自動停止服務,所以不需要調用stopSelf()來停止服務。

提供缺省的onBind()實現代碼,因爲不提供綁定,所以它返回null。

提供缺省的onStartCommand()實現代碼,它把intent送入工作隊列,稍後會再傳給你的onHandleIntent()實現代碼。

以上所有的步驟匯成一個結果,我們需要做的就是實現onHandleIntent()來完成客戶端提交的任務,還有就是爲服務提供一小段構造方法

以下是一個IntentService的實現例子:

public class MyIntentService extends IntentService {

    //必須實現一個構造方法,且以工作線程名稱作爲參數
    public MyIntentService() {
        super("MyIntentService");
    }

    /**
     * 從缺省的工作空間調用本方法,並用啓動服務的Intent作爲參數
     * 本方法返回後,IntentService會適時終止這個服務
     */
    @Override
    protected void onHandleIntent(Intent intent) {
        // 我們可以在這裏執行一些工作,如下載文件等
    }

}

如果想重寫其他回調方法,要確保調用一下父類的實現代碼以便IntentService能正確處理工作線程的生命週期。
下面程序回調了Service生命週期的其他方法
這裏寫圖片描述
MainActivity.java

package cn.wuxiaocheng.intentservice;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

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

    public void onHandleIntent(View v) {
        startService(new Intent(MainActivity.this, MyIntentService.class));
    }
}
MyIntentService.java
package cn.wuxiaocheng.intentservice;

import android.app.IntentService;
import android.content.Intent;
import android.os.IBinder;

public class MyIntentService extends IntentService {

    //必須實現一個構造方法,且以工作線程名稱作爲參數
    public MyIntentService() {
        super("MyIntentService");
    }

    /**
     * 從缺省的工作空間調用本方法,並用啓動服務的Intent作爲參數
     * 本方法返回後,IntentService會適時終止這個服務
     */
    @Override
    protected void onHandleIntent(Intent intent) {
        //我們可以在這裏執行一些工作,如下載文件等
        try {
            //作爲演示,這裏我讓它休息3秒,然後輸出onHandleIntent
            Thread.sleep(3000);
            System.out.println("onHandleIntent");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onCreate() {
        System.out.println("onCreate");
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void setIntentRedelivery(boolean enabled) {
        super.setIntentRedelivery(enabled);
        System.out.println("setIntentRedelivery");
    }

    @Override
    public IBinder onBind(Intent intent) {
        //不支持綁定,所以返回null
        return null;
    }

    @Override
    public void onDestroy() {
        System.out.println("onDestroy");
        super.onDestroy();
    }
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="cn.wuxiaocheng.intentservice.MainActivity">

    <Button
        android:onClick="onHandleIntent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="onHandleIntent" />
</RelativeLayout>
還有要在配置清單文件裏添加聲明 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cn.wuxiaocheng.intentservice">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

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

</manifest>
其中第19-21行就是

Service

下面說下繼承Service的使用
如果Service需要多線程運行,可以繼承Service來完成每個Intent處理。
對於每一個啓動請求,它都以一個工作線程來完成處理,並且每次只處理一個請求。因爲是自行處理每個onStartCommand()調用,所以可以爲每個請求創建一個新的線程,並立即運行它們,不需要等待前一個請求處理完畢。這就實現了多線程的操作。


來個小例子
這裏寫圖片描述
MainActivity.java
package cn.wuxiaocheng.started;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    private Intent intent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intent = new Intent(MainActivity.this, MyService.class);
    }

    public void startService(View v) {
        startService(intent);
    }

}

MyService.java

package cn.wuxiaocheng.started;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;

public class MyService extends Service {

    private Looper mServiceLooper;
    private ServiceHandler mServiceHandler;

    //程序從線程接收消息
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            // 通常我們在這裏執行一些操作,如下載文件
            // 這裏我們讓它休息3秒
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                //恢復中斷狀態
                Thread.currentThread().interrupt();
            }
            //通過startId來停止服務,這樣我們就不用在處理其他工作的過程中再來停止服務
            stopSelf(msg.arg1);
        }
    }

    @Override
    public void onCreate() {
        // 啓動運行服務的線程
        // 注意要創建一個單獨的線程,因爲服務通常運行於進行的主線程中,我們不想阻塞主線程
        // 還要賦予它後臺服務的保優先級,這樣處理密集的工作就不會干擾我們的UI
        HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
        thread.start();

        // 獲得HandlerThread的Looper的隊列並用於Handler
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
        System.out.println("onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("service starting");

        // 對於每一個請求,都發送一個消息來啓動處理。
        // 同時傳入啓動ID,以便任務完成後我們知道該終止哪一個請求
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        mServiceHandler.sendMessage(msg);

        // 如果我們被殺死,那從這裏返回後被重啓
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        System.out.println("onDestroy");
    }

    @Override
    public IBinder onBind(Intent intent) {
        // 不提供綁定,所有返回null
        return null;
    }
}

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"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="cn.wuxiaocheng.started.MainActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="startService"
        android:text="startService" />
</LinearLayout>

AndroidManifest.xml

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true"></service>
    </application>

</manifest>

onStartCommand()的返回值必須是以下常量之一 START_NOT_STICKY 在onStartCommand()返回後,如果系統kill這個服務,系統不會自動重啓這個服務,直到startService(Intent intent)方法再次被調用。 START_STICKY 如果系統在onStartCommand()後殺死了這個服務,則將重啓並調用onStartCommand(),但不會再次傳入一個intent,而是用null的intent來調用onStartCommand(),如果還有啓動服務的intent未發送完,那麼這些剩下的intent會繼續發送。這適用於媒體播放器(或類似服務),它們不執行命令,但需要一直運行並隨時待命。 START_REDELIVER_INTENT 如果系統在onStartCommand()返回後殺死了服務,則將重建服務並用上一個已送過的intent調用onStartCommand()。任何未發送完的intent也都會依次送入。這適用於那些需要立即恢復工作的活躍服務,比如下載文件。

Started:非綁定服務

package cn.wuxiaocheng.started;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;

public class MyService extends Service {

    public MyService() {
    }

    @Override
    public void onCreate() {
        //線程開始被創建
        System.out.println("onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //啓動線程後執行的內容
        System.out.println("onStartCommand");
        // 服務被殺死看後的表現
        return START_STICKY ;
    }

    @Override
    public void onDestroy() {
        //線程摧毀
        System.out.println("onDestroy");
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        //不允許綁定,所有返回null
        return null;
    }
}

Bound:綁定服務

MyService.java

package cn.wuxiaocheng.bound;

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

public class MyService extends Service {

    IBinder mBinder;      // 客戶端綁定接口
    boolean mAllowRebind; // 聲明是否使用onRebind

    public MyService() {
    }

    @Override
    public void onCreate() {
        //服務被創建
        System.out.println("onCreate");
    }

    @Override
    public IBinder onBind(Intent intent) {
        // 客戶端調用bindService()綁定服務
        return mBinder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        //所有擴客戶端都通過unbindService()解除綁定
        return mAllowRebind;
    }

    @Override
    public void onDestroy() {
        //服務被摧毀
        System.out.println("onDestroy");
    }
}


android:exported
該屬性決定該服務是否能夠被其他應用程序組件調用或跟它交互。值爲true時,能夠被調用或交互,值爲false時,只有同一個應用程序的組件或帶有相同用戶ID的應用程序才能啓動或綁定該服務。

android:enabled
該屬性決定系統是否能實例化這個服務,值爲true時,則能夠被實例化,值爲false時,不能被實例化,默認值爲true

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