自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

android四大組件之Service

移動(dòng)開發(fā) Android
Service 是一個(gè)可以在后臺(tái)執(zhí)行長(zhǎng)時(shí)間運(yùn)行操作而不提供用戶界面的應(yīng)用組件。服務(wù)可由其他應(yīng)用組件啟動(dòng),而且即使用戶切換到其他應(yīng)用,服務(wù)仍將在后臺(tái)繼續(xù)運(yùn)行。此外,組件可以綁定到服務(wù),以與之進(jìn)行交互,甚至是執(zhí)行進(jìn)程間通信 (IPC)。

最近因?yàn)檫€沒找到工作所以也趁著現(xiàn)在有時(shí)間,將以前的只是整理下,要不然總?cè)菀走z忘,今天就來講解下Service的用法。作為Android的四大組件之一,其重要性可想而知。在應(yīng)用中我們主要是用來進(jìn)行一些后臺(tái)操作,不需與應(yīng)用UI進(jìn)行交互,執(zhí)行耗時(shí)任務(wù)等。

官方文檔中這樣說:

Service 是一個(gè)可以在后臺(tái)執(zhí)行長(zhǎng)時(shí)間運(yùn)行操作而不提供用戶界面的應(yīng)用組件。服務(wù)可由其他應(yīng)用組件啟動(dòng),而且即使用戶切換到其他應(yīng)用,服務(wù)仍將在后臺(tái)繼續(xù)運(yùn)行。

此外,組件可以綁定到服務(wù),以與之進(jìn)行交互,甚至是執(zhí)行進(jìn)程間通信 (IPC)。 例如,服務(wù)可以處理網(wǎng)絡(luò)事務(wù)、播放音樂,執(zhí)行文件 I/O

或與內(nèi)容提供程序交互,而所有這一切均可在后臺(tái)進(jìn)行。

Service的用途:

1.在后臺(tái)執(zhí)行耗時(shí)操作,但不需要與用戶進(jìn)行交互。2.一個(gè)應(yīng)用暴露出來的一些供其他應(yīng)用使用的功能。

這里需要聲明一點(diǎn),Service是運(yùn)行在主線程中,因而如果需要進(jìn)行耗時(shí)操作或者訪問網(wǎng)絡(luò)等操作,需要在Service中再開啟一個(gè)線程來執(zhí)行(使用IntentService的話則不需要在自己手動(dòng)開啟線程)。

啟動(dòng)Service

啟動(dòng)一個(gè)Service有兩種方式:

  1. Context.startService() 
  1. Context.bindService()  

 

 

 

