步步爲營_Android開發課[5]_Service學習

Focus on technology, enjoy life!—— QQ:804212028
瀏覽鏈接:http://blog.csdn.net/y18334702058/article/details/44624305


  • 主題:Service服務相關內容
    -Android開發中Service服務是非常重要滴,也是有一定難度滴,不怕,我們一起一步一步來看:

一、 Service簡介

Service是android系統中的四大組件之一(Activity、Service、BroadcastReceiver、ContentProvider),它跟Activity的級別差不多,但不能自己運行只能後臺運行,並且可以和其他組件進行交互。service可以在很多場合的應用中使用,比如播放多媒體的時候用戶啓動了其他Activity這個時候程序要在後臺繼續播放,比如檢測SD卡上文件的變化,再或者在後臺記錄你地理信息位置的改變等等,總之服務總是藏在後臺的。
Service的啓動有兩種方式:context.startService() 和 context.bindService()

二、如何開發一個Service組件?

第一步:繼承Service類 public class SMSService extends Service {}
第二步:在AndroidManifest.xml文件中的節點裏對服務進行配置:
第三步:啓動服務

啓動服務方法一:context.startService():調用者與服務之間沒有關連,即使調用者退出了,服務仍然運行。
步驟:

context.startService() 啓動流程: context.startService() -> onCreate()
-> onStart() -> Service running -> context.stopService() -> onDestroy() -> Service stop

如果Service還沒有運行,則android先調用onCreate(),然後調用onStart();
如果Service已經運行,則只調用onStart(),所以一個Service的onStart方法可能會重複調用多次。
如果stopService的時候會直接onDestroy,如果是調用者自己直接退出而沒有調用stopService的話,Service會一直在後臺運行,該Service的調用者再啓動起來後可以通過stopService關閉Service。
所以調用startService的生命週期爲:onCreate –> onStart (可多次調用) –> onDestroy

啓動服務方法二:context.bindService():調用者與服務綁定在了一起,調用者一旦退出,服務也就終止,大有“不求同時生,必須同時死”的特點

context.bindService()啓動流程: context.bindService() -> onCreate() ->
onBind() -> Service running -> onUnbind() -> onDestroy() ->
Service stop
onBind()將返回給客戶端一個IBind接口實例,IBind允許客戶端回調服務的方法,比如得到Service的實例、運行狀態或其他操作。這個時候把調用者(Context,例如Activity)會和Service綁定在一起,Context退出了,Srevice就會調用onUnbind->onDestroy相應退出。
所以調用bindService的生命週期爲:onCreate –> onBind(只一次,不可多次綁定) –> onUnbind –>
onDestory。
在Service每一次的開啓關閉過程中,只有onStart可被多次調用(通過多次startService調用),其他onCreate,onBind,onUnbind,onDestory在一個生命週期中只能被調用一次。

三、 Service生命週期

Service生命週期很簡單,它只繼承了onCreate()、onStart()、onDestroy()三個方法
當我們第一次啓動Service時,先後調用了onCreate()、onStart()這兩個方法;當停止Service時,則執行onDestroy()方法。
這裏需要注意的是,如果Service已經啓動了,當我們再次啓動Service時,不會在執行onCreate()方法,而是直接執行onStart()方法。
它可以通過Service.stopSelf()方法或者Service.stopSelfResult()方法來停止自己,無論調用了多少次的啓動服務方法,只要調用一次stopService()方法便可以停止服務。

onCreate():
該方法在服務被創建時調用,該方法只會被調用一次,無論調用多少次startService()或bindService()方法,服務也只被創建一次。
onDestroy():
該方法在服務被終止時調用。與採用Context.startService()方法啓動服務有關的生命週期方法
onStart():
只有採用Context.startService()方法啓動服務時纔會回調該方法。該方法在服務開始運行時被調用。多次調用startService()方法儘管不會多次創建服務,但onStart() 方法會被多次調用。
onBind():
只有採用Context.bindService()方法啓動服務時纔會回調該方法。該方法在調用者與服務綁定時被調用,當調用者與服務已經綁定,多次調用Context.bindService()方法並不會導致該方法被多次調用。
onUnbind():
只有採用Context.bindService()方法啓動服務時纔會回調該方法。該方法在調用者與服務解除綁定時被調用

生命週期圖:
這裏寫圖片描述

四:Service和Thread的區別?

答:servie是系統的組件,它由系統進程託管(service manager);它們之間的通信類似於client和server,是一種輕量級的ipc通信,這種通信的載體是binder,它是在linux層交換信息的一種ipc。而thread是由本應用程序託管。

1).Thread:Thread是程序執行的最小單元,它是分配CPU的基本單位。可以用 Thread 來執行一些異步的操作。
2).Service:Service是android的一種機制,當它運行的時候如果是Local Service,那麼對應的 Service 是運行在主進程的 main 線程上的。如:onCreate,onStart 這些函數在被系統調用的時候都是在主進程的 main 線程上運行的。如果是Remote Service,那麼對應的 Service 則是運行在獨立進程的 main 線程上。因此請不要把 Service 理解成線程,它跟線程半毛錢的關係都沒有!

既然這樣,那麼我們爲什麼要用Service呢?

其實這跟android的系統機制有關,我們先拿Thread來說。Thread的運行是獨立於Activity的,也就是說當一個Activity
被finish之後,如果你沒有主動停止Thread或者Thread裏的run方法沒有執行完畢的話,Thread也會一直執行。因此這裏會出現一個問題:當Activity被finish之後,你不再持有該Thread的引用。另一方面,你沒有辦法在不同的
Activity 中對同一 Thread 進行控制。

舉個例子:如果你的 Thread 需要不停地隔一段時間就要連接服務器做某種同步的話,該 Thread 需要在 Activity
沒有start的時候也在運行。這個時候當你 start 一個 Activity 就沒有辦法在該 Activity 裏面控制之前創建的
Thread。因此你便需要創建並啓動一個 Service ,在 Service 裏面創建、運行並控制該
Thread,這樣便解決了該問題(因爲任何 Activity 都可以控制同一 Service,而系統也只會創建一個對應 Service
的實例)。

因此你可以把Service想象成一種消息服務,而你可以在任何有Context的地方調用Context.startService、Context.stopService、Context.bindService,Context.unbindService,來控制它,你也可以在
Service 裏註冊 BroadcastReceiver,在其他地方通過發送 broadcast 來控制它,當然這些都是 Thread
做不到的。

Service使用實例(用Service後臺播放音樂)

main.xml文件的源碼:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <TextView  
       android:layout_width="fill_parent" 
       android:layout_height="wrap_content" 
       android:text="Welcome to Andy's blog!"
       android:textSize="16sp"/>   
    <TextView  
       android:layout_width="fill_parent" 
       android:layout_height="wrap_content" 
       android:text="音樂播放服務"/>
    <Button
       android:id="@+id/startMusic" 
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="開啓音樂播放服務"/>
    <Button
       android:id="@+id/stopMusic" 
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="停止音樂播放服務"/>
   <Button
      android:id="@+id/bindMusic" 
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="綁定音樂播放服務"/>
   <Button
      android:id="@+id/unbindMusic" 
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="解除 ——綁定音樂播放服務"/>
</LinearLayout>

MusicServiceActivity源碼:

