Android中Services簡析


      Services是Android中四大基礎組件(Activities、 Services、 Content Providers、 BroadCast Receivers)之一,主要用於在后台長時間運行操作,不提供界面,如音樂播放器,關閉界面后還能繼續播放。當頁面需要交互時用線程。

      創建Services,繼承Service,復寫里面的方法,用日志顯示運行過程:

package com.example.androidservice;

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

public class MyService extends Service {

    private static final String TAG="TestTag";
    
    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void onCreate() {
        Log.i(TAG, "onCreate");
        super.onCreate();
    }

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

    @Override
    public void onDestroy() {
        Log.i(TAG, "onDestroy");
        super.onDestroy();
    }

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

}

服務生命周期context.startService() ->onCreate()- >onStart()- >onStartCommand()->Service running ->context.stopService()  ->onDestroy() ->Service stop

如果Service還沒有運行,則android先調用onCreate()然后調用onStartCommand(),每次調用startService(Intent)的時候,都會調用執行onStartCommand();
如果Service已經運行,則只調用onStartCommand()。 

 

我們要執行操作可在onStartCommand方法中定義,onStartCommand有4種返回值: 

        START_STICKY:如果service進程被kill掉,保留service的狀態為開始狀態,但不保留遞送的intent對象。隨后系統會嘗試重新創建service,由於服務狀態為開始狀態,所以創建服務后一定會調用onStartCommand(Intent,int,int)方法。如果在此期間沒有任何啟動命令被傳遞到service,那么參數Intent將為null。

        START_NOT_STICKY:“非粘性的”。使用這個返回值時,如果在執行完onStartCommand后,服務被異常kill掉,系統不會自動重啟該服務。

         START_REDELIVER_INTENT:重傳Intent。使用這個返回值時,如果在執行完onStartCommand后,服務被異常kill掉,系統會自動重啟該服務,並將Intent的值傳入。

         START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保證服務被kill后一定能重啟。

創建頁面用來啟動Services,布局:

<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"
    tools:context=".AndroidServiceActivity" >

    <Button
        android:id="@+id/btnStart"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="開始" >
    </Button>

    <Button
        android:id="@+id/btnStop"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="結束" >
    </Button>

</LinearLayout>

開始結束綁定事件,startService來啟動服務(調用者與服務之間沒有聯系,調用都關閉不影響服務運行),stopService來停止服務,注意其參數為Intent對象,所以可以可以通過些Intent傳遞一些參數給Service,Service可以通過Intent來接收:

package com.example.androidservice;

import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class AndroidServiceActivity extends Activity {

    private Button btnStart;
    private Button btnStop;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_android_service);
        btnStart=(Button)this.findViewById(R.id.btnStart);
        btnStop=(Button)this.findViewById(R.id.btnStop);
        btnStart.setOnClickListener(listener);
        btnStop.setOnClickListener(listener);
    }
    
    private OnClickListener listener=new OnClickListener() {
        
        @Override
        public void onClick(View v) {
            Intent intent=new Intent(AndroidServiceActivity.this,MyService.class);
            switch(v.getId()){
            case R.id.btnStart:
                startService(intent);
                break;
            case R.id.btnStop:
                stopService(intent);
                break;
            }
            
        }
    };


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_android_service, menu);
        return true;
    }

}

最后在manifest.xml中添加節點<service android:name=".MyService" />與AndroidServiceActivity的Activity節點同級。

 

還有一種是用bindService()來啟動,通過服務鏈接(ServiceConnection)或直接獲取Service中狀態和數據信息 
服務鏈接能夠獲取Service的對象,因此綁定Service的組件可以調用Service中的實現的函數 
使用Service的組件通過Context.bindService()建立服務鏈接,通過Context.unbindService()停止服務鏈接 
如果在綁定過程中Service沒有啟動,Context.bindService()會自動啟動Service 
同一個Service可以綁定多個服務鏈接,這樣可以同時為多個不同的組件提供服務

 創建BindService繼承Service,擴展Binder類聲明方法getBindService返回BindService,以便調用自定義方法ShowLog()

 

package com.example.androidservice;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class BindService extends Service {

    private static final String TAG="BindService";
    
    private BindServiceX myBinderServiceX=new BindServiceX();
    public class BindServiceX extends Binder{
        public BindService getBindService() {
            return BindService.this;
        }
    }

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return myBinderServiceX;
    }
    
    @Override
    public void onCreate() {
        Log.i(TAG, "onCreate");
        super.onCreate();
    }

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

    @Override
    public void onDestroy() {
        Log.i(TAG, "onDestroy");
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }
    
    public void ShowLog(){
        Log.i(TAG, "BindService=>ShowLog");
    }

}

Manifest.xml文件中聲明<service android:name=".BindService" />

界面添加啟動停止按鈕:

<Button
        android:id="@+id/btnStartBindService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="開始BindService" >
    </Button>

    <Button
        android:id="@+id/btnStopBindService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="結束BindService" >
    </Button>

AndroidServiceActivity綁定方法,Context.BIND_AUTO_CREATE表明只要綁定存在,就自動建立Service;同時也告知Android系統,這個Service的重要程度與調用者相同,除非考慮終止調用者,否則不要關閉這個Service。

如果service沒被創建,那么調用一次onCreate(),然后調用onBind(),多次綁定時,不會多次調用onBind()。

通過unbindService()函數取消綁定Servcie時,onUnbind()函數將被調用, 
如果onUnbind()函數的返回true,則表示在調用者綁定新服務時, 
onRebind()函數將被調用

取消綁定僅需要使用unbindService()方法,並將ServiceConnnection傳遞給unbindService()方法需注意的是,unbindService()方法成功后,系統並不會調用onServiceDisconnected(),因為onServiceDisconnected()僅在意外斷開綁定時才被調用

當bindService后,不能stopService,需要通過unBindService()來解除綁定

startService()后,不可以通過unBindService()來銷毀service

private boolean isConn = false;//用來標志服務是否綁定
private
OnClickListener listener = new OnClickListener() { @Override public void onClick(View v) { Intent intentBind = new Intent(AndroidServiceActivity.this, BindService.class); switch (v.getId()) { case R.id.btnStartBindService: bindService(intentBind, conn, Context.BIND_AUTO_CREATE); break; case R.id.btnStopBindService: if (isConn) { unbindService(conn); //不可以多次調用 isConn=false; } break; } } };

聲明conn,用來連接服務,調用服務的方法。

private ServiceConnection conn = new ServiceConnection() {

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

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            BindServiceX bindServiceX = (BindServiceX) service;
            BindService bindService = bindServiceX.getBindService();
            bindService.ShowLog();
            isConn=true;
        }
    };

bindService()目的是回調onBind()方法,它的作用是在Service和調用者之間建立一個橋梁,並不負責更多的工作(例如一個Service需要連接服務器的操作),一般使用bindService來綁定到一個現有的Service(即通過StartService啟動的服務),Activity 與 Service傳遞數據和調用接口。

 

以上兩種使用方法並不是完全獨立的,在某些情況下可以混合使用以MP3播放器為例,在后台的工作的Service通過Context.startService()啟動某個特定音樂播放,但在播放過程中如果用戶需要暫停音樂播放,則需要通過Context.bindService()獲取服務鏈接和Service對象,進而通過調用Service的對象中的函數,暫停音樂播放過程,並保存相關信息。在這種情況下,如果調用Context.stopService()並不能夠停止Service,需要在所有的服務鏈接關閉后,Service才能夠真正的停止


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM