淺談Android四大組件之Service

一:Service簡介java

Android開發中,當須要建立在後臺運行的程序的時候,就要使用到Service。android

1:Service(服務)是一個沒有用戶界面的在後臺運行執行耗時操做的應用組件。其餘應用組件可以啓動Service,而且當用戶切換到另外的應用場景,Service將持續在後臺運行。另外,一個組件可以綁定到一個service與之交互(IPC機制),例如,一個service可能會處理網絡操做,播放音樂,操做文件I/O或者與內容提供者(content provider)交互,全部這些活動都是在後臺進行。網絡

 

2:Service有兩種狀態,「啓動的」和「綁定:app

經過startService()啓動的服務處於「啓動的」狀態,一旦啓動,service就在後臺運行,即便啓動它的應用組件已經被銷燬了。一般started狀態的service執行單任務而且不返回任何結果給啓動者。好比當下載或上傳一個文件,當這項操做完成時,service應該中止它自己。ide

 

還有一種「綁定」狀態的service,經過調用bindService()來啓動,一個綁定的service提供一個容許組件與service交互的接口,能夠發送請求、獲取返回結果,還能夠經過誇進程通訊來交互(IPC)。綁定的service只有當應用組件綁定後才能運行,多個組件能夠綁定一個service,當調用unbind()方法時,這個service就會被銷燬了。佈局

 

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

 

二:Service的生命週期spa

Android Service生命週期與Activity生命週期是類似的,可是也存在一些細節上也存在着重要的不一樣:線程

onCreateonStart是不一樣的3d

經過從客戶端調用Context.startService(Intent)方法咱們能夠啓動一個服務。若是這個服務尚未運行,Android將啓動它而且在onCreate方法以後調用它的onStart方法。若是這個服務已經在運行,那麼它的onStart方法將被新的Intent再次調用。因此對於單個運行的Service它的onStart方法被反覆調用是徹底可能的而且是很正常的。

onResumeonPause以及onStop是不須要的

回調一個服務一般是沒有用戶界面的,因此咱們也就不須要onPauseonResume或者onStop方法了。不管什麼時候一個運行中的Service它老是在後臺運行。

onBind

若是一個客戶端須要持久的鏈接到一個服務,那麼他能夠調用Context.bindService方法。若是這個服務沒有運行方法將經過調用onCreate方法去建立這個服務但並不調用onStart方法來啓動它。相反,onBind方法將被客戶端的Intent調用,而且它返回一個IBind對象以便客戶端稍後能夠調用這個服務。同一服務被客戶端同時啓動和綁定是很正常的。

onDestroy

Activity同樣,當一個服務被結束是onDestroy方法將會被調用。當沒有客戶端啓動或綁定到一個服務時Android將終結這個服務。與不少Activity時的狀況同樣,當內存很低的時候Android也可能會終結一個服務。若是這種狀況發生,Android也可能在內存夠用的時候嘗試啓動被終止的服務,因此你的服務必須爲重啓持久保存信息,而且最好在onStart方法內來作。

 

三.Service的啓動方式

Service的啓動方式有以下2種

CstartService()和bindService(),這兩種方式對Service生命週期的影響是不一樣的

startservice是由其餘組件調用startService()方法啓動的,這致使服務的onStartCommand()方法被調用,當服務是started狀態時,其生命週期與啓動它的組件無關,而且能夠在後臺無限期運行,即便啓動服務的組件已經被銷燬。所以,服務須要在完成任務後調用stopself()方法中止,或者有其餘組件調用stopService()方法中止。

使用bindService()方法啓用服務,調用者與服務綁定在了一塊兒,調用者一旦退出,服務也就終止,大有‘不求同生,但求同死’的特色

Android應用中每一個Service都必需要在AndroidMainifest.Xml配置文件中聲明。

 四:2種啓動方式的具體例子

 

startService()方式的生命週期: 
啓動時,startService –> onCreate() –> onStart()

中止時,stopService –> onDestroy()

 

若是調用者直接退出而沒有中止Service,則Service 會一直在後臺運行
 
Context.startService()方法啓動服務,在服務未被建立時,系統會先調用服務的onCreate()方法,接着調用onStart()方法。若是調用startService()方法前服務已經被建立,屢次調用startService()方法並不會致使屢次建立服務,但會致使屢次調用onStart()方法。採用startService()方法啓動的服務,只能調用Context.stopService()方法結束服務,服務結束時會調用onDestroy()方法。

 

startService()方式啓動 Service的方法:

<?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" 
    > 
    <Button 
        android:id="@+id/startBtn" 
        android:layout_width="match_parent" 
        android:layout_height="wrap_content" 
        android:text="啓動 Service" 
        /> 
    <Button 
        android:id="@+id/stopBtn" 
        android:layout_width="match_parent" 
        android:layout_height="wrap_content" 
        android:text="中止 Service" 
        /> 
</LinearLayout> 

MainActivity.java

package com.android.service.activity;  
 
import android.app.Activity;  
import android.content.Intent;  
import android.os.Bundle;  
import android.view.View;  
import android.view.View.OnClickListener;  
import android.widget.Button;  
 
public class MainActivity extends Activity  
{  
    private Button startBtn;  
    private Button stopBtn;  
    @Override 
    public void onCreate(Bundle savedInstanceState)  
    {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        startBtn = (Button) findViewById(R.id.startBtn);  
        stopBtn = (Button) findViewById(R.id.stopBtn);  
        //添加監聽器  
        startBtn.setOnClickListener(listener);  
        stopBtn.setOnClickListener(listener);  
    }  
      
    //啓動監聽器  
    private OnClickListener listener=new OnClickListener()  
    {         
        @Override 
        public void onClick(View v)  
        {  
            Intent intent=new Intent(MainActivity.this, ServiceDemo.class);  
            switch (v.getId())  
            {  
            case R.id.startBtn:  
                startService(intent);  
                break;  
            case R.id.stopBtn:  
                stopService(intent);  
                break;  
            default:  
                break;  
            }             
        }  
    };  
} 

新建ServiceDemo類,ServiceDemo.java以下

package com.android.service.activity;  
 
import android.app.Service;  
import android.content.Intent;  
import android.os.IBinder;  
import android.util.Log;  
 
public class ServiceDemo extends Service  
{  
    private static final String TAG="Test";  
      
    @Override 
    //Service時被調用  
    public void onCreate()  
    {  
        Log.i(TAG, "Service onCreate--->");  
        super.onCreate();  
    }  
 
    @Override 
    //當調用者使用startService()方法啓動Service時,該方法被調用  
    public void onStart(Intent intent, int startId)  
    {  
        Log.i(TAG, "Service onStart--->");  
        super.onStart(intent, startId);  
    }  
 
    @Override 
    //當Service不在使用時調用  
    public void onDestroy()  
    {  
        Log.i(TAG, "Service onDestroy--->");  
        super.onDestroy();  
    }  
 
    @Override 
    //當使用startService()方法啓動Service時,方法體內只需寫return null  
    public IBinder onBind(Intent intent)  
    {  
        return null;  
    }  
}  

在AndroidManifest.xml文件中添加16~21行的聲明

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
      package="com.android.service.activity" 
      android:versionCode="1" 
      android:versionName="1.0"> 
    <uses-sdk android:minSdkVersion="10" /> 
 
    <application android:icon="@drawable/icon" android:label="@string/app_name"> 
        <activity android:name=".MainActivity" 
                  android:label="@string/app_name"> 
            <intent-filter> 
                <action android:name="android.intent.action.MAIN" /> 
                <category android:name="android.intent.category.LAUNCHER" /> 
            </intent-filter> 
        </activity> 
    <service android:name=".ServiceDemo" >    
             <intent-filter> 
                <action android:name="android.intent.action.MAIN" /> 
                <category android:name="android.intent.category.LAUNCHER" /> 
            </intent-filter> 
    </service>    
    </application> 
</manifest> 

效果以下:

當點擊按鈕時,前後執行了Service中onCreate()->onStart()這兩個方法,LogCat顯示以下:

當點擊 按鈕時,Service則執行了onDestroy()方法,LogCat顯示以下:

 

退出後,進入Settings(設置)->Applications(應用)->Running Services(正在運行的服務)看一下咱們新啓動了的服務,效果圖以下:

 

 

 
 
bindService()方式的生命週期: 
綁定時,bindService -> onCreate() –> onBind()
調用者退出了,即解綁定時,Srevice就會unbindService –>onUnbind() –> onDestory()
 
用Context.bindService()方法啓動服務,在服務未被建立時,系統會先調用服務的onCreate()方法,接着調用onBind()方法。這個時候調用者和服務綁定在一塊兒,調用者退出了,系統就會先調用服務的onUnbind()方法,接着調用onDestroy()方法。若是調用bindService()方法前服務已經被綁定,屢次調用bindService()方法並不會致使屢次建立服務及綁定(也就是說onCreate()和onBind()方法並不會被屢次調用)。若是調用者但願與正在綁定的服務解除綁定,能夠調用unbindService()方法,調用該方法也會致使系統調用服務的onUnbind()-->onDestroy()方法。
 bindService()方式啓動 Service的方法:
綁定Service須要三個參數:bindService(intent, conn, Service.BIND_AUTO_CREATE);
第一個:Intent對象
第二個:ServiceConnection對象,建立該對象要實現它的onServiceConnected()和 onServiceDisconnected()來判斷鏈接成功或者是斷開鏈接
第三個:如何建立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" 
    > 
    <Button   
        android:text="啓動Service"   
        android:id="@+id/startBtn1"   
        android:layout_width="match_parent"   
        android:layout_height="wrap_content" 
        />    
    <Button   
        android:text="中止Service"   
        android:id="@+id/stopBtn2"   
        android:layout_width="match_parent"   
        android:layout_height="wrap_content" 
        />    
    <Button   
        android:text="綁定Service"   
        android:id="@+id/bindBtn3"   
        android:layout_width="match_parent"   
        android:layout_height="wrap_content" 
        /> 
    <Button   
        android:text="解除綁定"   
        android:id="@+id/unbindBtn4"   
        android:layout_width="match_parent"   
        android:layout_height="wrap_content" 
        /> 
</LinearLayout> 

MainActivity.java

package com.android.bindservice.activity;  
 
import android.app.Activity;  
import android.app.Service;  
import android.content.ComponentName;  
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;  
 
public class MainActivity extends Activity {  
    // 聲明Button  
    private Button startBtn,stopBtn,bindBtn,unbindBtn;  
    @Override 
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        // 設置當前佈局視圖  
        setContentView(R.layout.main);  
        // 實例化Button  
        startBtn = (Button)findViewById(R.id.startBtn1);  
        stopBtn = (Button)findViewById(R.id.stopBtn2);  
        bindBtn = (Button)findViewById(R.id.bindBtn3);  
        unbindBtn = (Button)findViewById(R.id.unbindBtn4);  
          
