Android開發祕籍學習筆記(七)

  該目錄爲有關Android中Service的學習

服務(Service)的簡單介紹:

  服務(Service)是運行在後臺且不與用戶發生任何交互的Android組件。它可以被任意其他組件開啓或停止。當其處於運行狀態時,任何組件都可與它進行綁定。服務也可以自行停止。下面給出幾個概念性場景,幫助理解什麼是服務。

  1. Activity讓用戶可以選擇一組音樂文件,然後啓動一個服務來播放這些文件。播放期間,一個新的Activity被啓動並綁定到這個服務之上,允許用戶變更樂曲或停止播放。
  2. Activity啓動一個服務向網站上傳一組圖片,一個新的Activity被啓動並綁定到服務上,以確定當前正在上傳的文件,並把該圖片顯示在屏幕上。
  3. 廣播接收器接收到一條消息,消息表明用戶拍攝了一張圖片,隨即啓動一個服務以將該圖片上傳到某網站上。然後廣播接收器轉入非活動狀態,並最終殺死以回收內存。但服務會繼續運行,直至上傳完成。最後,服務自動停止。

服務(Service)的生命週期:

  首先Service有兩種狀態:啓動的綁定的。

    啓動的(Started):
  通過startService()啓動的服務處於“啓動的”狀態,一旦啓動,service就在後臺運行,即使啓動它的應用組件已經被銷燬了。通常started狀態的service執行單任務並且不返回任何結果給啓動者。比如當下載或上傳一個文件,當這項操作完成時,service應該停止它本身。即能啓動一個後臺服務。但是不能通信
 綁定的(Bound):
“綁定”狀態的service,通過調用bindService()來啓動,一個綁定的service提供一個允許組件與service交互的接口,可以發送請求、獲取返回結果,還可以通過誇進程通信來交互(IPC)。綁定的service只有當應用組件綁定後才能運行,多個組件可以綁定一個service,當調用unbind()方法時,這個service就會被銷燬了。

 注意事項:

 service與activity一樣都存在與當前進程的主線程中,所以,一些阻塞UI的操作,比如耗時操作不能放在service裏進行,比如另外開啓一個線程來處理諸如網絡請求的耗時操作。如果在service裏進行一些耗CPU和耗時操作,可能會引發ANR警告,這時應用會彈出是強制關閉還是等待的對話框。所以,對service的理解就是和activity平級的,只不過是看不見的,在後臺運行的一個組件,這也是爲什麼和activity同被說爲Android的基本組件。



 生命週期:

 1). 被啓動的服務的生命週期:如果一個Service被某個Activity 調用 Context.startService 方法啓動,那麼不管是否有Activity使用bindService綁定或unbindService解除綁定到該Service,該Service都在後臺運行。如果一個Service被startService 方法多次啓動,那麼onCreate方法只會調用一次,onStart將會被調用多次(對應調用startService的次數),並且系統只會創建Service的一個實例(因此你應該知道只需要一次stopService調用)。該Service將會一直在後臺運行,而不管對應程序的Activity是否在運行,直到被調用stopService,或自身的stopSelf方法。當然如果系統資源不足,android系統也可能結束服務。
 2). 被綁定的服務的生命週期:如果一個Service被某個Activity 調用 Context.bindService 方法綁定啓動,不管調用 bindService 調用幾次,onCreate方法都只會調用一次,同時onStart方法始終不會被調用。當連接建立之後,Service將會一直運行,除非調用Context.unbindService 斷開連接或者之前調用bindService 的 Context 不存在了(如Activity被finish的時候),系統將會自動停止Service,對應onDestroy將被調用。

特別注意:

1、你應當知道在調用 bindService 綁定到Service的時候,你就應當保證在某處調用 unbindService 解除綁定(儘管 Activity 被 finish 的時候綁定會自      動解除,並且Service會自動停止);

2、你應當注意 使用 startService 啓動服務之後,一定要使用 stopService停止服務,不管你是否使用bindService;

3、同時使用 startService 與 bindService 要注意到,Service 的終止,需要unbindService與stopService同時調用,才能終止 Service,不管 startService 與 bindService 的調用順序,如果先調用 unbindService 此時服務不會自動終止,再調用 stopService 之後服務纔會停止,如果先調用 stopService 此時服務也不會終止,而再調用 unbindService 或者 之前調用 bindService 的 Context 不存在了(如Activity 被 finish 的時候)之後服務纔會自動停止;