package com.example.service;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
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.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class MusicServiceActivity extends Activity {

    //爲日誌工具設置標籤
    private static String TAG = "--------------";

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        //輸出Toast消息和日誌記錄
        Toast.makeText(this, "MusicServiceActivity",
                Toast.LENGTH_SHORT).show();
        Log.e(TAG, "MusicServiceActivity");

        initlizeViews();
    }

    private void initlizeViews(){
        Button btnStart = (Button)findViewById(R.id.startMusic);
        Button btnStop = (Button)findViewById(R.id.stopMusic);
        Button btnBind = (Button)findViewById(R.id.bindMusic);
        Button btnUnbind = (Button)findViewById(R.id.unbindMusic);

        //定義點擊監聽器
        OnClickListener ocl = new OnClickListener() {

            @Override
            public void onClick(View v) {
                //顯示指定  intent所指的對象是個   service
                Intent intent = new Intent(MusicServiceActivity.this,MusicService.class);
                switch(v.getId()){
                case R.id.startMusic:
                    //開始服務
                    startService(intent);
                    break;
                case R.id.stopMusic:
                    //停止服務
                    stopService(intent);
                    break;
                case R.id.bindMusic:
                    //綁定服務
                    bindService(intent, conn, Context.BIND_AUTO_CREATE);
                    break;
                case R.id.unbindMusic:
                    //解綁服務
                    unbindService(conn);
                    break;
                }
            }
        };

         //綁定點擊監聽
        btnStart.setOnClickListener(ocl);
        btnStop.setOnClickListener(ocl);
        btnBind.setOnClickListener(ocl);
        btnUnbind.setOnClickListener(ocl);
    }

    //定義服務鏈接對象
    final ServiceConnection conn = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Toast.makeText(MusicServiceActivity.this, "MusicServiceActivity onSeviceDisconnected"
                    , Toast.LENGTH_SHORT).show();
            Log.e(TAG, "MusicServiceActivity onSeviceDisconnected");
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Toast.makeText(MusicServiceActivity.this, "MusicServiceActivity onServiceConnected"
                    ,Toast.LENGTH_SHORT).show();
            Log.e(TAG, "MusicServiceActivity onServiceConnected");
        }
    };
}

MusicService.java源碼:

package com.example.service;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
public class MusicService extends Service {
    //爲日誌工具設置標籤
    private static String TAG = "--------------";
    //定義音樂播放器變量
    private MediaPlayer mPlayer;

    //該服務不存在需要被創建時被調用,不管startService()還是bindService()都會啓動時調用該方法
    @Override
    public void onCreate() {
        Toast.makeText(this, "MusicSevice onCreate()"
                , Toast.LENGTH_SHORT).show();
        Log.e(TAG, "MusicSerice onCreate()");

        mPlayer = MediaPlayer.create(getApplicationContext(), R.raw.music);
        //設置可以重複播放
        mPlayer.setLooping(true);
        super.onCreate();
    }

    @Override
    public void onStart(Intent intent, int startId) {
        Toast.makeText(this, "MusicSevice onStart()"
                , Toast.LENGTH_SHORT).show();
        Log.e(TAG, "MusicSerice onStart()");

        mPlayer.start();

        super.onStart(intent, startId);
    }
    @Override
    public void onDestroy() {
        Toast.makeText(this, "MusicSevice onDestroy()"
                , Toast.LENGTH_SHORT).show();
        Log.e(TAG, "MusicSerice onDestroy()");

        mPlayer.stop();

        super.onDestroy();
    }
    //其他對象通過bindService 方法通知該Service時該方法被調用
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(this, "MusicSevice onBind()"
                , Toast.LENGTH_SHORT).show();
        Log.e(TAG, "MusicSerice onBind()");

        mPlayer.start();

        return null;
    }
    //其它對象通過unbindService方法通知該Service時該方法被調用
    @Override
    public boolean onUnbind(Intent intent) {
        Toast.makeText(this, "MusicSevice onUnbind()"
                , Toast.LENGTH_SHORT).show();
        Log.e(TAG, "MusicSerice onUnbind()");

        mPlayer.stop();

        return super.onUnbind(intent);
    }

}

最後在AndroidManifest.xml配置文件中添加對Service的註冊

    <service android:name=".MusicService"/> 

就算我們退出程序回到手機主界面,由於該服務還在後臺運行着,音樂還是不會停止播放,這樣我們就可以邊聽歌曲,邊聊QQ了。

Focus on technology, enjoy life!—— QQ:804212028
瀏覽鏈接:http://blog.csdn.net/y18334702058/article/details/44624305

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