(圖片截取自官方文檔:https://developer.android.com...)

startService()方式啟動(dòng)Service,我們啟動(dòng)之后是沒有辦法再對(duì)Service進(jìn)行控制的,而且啟動(dòng)之后該Service是一直在后臺(tái)運(yùn)行的,即使它里面的一些代碼執(zhí)行完畢,我們要想終止該Service,就需要在他的代碼里面調(diào)用stopSelf()方法或者直接調(diào)用stopService() 方法。而通過bindService()方法啟動(dòng)的Service,客戶端將獲得一個(gè)到Service的持久連接,客戶端會(huì)獲取到一個(gè)由Service的onBind(Intent)方法返回來的IBinder對(duì)象,用來供客戶端回調(diào)Service中的回調(diào)方法。

我們無論使用那種方法,都需要定義一個(gè)類,讓它繼承Service類,并重寫其中的幾個(gè)方法,如果我們是采用startService()方式啟動(dòng)的話,只需要重寫onCreate() 、onStartCommand(Intent intent, int flags, int startId)、onDestroy()方法即可(其實(shí)我們也可以重寫),而如果采用的是bindService()方法啟動(dòng)的話,我們就需要重寫onCreate() 、onBind(Intent intent)、 onUnbind(Intent intent)方法.注意,作為四大組件之一,Service使用之前要在清單文件中進(jìn)行配置。 

  1. <application> 
  2.        ...... 
  3.        <service 
  4.            android:name=".MyService"
  5.        </service> 
  6.    </application>  

Context.startService()

MyService.java的代碼: 

  1. public class MyService extends Service { 
  2.     public MyService() { 
  3.     } 
  4.  
  5.     @Override 
  6.     public void onCreate() { 
  7.         super.onCreate(); 
  8.  
  9.         Log.i("test","onCrete executed !"); 
  10.     } 
  11.  
  12.     @Override 
  13.     public int onStartCommand(Intent intent, int flags, int startId) { 
  14.  
  15.         Log.i("test","onStartComand executed !"); 
  16.         return super.onStartCommand(intent, flags, startId); 
  17.     } 
  18.  
  19.     @Override 
  20.     public void onDestroy() { 
  21.         super.onDestroy(); 
  22.         Log.i("test","onDestroy executed !"); 
  23.     } 
  24.  

MainActivity.java的代碼如下:

  1. public class MainActivity extends AppCompatActivity implements View.OnClickListener{ 
  2.  
  3.     Button btnStart,btnStop; 
  4.     @Override 
  5.     protected void onCreate(Bundle savedInstanceState) { 
  6.         super.onCreate(savedInstanceState); 
  7.         setContentView(R.layout.activity_main); 
  8.  
  9.         btnStart = (Button) findViewById(R.id.btn_start); 
  10.         btnStop = (Button) findViewById(R.id.btn_stop); 
  11.         btnStart.setOnClickListener(this); 
  12.         btnStop.setOnClickListener(this); 
  13.     } 
  14.  
  15.  
  16.     @Override 
  17.     public void onClick(View view) { 
  18.  
  19.         Intent mIntent = new Intent(MainActivity.this,MyService.class); 
  20.  
  21.         switch (view.getId()){ 
  22.             case R.id.btn_start: 
  23.                 startService(mIntent); 
  24.                 break; 
  25.             case R.id.btn_stop: 
  26.                 stopService(mIntent); 
  27.                 break; 
  28.         } 
  29.     } 
  30.  

主界面就兩個(gè)按鈕,一個(gè)用來啟動(dòng)Service,一個(gè)用來停止Service: 

 

 

 

下面我們先點(diǎn)擊START按鈕,Log信息如下: 

 

可以看出,onCreate()方法先執(zhí)行,然后onStartCommand()方法緊接著執(zhí)行,那么如果我們?cè)俅吸c(diǎn)擊啟動(dòng)按鈕呢?結(jié)果如下圖: 

 

我們可以看到,這次onCreate()方法沒有再執(zhí)行,而是直接執(zhí)行了onStartCommand()方法,這是因?yàn)镾ervice只在***次創(chuàng)建的時(shí)候才執(zhí)行onCreate()方法,如果已經(jīng)創(chuàng)建了,那之后再次調(diào)用startService()啟動(dòng)該Service的時(shí)候,只會(huì)去執(zhí)行onStartCommand()方法方法,而不會(huì)再執(zhí)行onCreate()方法。 

接下來我們點(diǎn)擊停止按鈕,可以看到,onDestroy()方法被執(zhí)行了: 

 

 

 

注意,如果我們不點(diǎn)擊停止按鈕手動(dòng)停止該Service的話,該Service會(huì)一直在后臺(tái)運(yùn)行,即使它的onStartCommand()方法中的代碼已經(jīng)執(zhí)行完畢,在下圖中我們可以看到:

這時(shí)候我們的這個(gè)Service是一直在后臺(tái)執(zhí)行的,即使它的onStartCommand()方法中的代碼已經(jīng)執(zhí)行完了。如果我們想要它自動(dòng)停止的話,可以將onStartCommand()方法中的代碼修改如下:

  1. @Override 
  2.    public int onStartCommand(Intent intent, int flags, int startId) { 
  3.  
  4.        Log.i("test","onStartComand() executed !"); 
  5.        stopSelf(); 
  6.        return super.onStartCommand(intent, flags, startId); 
  7.    }  

Context.bindService()

采用該方法的代碼就稍微比以前的多了,因?yàn)槲覀冃枰诳蛻舳藢?duì)Service進(jìn)行控制,因而會(huì)在MainActivity中創(chuàng)建一個(gè)匿名內(nèi)部類ServiceConnection,然后會(huì)在bindService()方法和unbindService()方法中將其傳入。MyService.java 中的代碼如下: 

  1. public class MyService extends Service { 
  2.     private MyBinder myBinder = new MyBinder(); 
  3.  
  4.     public MyService() { 
  5.     } 
  6.  
  7.     @Override 
  8.     public void onCreate() { 
  9.         super.onCreate(); 
  10.         Log.i("test","onCreate() executed !"); 
  11.     } 
  12.  
  13.     @Override 
  14.     public void onDestroy() { 
  15.         super.onDestroy(); 
  16.         Log.i("test","onDestroy() executed !"); 
  17.     } 
  18.  
  19.     @Override 
  20.     public boolean onUnbind(Intent intent) { 
  21.  
  22.         Log.i("test","onUnbind executed !"); 
  23.         return super.onUnbind(intent); 
  24.     } 
  25.  
  26.     @Override 
  27.     public IBinder onBind(Intent intent) { 
  28.         Log.i("test","onBind() executed !"); 
  29.         return myBinder; 
  30.     } 
  31.  
  32.     class MyBinder extends Binder{ 
  33.         public void startDownload(){ 
  34.  
  35.             Log.i("test""MyBinder中的startDownload() executed !"); 
  36.             // 執(zhí)行具體的下載任務(wù),需開啟一個(gè)子線程,在其中執(zhí)行具體代碼 
  37.         } 
  38.     } 
  39.  

MainActivity.java 的代碼如下: 

  1. public class MainActivity extends AppCompatActivity implements View.OnClickListener{ 
  2.  
  3.     Button btnBind,btnUnBind; 
  4.     MyService.MyBinder myBinder ; 
  5.     @Override 
  6.     protected void onCreate(Bundle savedInstanceState) { 
  7.         super.onCreate(savedInstanceState); 
  8.         setContentView(R.layout.activity_main); 
  9.  
  10.         btnBind = (Button) findViewById(R.id.bind); 
  11.         btnUnBind = (Button) findViewById(R.id.btn_unBind); 
  12.         btnBind.setOnClickListener(this); 
  13.         btnUnBind.setOnClickListener(this); 
  14.  
  15.     } 
  16.  
  17.     ServiceConnection mServiceConnection = new ServiceConnection() { 
  18.         @Override 
  19.         public void onServiceConnected(ComponentName componentName, IBinder iBinder) { 
  20.             // 將IBinder向下轉(zhuǎn)型為我們的內(nèi)部類MyBinder 
  21.             myBinder = (MyService.MyBinder) iBinder; 
  22.             // 執(zhí)行下載任務(wù) 
  23.             myBinder.startDownload(); 
  24.         } 
  25.  
  26.         @Override 
  27.         public void onServiceDisconnected(ComponentName componentName) { 
  28.  
  29.         } 
  30.     }; 
  31.  
  32.     @Override 
  33.     public void onClick(View view) { 
  34.  
  35.         Intent mIntent = new Intent(MainActivity.this,MyService.class); 
  36.  
  37.         switch (view.getId()){ 
  38.             case R.id.bind: 
  39.                 // 綁定Service 
  40.                 bindService(mIntent,mServiceConnection,BIND_AUTO_CREATE); 
  41.                 break; 
  42.             case R.id.btn_unBind: 
  43.                 // 取消綁定Service 
  44.                 unbindService(mServiceConnection); 
  45.                 break; 
  46.         } 
  47.     } 
  48.  

點(diǎn)擊綁定按鈕; 

 

點(diǎn)擊取消綁定按鈕: 

 

注意,如果我們沒有先點(diǎn)擊綁定,而是直接點(diǎn)擊的取消綁定,程序會(huì)直接crash,報(bào)以下錯(cuò)誤: 

  1. java.lang.IllegalArgumentException: Service not registered: com.qc.admin.myserializableparceabledemo.MainActivity$1@8860e28 
  2.  at android.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:1120) 
  3.  at android.app.ContextImpl.unbindService(ContextImpl.java:1494) 
  4.  at android.content.ContextWrapper.unbindService(ContextWrapper.java:616) 
  5.  at com.qc.admin.myserializableparceabledemo.MainActivity.onClick(MainActivity.java:71)  

 

 

 

細(xì)心的你也許早就發(fā)現(xiàn)了,Log中并沒有打印"onServiceDisconnected executed !"這句,也就是說沒有調(diào)用onServiceDisconnected()方法?從字面理解,onServiceConnected()方法是在Service建立連接的時(shí)候調(diào)用的,onServiceDisconnected()不就應(yīng)該是在Service斷開連接的時(shí)候調(diào)用的嗎?其實(shí)不然,我們查看該方法的文檔就知道了:

Called when a connection to the Service has been lost. This typically happens when the process hosting the service has crashed or been killed. This does not remove the ServiceConnection itself -- this binding to the service will remain active, and you will receive a call to onServiceConnected(ComponentName, IBinder) when the Service is next running.

意思就是:當(dāng)綁定到該Service的連接丟失的時(shí)候,該方法會(huì)被調(diào)用,典型的情況就是持有該Service的進(jìn)程crash掉了,或者被殺死了。但是這并不會(huì)移除ServiceConnection 自身--它仍然是保持活躍狀態(tài),當(dāng)Service下次被執(zhí)行的時(shí)候,onServiceConnected(ComponentName, IBinder) 方法仍然會(huì)被調(diào)用。

但是要注意,如果我們按照剛才說的,不是先點(diǎn)擊 bindService()方法,而是直接點(diǎn)擊unbindService()方法,程序雖然也是crash掉了,但onServiceDisconnected()方法并不會(huì)被調(diào)用,這個(gè)很容易理解,畢竟都沒有建立連接呢,談何斷開連接啊。但是如果我們已經(jīng)綁定了Service,然后在后臺(tái)直接終止該Service呢?結(jié)果會(huì)怎樣?答案是onServiceDisconnected()方法仍然不會(huì)調(diào)用。這里我覺得應(yīng)該是只有在意外的情況下進(jìn)程結(jié)束,是由系統(tǒng)自動(dòng)調(diào)用的,而非我們手動(dòng)停止的。我們可以查看該方法內(nèi)部的注釋:

This is called when the connection with the service has been

unexpectedly disconnected -- that is, its process crashed.Because it

is running in our same process, we should never see this happen.

這段文字清楚的說明了該方法執(zhí)行的場(chǎng)景:異常情況下導(dǎo)致斷開了連接。也就是進(jìn)程crash掉了。因?yàn)樗\(yùn)行在我們應(yīng)用程序所在的進(jìn)程中,因而我們將永遠(yuǎn)不希望看到這種情況發(fā)生。