        // 添加監聽器  
        startBtn.setOnClickListener(startListener);  
        stopBtn.setOnClickListener(stopListener);  
        bindBtn.setOnClickListener(bindListener);  
        unbindBtn.setOnClickListener(unBindListener);  
          
    }  
    // 啓動Service監聽器  
    private OnClickListener startListener = new OnClickListener() {  
        @Override 
        public void onClick(View v) {  
            // 建立Intent  
            Intent intent = new Intent();  
            // 設置Class屬性  
            intent.setClass(MainActivity.this, BindService.class);  
            // 啓動該Service  
            startService(intent);  
        }  
    };  
      
    // 中止Service監聽器  
    private OnClickListener stopListener = new OnClickListener() {  
        @Override 
        public void onClick(View v) {  
            // 建立Intent  
            Intent intent = new Intent();  
            // 設置Class屬性  
            intent.setClass(MainActivity.this, BindService.class);  
            // 啓動該Service  
            stopService(intent);  
        }  
    };  
      
   // 鏈接對象  
   private ServiceConnection conn = new ServiceConnection() {  
        @Override 
        public void onServiceConnected(ComponentName name, IBinder service) {  
            Log.i("Service", "鏈接成功!");  
        }  
        @Override 
        public void onServiceDisconnected(ComponentName name) {  
            Log.i("Service", "斷開鏈接!");  
        }  
    };  
      
    // 綁定Service監聽器  
    private OnClickListener bindListener = new OnClickListener() {  
        @Override 
        public void onClick(View v) {  
            // 建立Intent  
            Intent intent = new Intent();  
            // 設置Class屬性  
            intent.setClass(MainActivity.this, BindService.class);  
           
            // 綁定Service  
            bindService(intent, conn, Service.BIND_AUTO_CREATE);  
        }  
    };  
          
    // 解除綁定Service監聽器  
    private OnClickListener unBindListener = new OnClickListener() {  
        @Override 
        public void onClick(View v) {  
            // 建立Intent  
            Intent intent = new Intent();  
            // 設置Class屬性  
            intent.setClass(MainActivity.this, BindService.class);  
            // 解除綁定Service  
            unbindService(conn);  
        }  
    };    
} 

BindService.java

package com.android.bindservice.activity;  
 
import android.app.Service;  
import android.content.Intent;  
import android.os.IBinder;  
import android.util.Log;  
 
public class BindService extends Service{  
      
    private static final String TAG="Test";  
      
    //返回null  
    public IBinder onBind(Intent intent) {  
        Log.i(TAG, "Service onBind--->");  
        return null;  
    }  
    // Service建立時調用  
    public void onCreate() {  
        Log.i(TAG, "Service onCreate--->");  
    }  
    // 當客戶端調用startService()方法啓動Service時,該方法被調用  
    public void onStart(Intent intent, int startId) {  
        Log.i(TAG, "Service onStart--->");  
    }  
    // 當Service再也不使用時調用  
    public void onDestroy() {  
        Log.i(TAG, "Service onDestroy--->");  
    }  
    // 當解除綁定時調用  
    public boolean onUnbind(Intent intent) {    
        Log.i(TAG, "Service onUnbind--->");    
        return super.onUnbind(intent);    
    }    
}  

 

在AndroidManifest.xml文件中添加16~21行的聲明

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
      package="com.android.bindservice.activity" 
      android:versionCode="1" 
      android:versionName="1.0"> 
    <uses-sdk android:minSdkVersion="10" /> 
 
    <application android:icon="@drawable/icon" android:label="@string/app_name"> 
        <activity android:name=".MainActivity" 
                  android:label="@string/app_name"> 
            <intent-filter> 
                <action android:name="android.intent.action.MAIN" /> 
                <category android:name="android.intent.category.LAUNCHER" /> 
            </intent-filter> 
        </activity> 
        <service android:name=".BindService" >    
             <intent-filter> 
                <action android:name="android.intent.action.MAIN" /> 
                <category android:name="android.intent.category.LAUNCHER" /> 
            </intent-filter> 
    </service> 
    </application> 
</manifest> 

效果以下:

當點擊按鈕時,前後執行了Service中onCreate()->onStart()這兩個方法,LogCat顯示以下:

當點擊按鈕,則Service執行了onUnbind()方法,LogCat顯示以下:

 

當點擊按鈕,則Service執行了onUnbind()方法,LogCat顯示以下:

相關文章
相關標籤/搜索