4、當在旋轉手機屏幕的時候,當手機屏幕在“橫”“豎”變換時,此時如果你的 Activity 如果會自動旋轉的話,旋轉其實是 Activity 的重新創建,因此旋轉之前的使用 bindService 建立的連接便會斷開(Context 不存在了),對應服務的生命週期與上述相同。

5、在 sdk 2.0 及其以後的版本中,對應的 onStart 已經被否決變爲了 onStartCommand,不過之前的 onStart 任然有效。這意味着,如果你開發的應用程序用的 sdk 爲 2.0 及其以後的版本,那麼你應當使用 onStartCommand 而不是 onStart。


 

 Service的簡單實例:

 
 佈局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="start" />

    <Button
        android:id="@+id/end"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="end" />

</LinearLayout>
兩個Button,一個負責開始服務,一個負責關閉服務。
在Activity中則只需給兩個Button添加監聽事件:
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {

	Button start, end;

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

		start = (Button) findViewById(R.id.start);
		end = (Button) findViewById(R.id.end);

		start.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				startService(new Intent(MainActivity.this,MainServive.class));
			}
		});

		end.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				stopService(new Intent(MainActivity.this,MainServive.class));
			}
		});
	}
}

最後是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 MainServive extends Service {

	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}
	
	@Override
	public void onCreate() {
		super.onCreate();
		Toast.makeText(this, "Service created", Toast.LENGTH_SHORT).show();
		Thread initBackground = new Thread(new Runnable() {
			
			@Override
			public void run() {
				play_music();
				Log.i("Did i go to here", "Yes I did"); 
			}
		});
		initBackground.start();
	}
	
	@Override
	public void onDestroy() {
		super.onDestroy();
		Toast.makeText(this, "Service Destoryed", Toast.LENGTH_SHORT).show();
		m_mediaPlayer.stop();
	}
	
	MediaPlayer m_mediaPlayer;
	private void play_music(){
		m_mediaPlayer = MediaPlayer.create(this, R.raw.a);
		try {
			m_mediaPlayer.start();
			Log.i("Did i go to here....", "Yes I did...."); 
			Thread.sleep(400);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}
最後的效果就是點擊Button,會響起一段音樂,而且無論是點擊Home鍵,Back鍵,切換屏幕的方向,音樂仍然照常播放。

 Service和Thread:

1). Thread:Thread 是程序執行的最小單元,它是分配CPU的基本單位。可以用 Thread 來執行一些異步的操作。

2). Service:Service 是android的一種機制,當它運行的時候如果是Local Service,那麼對應的 Service 是運行在主進程的 main 線程上的。如:onCreate,onStart 這些函數在被系統調用的時候都是在主進程的 main 線程上運行的。如果是Remote Service,那麼對應的 Service 則是運行在獨立進程的 main 線程上。因此請不要把 Service 理解成線程,它跟線程半毛錢的關係都沒有!


IntentService的使用:

  Android開發中,我們或許會碰到這麼一種業務需求,一項任務分成幾個子任務,子任務按順序先後執行,子任務全部執行完後,這項任務纔算成功。那麼,利用幾個子線程順序執行是可以達到這個目的的,但是每個線程必須去手動控制,而且得在一個子線程執行完後,再開啓另一個子線程。或者,全部放到一個線程中讓其順序執行。這樣都可以做到,但是,如果這是一個後臺任務,就得放到Service裏面,由於Service和Activity是同級的,所以,要執行耗時任務,就得在Service裏面開子線程來執行。那麼,有沒有一種簡單的方法來處理這個過程呢,答案就是IntentService。
 
什麼是IntentService,IntentService是繼承於Service並處理異步請求的一個類,在IntentService內有一個工作線程來處理耗時操作,啓動IntentService的方式和啓動傳統Service一樣,同時,當任務執行完後,IntentService會自動停止,而不需要我們去手動控制。另外,可以啓動IntentService多次,而每一個耗時操作會以工作隊列的方式在IntentService的onHandleIntent回調方法中執行,並且,每次只會執行一個工作線程,執行完第一個再執行第二個,以此類推。

 在使用IntentService時要注意,一個必須通過調用super("Myname")爲隊列命名的構造函數;另一個是handleIntent方法,在其中對Intent進行反編列並執行查詢。

 其實IntentService就是這樣一類服務:它保持一個它收到的Intent的隊列,並逐個執行他們。它對許多後臺任務(比如對服務器進行輪詢以獲取新信息,或下載大量的數據)而言是個理想的處理者。由於Intent十分靈活,可以在其額外信息中包含任何類型的可打包說對象,所以在其中可以給出的配置信息量也差不多是無限制的。這就允許向IntentService發送非常複雜的查詢,然後讓其做出反應。

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