服務的基本用法

  • 服務(Service)是 Android 中實現(xiàn)程序后臺運行的解決方案戏羽,它非常適合用于去執(zhí)行那些不需要和用戶交互而且還要求長期運行的任務。
  • 服務并不是運行在一個獨立的進程當中的刀荒,而是依賴于創(chuàng)建服務時所在的應用程序進程首懈。當某個應用程序進程被殺掉時看成,所有依賴于該進程的服務也會停止運行。
  • 服務并不會自動開啟線程鹏秋,所有的代碼都是默認運行在主線程當中的尊蚁。也就是說,我們需要在服務的內(nèi)部手動創(chuàng)建子線程侣夷,并在這里執(zhí)行具體的任務横朋。

一、定義服務


public class MyService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}
  • **onBind() **方法百拓,用于活動和服務進行通信琴锭。
  • **onCreate() **方法會在服務創(chuàng)建的時候調用。
  • **onStartCommand() **方法會在每次服務啟動的時候調用衙传。
  • **onDestroy() **方法會在服務銷毀的時候調用决帖。
  • 需要在 AndroidManifest.xml 文件中進行注冊:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.servicetest"
    android:versionCode="1"
    android:versionName="1.0" >
......
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
......
        <service android:name=".MyService" >
        </service>

    </application>
</manifest>

二、啟動和停止服務


1. 創(chuàng)建 Intent蓖捶,再在活動中用 startService() 方法啟動服務地回。
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent); // 啟動服務
  • 服務還未創(chuàng)建過onCreate()俊鱼、**onStartCommand() **兩個方法都會執(zhí)行落君。
  • 服務已經(jīng)創(chuàng)建過,則只有 **onStartCommand() **方法可以得到執(zhí)行了亭引。
2. 創(chuàng)建 Intent,再在活動中用 stopService() 方法停止服務皮获。
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent); // 停止服務
  • 若要服務自己停止焙蚓,只需要在服務類的任何一個位置調用 **stopSelf() **方法就行。

三洒宝、活動和服務進行通信


在 MyService 中:

1. 創(chuàng)建內(nèi)部類 MyBinder 繼承自 Binder购公,里面是活動需要調用的內(nèi)容。
2. 在 MyService 中創(chuàng)建 MyBinder 的實例雁歌。
3. 在 onBind() 方法里返回這個實例 mBinder宏浩。
public class MyService extends Service {
    private DownloadBinder mBinder = new DownloadBinder();
    class DownloadBinder extends Binder {
        public void startDownload() {
            Log.d("MyService", "startDownload executed");
        }
        public int getProgress() {
            Log.d("MyService", "getProgress executed");
            return 0;
        }
    }

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

在 MainActivity 中:

1. 創(chuàng)建 ServiceConnection 的匿名類實例,重寫 onServiceConnected() 方法和 onServiceDisconnected() 方法靠瞎。
  • 這兩個方法分別會在活動與服務成功綁定以及解除綁定的時候調用比庄。
2. 在 onServiceConnected() 方法中求妹,通過向下轉型得到 MyBinder 的實例。
  • 有了這個實例佳窑,可以在活動中根據(jù)具體的場景來調用 MyBinder 中的任何 public 方法制恍。

綁定活動和服務:

1. 創(chuàng)建 Intent。
2. 用 bindService() 方法綁定活動和服務神凑。
  • 第一個參數(shù):Intent净神。
  • 第二個參數(shù):ServiceConnection 的實例
  • 第三個參數(shù):這里傳入** BIND_AUTO_CREATE** 表示在活動和服務進行綁定后自動創(chuàng)建服務溉委,即執(zhí)行 onCreate() 方法鹃唯。
3. 用 unbindService() 方法解除綁定。
  • 參數(shù):ServiceConnection 的實例瓣喊。
public class MainActivity extends Activity implements OnClickListener {
    private Button startService;
    private Button stopService;
    private Button bindService;
    private Button unbindService;

    private MyService.DownloadBinder downloadBinder;

    private ServiceConnection connection = new ServiceConnection() {

        @Override
            public void onServiceDisconnected(ComponentName name) {
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            downloadBinder = (MyService.DownloadBinder) service;
            downloadBinder.startDownload();
            downloadBinder.getProgress();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ......
        bindService = (Button) findViewById(R.id.bind_service);
        unbindService = (Button) findViewById(R.id.unbind_service);
        bindService.setOnClickListener(this);
        unbindService.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            ......
            case R.id.bind_service:
                Intent bindIntent = new Intent(this, MyService.class);
                bindService(bindIntent, connection, BIND_AUTO_CREATE); // 綁定服務
                break;
            case R.id.unbind_service:
                unbindService(connection); // 解綁服務
                break;
            default:
                break;
        }
    }
}

四坡慌、服務的生命周期


  1. 調用 **startService() 方法,相應的服務就會啟動起來型宝,并回調 onStartCommand() 方法八匠。如果這個服務之前還沒有創(chuàng)建過onCreate() 方法會先于 onStartCommand() **方法執(zhí)行趴酣。
  2. 服務啟動了之后會一直保持運行狀態(tài)梨树,直到 stopService() 或 **stopSelf() **方法被調用。
  3. 還可以調用** bindService() 來獲取一個服務的持久連接岖寞,這時就會回調服務中的 onBind() 方法抡四。如果這個服務之前還沒有創(chuàng)建過onCreate()** 方法會**先于 onBind() **方法執(zhí)行仗谆。
  4. 當調用了** startService() **方法后土匀,又去調用 stopService() 方法,這時服務中的 onDestroy() 方法就會執(zhí)行棱诱,表示服務已經(jīng)銷毀了雕崩。
  5. 當調用了 **bindService() **方法后,又去調用 unbindService() 方法狸吞,onDestroy() 方法也會執(zhí)行勉耀。
  6. 需要注意的是,當對一個服務既調用了 startService() 方法蹋偏,又調用了 bindService() 方法便斥,一個服務只要被啟動或者被綁定了之后,就會一直處于運行狀態(tài)威始,必須要讓以上兩種條件同時不滿足枢纠,服務才能被銷毀。所以黎棠,這種情況下要同時調用 stopService() 和 unbindService() 方法晋渺,onDestroy() 方法才會執(zhí)行镰绎。

五、服務的更多技巧


1. 使用前臺服務

  • 前臺服務會一直有一個正在運行的圖標在系統(tǒng)的狀態(tài)欄顯示些举,下拉狀態(tài)欄后可以看到更加詳細的信息跟狱,非常類似于通知的效果。如天氣應用經(jīng)常要用到户魏。
  • 希望服務可以一直保持運行狀態(tài)驶臊,而不會由于系統(tǒng)內(nèi)存不足的原因導致被回收,就可以考慮使用前臺服務叼丑。
Notification.Builder builder = new Notification.Builder(MainActivity.this);
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentTitle("title");
builder.setContentText("text");
builder.setWhen(System.currentTimeMillis()); // 顯示時間

Intent intent=new Intent(MainActivity.this,Main2Activity.class);
PendingIntent pi=PendingIntent.getActivity(MainActivity.this,0,intent,PendingIntent.FLAG_CANCEL_CURRENT);
builder.setContentIntent(pi);

Notification notification = builder.build();

startForeground(1, notification);

使用很簡單关翎,就是把創(chuàng)建 Notification 方法里的 manager.notify(1, notification); 換成 startForeground(1, notification);

2. 使用 IntentService

  • 服務中的代碼都是默認運行在主線程當中的鸠信,如果直接在服務里去處理一些耗時的邏輯纵寝,就很容易出現(xiàn) ANR(Application Not Responding)的情況。
  • 所以對于一些耗時操作星立,需要在服務中開啟子線程執(zhí)行爽茴。
  • 因為服務啟動后會一直處于開啟狀態(tài),有時也會希望服務在執(zhí)行完畢后自動停止绰垂∈易啵可以這樣寫。
public class MyService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        new Thread(new Runnable() {
            @Override
            public void run() {
                // 處理具體的邏輯
                stopSelf();
            }
        }).start();

        return super.onStartCommand(intent, flags, startId);
    }
}
  • 為了可以簡單地創(chuàng)建一個異步的劲装、會自動停止的服務胧沫,Android 專門提供了一個 IntentService 類:
public class MyIntentService extends IntentService {

    public MyIntentService() {
        super("MyIntentService"); // 調用父類的有參構造函數(shù)
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        // 打印當前線程的id
        Log.d("MyIntentService", "Thread id is " + Thread.currentThread().getId());
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("MyIntentService", "onDestroy executed");
    }
}
  1. 首先要提供一個無參的構造函數(shù),并且必須在其內(nèi)部調用父類的有參構造函數(shù)占业。
  2. 在子類中去實現(xiàn)** onHandleIntent()** 這個抽象方法绒怨,這個方法已經(jīng)是在子線程中運行的了。
  3. 根據(jù) IntentService 的特性谦疾,這個服務在運行結束后應該是會自動停止的南蹂,即執(zhí)行** onDestroy()** 方法。
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末念恍,一起剝皮案震驚了整個濱河市碎紊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌樊诺,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件音同,死亡現(xiàn)場離奇詭異词爬,居然都是意外死亡,警方通過查閱死者的電腦和手機权均,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門顿膨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锅锨,“玉大人,你說我怎么就攤上這事恋沃”馗悖” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵囊咏,是天一觀的道長恕洲。 經(jīng)常有香客問我,道長梅割,這世上最難降的妖魔是什么霜第? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮户辞,結果婚禮上泌类,老公的妹妹穿的比我還像新娘。我一直安慰自己底燎,他們只是感情好刃榨,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著双仍,像睡著了一般枢希。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上殊校,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天晴玖,我揣著相機與錄音,去河邊找鬼为流。 笑死呕屎,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的敬察。 我是一名探鬼主播秀睛,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼莲祸!你這毒婦竟也來了蹂安?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤锐帜,失蹤者是張志新(化名)和其女友劉穎田盈,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缴阎,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡允瞧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片述暂。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡痹升,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出畦韭,到底是詐尸還是另有隱情疼蛾,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布艺配,位于F島的核電站察郁,受9級特大地震影響,放射性物質發(fā)生泄漏妒挎。R本人自食惡果不足惜绳锅,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望酝掩。 院中可真熱鬧鳞芙,春花似錦、人聲如沸期虾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽镶苞。三九已至喳坠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間茂蚓,已是汗流浹背壕鹉。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留聋涨,地道東北人晾浴。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像牍白,于是被迫代替她去往敵國和親脊凰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容