Context.startService()和Context.bindService()同時(shí)使用

這兩種方式是可以同時(shí)使用的,但是要注意,startService()和stopService()方法是對(duì)應(yīng)的,而bindService()和unBind()方法是對(duì)應(yīng)的,也就是說如果我們先調(diào)用startService()之后調(diào)用bindService()方法,或者相反,那么我們?nèi)绻徽{(diào)用stopService()或者只調(diào)用bindService()都無法停止該Service,只有同時(shí)調(diào)用才可以。

下面來看下具體代碼:

MainActivity.java 

  1. public class MainActivity extends AppCompatActivity implements View.OnClickListener{ 
  2.  
  3.     Button btnStart,btnStop,btnBind,btnUnBind; 
  4.     MyService.MyBinder myBinder ; 
  5.     @Override 
  6.     protected void onCreate(Bundle savedInstanceState) { 
  7.         super.onCreate(savedInstanceState); 
  8.         setContentView(R.layout.activity_main); 
  9.  
  10.         btnStart = (Button) findViewById(R.id.btn_start); 
  11.         btnStop = (Button) findViewById(R.id.btn_stop); 
  12.         btnBind = (Button) findViewById(R.id.btn_bind); 
  13.         btnUnBind = (Button) findViewById(R.id.btn_unBind); 
  14.  
  15.         btnStart.setOnClickListener(this); 
  16.         btnStop.setOnClickListener(this); 
  17.         btnBind.setOnClickListener(this); 
  18.         btnUnBind.setOnClickListener(this); 
  19.  
  20.     } 
  21.  
  22.     ServiceConnection mServiceConnection = new ServiceConnection() { 
  23.         @Override 
  24.         public void onServiceConnected(ComponentName componentName, IBinder iBinder) { 
  25.             // 將IBinder向下轉(zhuǎn)型為我們的內(nèi)部類MyBinder 
  26.             myBinder = (MyService.MyBinder) iBinder; 
  27.             // 執(zhí)行下載任務(wù) 
  28.             myBinder.startDownload(); 
  29.  
  30.         } 
  31.  
  32.         @Override 
  33.         public void onServiceDisconnected(ComponentName componentName) { 
  34.  
  35.             Log.i("test","onServiceDisconnected executed !"); 
  36.         } 
  37.     }; 
  38.  
  39.     @Override 
  40.     public void onClick(View view) { 
  41.  
  42.         Intent mIntent = new Intent(MainActivity.this,MyService.class); 
  43.  
  44.         switch (view.getId()){ 
  45.             case R.id.btn_start: 
  46.                 // 啟動(dòng)Service 
  47.                 startService(mIntent); 
  48.                 break; 
  49.             case R.id.btn_stop: 
  50.                 // 終止Service 
  51.                 stopService(mIntent); 
  52.                 break; 
  53.             case R.id.btn_bind: 
  54.                 // 綁定Service 
  55.                 bindService(mIntent,mServiceConnection,BIND_AUTO_CREATE); 
  56.                 break; 
  57.             case R.id.btn_unBind: 
  58.                 // 取消綁定Service 
  59.                 unbindService(mServiceConnection); 
  60.                 break; 
  61.         } 
  62.     } 
  63.  

MyService.java的代碼: 

  1. public class MyService extends Service { 
  2.     private MyBinder myBinder = new MyBinder(); 
  3.  
  4.     public MyService() { 
  5.     } 
  6.  
  7.     @Override 
  8.     public void onCreate() { 
  9.         super.onCreate(); 
  10.         Log.i("test","onCreate() executed !"); 
  11.     } 
  12.  
  13.     @Override 
  14.     public int onStartCommand(Intent intent, int flags, int startId) { 
  15.  
  16.         Log.i("test","onStartComand() executed !"); 
  17.         return super.onStartCommand(intent, flags, startId); 
  18.     } 
  19.  
  20.     @Override 
  21.     public void onDestroy() { 
  22.         super.onDestroy(); 
  23.         Log.i("test","onDestroy() executed !"); 
  24.     } 
  25.  
  26.     @Override 
  27.     public boolean onUnbind(Intent intent) { 
  28.  
  29.         Log.i("test","onUnbind executed !"); 
  30.         return super.onUnbind(intent); 
  31.     } 
  32.  
  33.     @Override 
  34.     public IBinder onBind(Intent intent) { 
  35.         Log.i("test","onBind() executed !"); 
  36.         return myBinder; 
  37.     } 
  38.  
  39.     class MyBinder extends Binder{ 
  40.         public void startDownload(){ 
  41.  
  42.             Log.i("test""MyBinder中的startDownload() executed !"); 
  43.             // 執(zhí)行具體的下載任務(wù) 
  44.         } 
  45.     } 
  46.  

a.下面是依次點(diǎn)擊start、bind、stop、unBind 按鈕的輸出結(jié)果: 

 

 

 

b.下面是依次點(diǎn)擊start、bind、unbind、stop 按鈕時(shí)的輸出結(jié)果: 

 

 

 

在前臺(tái)運(yùn)行服務(wù)

我們上面一直說Service一般是用來在后臺(tái)執(zhí)行耗時(shí)操作,但是要知道,Service也是可以運(yùn)行在前臺(tái)的。后臺(tái)Service的優(yōu)先級(jí)比較低,容在內(nèi)存不足等情況下被系統(tǒng)殺死,通過將其設(shè)置為前臺(tái),可以大大降低其被殺死的機(jī)會(huì)。前臺(tái)Service會(huì)在系統(tǒng)通知欄顯示一個(gè)圖標(biāo),我們可以在這里進(jìn)行一些操作。前臺(tái)Service比較常見的場(chǎng)景有音樂播放器和天氣預(yù)報(bào)等: 

 

 

 

那么接下來我們就直接上代碼: 

  1. @Override 
  2.     public void onCreate() { 
  3.         super.onCreate(); 
  4.         Log.i("test""onCreate() executed !"); 
  5.  
  6.         Intent mIntent = new Intent(this, SecondActivity.class); 
  7.         PendingIntent mPendingIntent = PendingIntent.getActivity(this, 0, mIntent, 0); 
  8.         Notification mNotification = new NotificationCompat.Builder(this) 
  9.                 .setSmallIcon(R.mipmap.ic_launcher) 
  10.                 .setContentTitle("My Notification "
  11.                 .setContentText("Hello World ! "
  12.                 .setContentIntent(mPendingIntent) 
  13.                 .build(); 
  14.  
  15.         // 注意:提供給 startForeground() 的整型 ID 不得為 0。 
  16.         // 要從前臺(tái)移除服務(wù),請(qǐng)調(diào)用 stopForeground()。此方法采用一個(gè)布爾值,指示是否也移除狀態(tài)欄通知。 
  17.         // 然而stopForeground()不會(huì)停止服務(wù)。 但是,如果您在服務(wù)正在前臺(tái)運(yùn)行時(shí)將其停止,則通知也會(huì)被移除。 
  18.         startForeground(1, mNotification); 
  19.     }  

其實(shí)這里的實(shí)現(xiàn)很簡(jiǎn)單,就是將一個(gè)Notification通過startForeground(1, mNotification);傳進(jìn)去,從而將Notification與 Service建立起關(guān)聯(lián)。我們點(diǎn)擊這個(gè)通知,就會(huì)跳轉(zhuǎn)到第二個(gè)Activity(但是該Notification并不會(huì)消失),截圖如下:

 

責(zé)任編輯:龐桂玉 來源: segmentfault
相關(guān)推薦

2014-07-31 10:57:15

Android組件Service

2013-01-10 14:21:24

Android開發(fā)組件Activities

2014-03-27 15:34:55

Android組件Activity

2014-03-27 15:57:45

Android組件Activity

2010-08-05 10:22:46

Flex效果

2015-07-17 09:50:16

Carthage優(yōu)劣比較

2024-12-30 11:24:56

APMZipkinPinpoint

2010-11-03 11:10:04

AndroidiPhone

2012-02-08 13:52:30

云計(jì)算

2010-08-17 09:20:28

DIV布局

2017-12-08 14:26:19

Android面試知識(shí)點(diǎn)總結(jié)

2015-10-22 10:48:47

Android四大組件攔截

2011-03-21 09:01:49

CSS框架

2009-08-28 10:47:46

Java EE容器

2013-01-06 10:44:43

微軟Windows 8云計(jì)算

2016-03-30 11:51:55

2013-05-20 08:56:13

2021-08-10 20:41:33

AndroidApp流程

2017-03-03 10:10:44

Linux進(jìn)程管理基礎(chǔ)知識(shí)

2019-01-23 16:13:02

大數(shù)據(jù)數(shù)據(jù)處理數(shù)據(jù)挖掘
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)