知識
不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價值,我們在追求其視覺表現(xiàn)的同時,更側(cè)重于功能的便捷,營銷的便利,運營的高效,讓網(wǎng)站成為營銷工具,讓軟件能切實提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序為后期升級提供便捷的支持!
android學(xué)習(xí)十八(Service服務(wù)的基本用法)
發(fā)表時間:2020-10-19
發(fā)布人:葵宇科技
瀏覽次數(shù):36
定義一個辦事
在項目中定義一個辦事,新建一個ServiceTest項目,然后在這個項目中新增一個名為MyService的類,并讓它持續(xù)自Service,完成后的代碼如下所示:
package com.jack.servicetest; import android.app.Service; import android.content.Intent; import android.os.IBinder; public class MyService extends Service { @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; } }
今朝MyService中只用一個onBind()辦法,這個辦法是Service中獨一的一個抽象辦法,所以必須要在子類誠實現(xiàn)。既然定義了一個辦事,天然應(yīng)當在辦事中去處理一些工作,那邊那邊理工作的邏輯應(yīng)當寫在哪里?這時我們就可以重寫Service中的別的一些辦法了,如下所示:
package com.jack.servicetest; import android.app.Service; import android.content.Intent; import android.os.IBinder; public class MyService extends Service { @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; } @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub return super.onStartCommand(intent, flags, startId); } }
可以看到,這里我們又重寫了onCreate(),onDestroy()和onStartCommand(Intent intent, int flags, int startId)這三個辦法,它們是每個辦事中最常用到的三個辦法。個中onCreate辦法會在辦事創(chuàng)建的時刻調(diào)用,onStartCommand辦法會在每次辦事啟動的時刻調(diào)用。onDestroy()辦法會在辦事燒毀的時刻調(diào)用。
平日情況下,如不雅我們欲望辦事一旦啟動就急速去履行某個動作,就可以將邏輯寫在onStartCommand辦法里。而當辦事燒毀時,我們又應(yīng)當在onDestroy()辦法中去收受接收那些不在應(yīng)用的資本。
別的須要留意的是,沒一個辦事都須要在AndroidManifest.xml文件中進行注冊才能生效,android四大年夜組件都須要進行注冊。于是我們修改AndroidManifest.xml文件,代碼如下所示:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.jack.servicetest" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="13" android:targetSdkVersion="17" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.jack.servicetest.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="com.jack.servicetest.MyService"></service> </application> </manifest>
如許的話,就已經(jīng)將一個辦事定義好了。
啟動和停止辦事
定義好了辦過后,接下來就應(yīng)當推敲若何啟動以及停止這個辦事。啟動辦事和停止辦事重要借助Intent來實現(xiàn),下面我們在ServiceTest項目中測驗測驗去啟動已經(jīng)停止MyService這個辦事。
起首修改activity_main.xml中的代碼,如下所示:
<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" > <Button android:id="@+id/start_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="start service" /> <Button android:id="@+id/stop_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="stop service" /> </LinearLayout>
膳綾擎的構(gòu)造重要參加了2個按鈕,用來啟動和停止辦事。
然后修改MainActivity中的代碼,如下所示:
package com.jack.servicetest; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity implements OnClickListener{ private Button startService; private Button stopService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startService=(Button) findViewById(R.id.start_service); stopService=(Button) findViewById(R.id.stop_service); startService.setOnClickListener(this); stopService.setOnClickListener(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public void onClick(View v) { // TODO Auto-generated method stub switch(v.getId()){ case R.id.start_service: Intent startIntent =new Intent(this,MyService.class); startService(startIntent);//啟動辦事 break; case R.id.stop_service: Intent stopIntent =new Intent(this,MyService.class); stopService(stopIntent);//停止辦事 break; default: break; } } }
膳綾擎我們在onCreate辦法平分別獲取到start service按鈕和stop service按鈕的實例,并給它們注冊了點擊
事宜。然后在start service按鈕的點擊事沂攀瑯綾擎,我們構(gòu)建出了一個Intent對象,并調(diào)用startService()
辦法來啟動MyService這個辦事。在stop service按鈕的點擊事沂攀里,我們同樣構(gòu)建出了一個Intent對象,并調(diào)用
stopService()辦法來停止MyService這個辦事。startService()和stopService()辦法都是定義在Context
類中的,所以我們在晃蕩里可以直接調(diào)用這兩個辦法。留意,這瑯綾搶滿是由晃蕩來決定辦事何時停止的,如不雅沒有點擊stop service
按鈕,辦事就會一向處于運行狀況。那辦事有什么辦法讓本身停下來了?只須要在MyService的任何一個地位調(diào)用shopSelf()
辦法就能讓辦事停止下來了。
接下來我們要推敲,若何才能證實辦事已經(jīng)成功啟動或者停止了?最簡單的辦法就是在MyService的幾個辦法中參加打印日記,如下所示:
package com.jack.servicetest; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.util.Log; public class MyService extends Service { @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; } @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); Log.d("MyService", "onCreate()"); } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.d("MyService", "onDestroy()"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub Log.d("MyService", "onStartCommand"); return super.onStartCommand(intent, flags, startId); } }
如今運行法度榜樣,進行測試,法度榜樣的主界面如下所示:
[img]http://img.blog.csdn.net/20141120211442358?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvajkwMzgyOTE4Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
點擊一下start service按鈕,不雅察logcat打印的日記如下所示:
[img]http://img.blog.csdn.net/20141120211554945?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvajkwMzgyOTE4Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
MyService中的onCreate辦法和onStartCommand辦法都履行了,解釋辦事已經(jīng)成功啟動了,并且可以在正在運行的辦事列表中找到。
在點擊下stop service,不雅察logcat日記的輸出:
[img]http://img.blog.csdn.net/20141120211833644?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvajkwMzgyOTE4Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
由此證實MyService辦事確切已經(jīng)成功停止下來了。
onCreate辦法和onStartCommand辦法的差別:onCreate辦法是在辦事第一次創(chuàng)建的時刻調(diào)用的,而onStartCommand方軌則在每次啟動辦事的時刻都邑調(diào)用,因為剛才我們是第一次點擊start service按鈕,辦事此時還未創(chuàng)建過,所以兩個辦法都邑履行,之后如不雅你在持續(xù)多點擊幾回start service按鈕,你就會發(fā)明只有onStartCommand辦法可以獲得履行了。
晃蕩和辦事進行通信
今朝我們欲望在MyService里供給一個下載的功能,然后再晃蕩中可以決定何時開端下載,以及隨時查看下載進。實現(xiàn)這個功能的思路是創(chuàng)建一個專門的Binder對象來對下載功能進行治理,修改MyService中的代碼:如下所示:
package com.jack.servicetest; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; public class MyService extends Service { private DownloadBinder mBinder=new DownloadBinder(); class DownloadBinder extends Binder{ public void startDownload(){ Log.d("MyService", "startdownload executed"); } public int getProgress(){ Log.d("MyService", "getProgress executed"); return 0; } } @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return mBinder; } @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); Log.d("MyService", "onCreate()"); } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.d("MyService", "onDestroy()"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub Log.d("MyService", "onStartCommand"); return super.onStartCommand(intent, flags, startId); } }
這里我們新建了一個DownloadBinder類,并讓它持續(xù)自Binder,然后再它的內(nèi)部供給開端下載以及查看下載進度的辦法。當然這只是兩個模仿的辦法,并沒有實現(xiàn)真正的功能,我們在這兩個辦法平分別打印了一行日記。
接著,在MyService中創(chuàng)建了DownloadBinder的實例,然后再onBind()辦法里返回了這個實例,如許MyService中的工作就全部完成了。
下面我們須要在晃蕩中調(diào)用辦事里的辦法,起首須要在構(gòu)造文件中新曾兩個按鈕,修改activity_main.xml中的代碼,如下所示:
<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" > <Button android:id="@+id/start_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="start service" /> <Button android:id="@+id/stop_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="stop service" /> <Button android:id="@+id/bind_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="bind service" /> <Button android:id="@+id/unbind_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="unbind service" /> </LinearLayout>
這兩個晃蕩用于在晃蕩中進行綁定和撤消綁定辦事,當一個晃蕩和辦事綁定了之后,就可聲調(diào)用該辦事里的Binder供給的辦法了,修改MainActivity中的代碼,如下所示:
package com.jack.servicetest; import com.jack.servicetest.MyService.DownloadBinder; import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity implements OnClickListener{ private Button startService; private Button stopService; private Button bindService; private Button unbindService; private MyService.DownloadBinder downloadBinder; private ServiceConnection connection=new ServiceConnection() { /* * 這里創(chuàng)建了一個ServiceConnection的匿名類,在這里重寫了onServiceConnected辦法和 * onServiceDisconnected辦法,這兩個辦法分別會在晃蕩與辦事成功綁定以及解除綁定的時刻調(diào)用。 * 在onServiceConnected辦法中,我們又經(jīng)由過程向下轉(zhuǎn)型獲得了DownloadBinder的實例,有了這個 * 實例,晃蕩和辦事之間的關(guān)系就變得異常慎密了,如今我們可以在晃蕩中根據(jù)具體的場景來調(diào)用DownloadBinder * 中的任何public辦法,及實現(xiàn)了批示辦事干什么,辦事就干什么的功能,這里只做了簡單的測試,在onServiceConnected * 中調(diào)用了DownloadBinder的startDownload(),getProgress()辦法。 * */ @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub } @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub downloadBinder=(MyService.DownloadBinder) service; downloadBinder.startDownload(); downloadBinder.getProgress(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startService=(Button) findViewById(R.id.start_service); stopService=(Button) findViewById(R.id.stop_service); startService.setOnClickListener(this); stopService.setOnClickListener(this); bindService = (Button) findViewById(R.id.bind_service); unbindService = (Button) findViewById(R.id.unbind_service); bindService.setOnClickListener(this); unbindService.setOnClickListener(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public void onClick(View v) { // TODO Auto-generated method stub switch(v.getId()){ case R.id.start_service: Intent startIntent =new Intent(this,MyService.class); startService(startIntent);//啟動辦事 break; case R.id.stop_service: Intent stopIntent =new Intent(this,MyService.class); stopService(stopIntent);//停止辦事 break; case R.id.bind_service: /* *如今我們須要進行晃蕩和辦事的綁定,構(gòu)建一個Intent對象,然后調(diào)用bindService()辦法將 *MainActivity()和MyService進行綁定。 bindService辦法接收留個參數(shù),第一個參數(shù)就是 *膳綾擎創(chuàng)建出的Intent對象,第二個參數(shù)就是前面創(chuàng)建出的ServiceConnection的實例,第三個 *參數(shù)則是一個標記位,這里傳入BIND_AUTO_CREATE表示在晃蕩和辦事進行綁定后主動創(chuàng)建辦事。 *這會使得MyService中的onCreate()辦法獲得履行,但onStartCommand()辦法不會履行。 * */ Intent bindIntent=new Intent(this,MyService.class); bindService(bindIntent, connection, BIND_AUTO_CREATE);//綁定辦事 break; case R.id.unbind_service: /* * 如不雅我們想解除晃蕩和辦事之間的綁定,調(diào)用一下unbindService()辦法就可以了。 * */ unbindService(connection);//解綁辦事 break; default: break; } } }
大年夜新運行下法度榜樣,界面如下所示:
[img]http://img.blog.csdn.net/20150105162929487?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvajkwMzgyOTE4Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
點擊以下bind service,然后可以不雅察logcat中打印的日記如下圖所示:
[img]http://img.blog.csdn.net/20150105163058187?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvajkwMzgyOTE4Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
可以看到,起首是MyService的onCreate()辦法獲得了履行,然后startDownload和getProgeress辦法獲得了履行,解釋我們確切已經(jīng)在晃蕩力成功的調(diào)用了辦事里供給的辦法了。別的須要留意的,任何一個辦事在全部應(yīng)用法度榜樣范圍內(nèi)都是通用的,即MyService不僅可以和MainActivity綁定,還可以和任何一個其他的晃蕩進行綁定,并且在綁定完成之后他們都可以獲取到雷同的DownloadBinder實例。
辦事的生命周期
辦事也有本身的生命周期,前面我們應(yīng)用到的onCreate(),onStartCommand(),onBind()和onDestroy()等辦法
都是在辦事的生命周期內(nèi)可能回掉落的辦法。
一旦在項目標任何地位調(diào)用了Context的startService()辦法,響應(yīng)的辦事就會啟動起來,并回調(diào)onStartCommand()。如不雅 這個辦事之前還沒創(chuàng)建過,onCreate()辦法會先于onStartCommand()辦法履行。辦事啟動了之后一向保持運行狀況,
直到stopService()或stopSelf()辦法被調(diào)用。留意固然每調(diào)用一次startService()辦法,onStartCommand()就會
履行一次,但實際膳綾強個辦事都只會存在一個實例。所以不管你調(diào)用了若干次startService()辦法,只需調(diào)用一次stopService()或stopSelf()辦法,辦事就會停止下來了。
別的,還可聲調(diào)用Context的bindService()來獲取一個辦事的持久連接,這時就會回調(diào)辦事中的onBind()辦法。類似地,如不雅這個辦事之前還沒有創(chuàng)建過,onCreate()辦法會先于onBind()辦法履行。之后,調(diào)用方可以獲取到onBind()辦法里返回的IBinder對象的實例,如許就能自由地和辦事進行通信了。只要調(diào)用方和辦事之間的連接沒有斷開,辦事就會一向保持運行狀況。
當調(diào)用了startService()辦法后,又去調(diào)用stopService()辦法,這時辦事中的onDestroy()辦法就會履行,表示
辦事已經(jīng)燒毀了。類似地,當調(diào)用了bindService()辦法后,又去調(diào)用unbindService()辦法,onDestroy()辦法也會履行,這
兩種情況都很好懂得。然則須要留意,我們是完全有可能對一個辦事既調(diào)用了startService()辦法,又調(diào)用了bindService()辦法的,這種情況下該若何才能讓辦事燒毀掉落?根據(jù)android體系的機制,一個辦事只要被啟動或者綁定了之后就會一向處于運行狀況,必須要讓以上兩種前提同時不知足,辦事才能被燒毀。所以,這種情況下須要同時調(diào)用stopService()和unbindService()辦法,onDestroy()辦法才會履行。
應(yīng)用前臺辦事
辦事幾乎都是在后臺運行的,一向以來它都是默默的做著辛苦的工作。然則辦事的體系優(yōu)先級照樣比較低的,當體系出現(xiàn)內(nèi)存不足的情況時,就有可能會收受接收掉履┞俘在后臺運行的辦事。如不雅你欲望辦事可以一向 保持運行狀況,而 不會因為體系內(nèi)存不足的原因?qū)е卤皇帐芙邮眨涂梢酝魄脩?yīng)用前臺辦事。前臺辦事和通俗辦事最大年夜的差別就在于,它會一向有一個正在運行的體系狀況欄顯示,下拉狀況欄后可以看到加倍具體的信息,異常類似于通知的效不雅。
下面我們創(chuàng)建一個前臺辦事吧,修改MyService中的代碼,如下所示:
package com.jack.servicetest; import android.app.Notification; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; public class MyService extends Service { private DownloadBinder mBinder=new DownloadBinder(); class DownloadBinder extends Binder{ public void startDownload(){ Log.d("MyService", "startdownload executed"); } public int getProgress(){ Log.d("MyService", "getProgress executed"); return 0; } } @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return mBinder; } @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); @SuppressWarnings("deprecation") Notification notification=new Notification(R.drawable.ic_launcher, "Notification comes",System.currentTimeMillis()); Intent notificationIntent=new Intent(this,MainActivity.class); PendingIntent pendingIntent=PendingIntent.getActivity(this, 0,notificationIntent, 0); notification.setLatestEventInfo(this, "this is title", "this is content", pendingIntent); startForeground(1, notification); /* 可以看到,這里只是修改了onCreate()辦法中的代碼,信賴這部分代碼你會異常眼熟。這就是我們前面進修的 創(chuàng)建通知的辦法。只不過此次在構(gòu)建出Notification對象并沒有應(yīng)用NotificationManager來精曉知顯示 出來,而是調(diào)用了startForeground()辦法。這個辦法接收兩個參數(shù),第一個參數(shù)是通知的id,類似于notify()辦法 的第一個參數(shù),第二個參數(shù)則是構(gòu)建出來的Notification對象。調(diào)用startForeground()辦法后就會讓MyService變成 一個前臺辦事,并在體系狀況顯示出來。 */ Log.d("MyService", "onCreate()"); } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.d("MyService", "onDestroy()"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub Log.d("MyService", "onStartCommand"); return super.onStartCommand(intent, flags, startId); } }
如今從新運行下法度榜樣,并點擊start service或bind service按鈕,MyService就會以前臺辦事的模式開啟了,并且在體系狀況欄會顯示一個通知擱筆,下拉狀況欄后可以看到該通知的具體內(nèi)容,如下所示:
[img]http://img.blog.csdn.net/20150105172643085?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvajkwMzgyOTE4Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
應(yīng)用IntentService
我們知道辦事中的代碼都是默認運行在主線程傍邊,如不雅直接在辦事里去處理一些耗時的邏輯,就很輕易出現(xiàn)ANR(Application Not Responding)的情況。
所以這個時刻,就須要用到Android多線程編程的技巧了,我們應(yīng)當在辦事的每個具體的辦法里開啟一個子線程,然后再這里去處理那些耗時的邏輯。是以,一個比較標準的辦事就可以寫成如下情勢了:
package com.jack.servicetest; import android.app.Notification; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; public class MyService extends Service { /*private DownloadBinder mBinder=new DownloadBinder(); class DownloadBinder extends Binder{ public void startDownload(){ Log.d("MyService", "startdownload executed"); } public int getProgress(){ Log.d("MyService", "getProgress executed"); return 0; } }*/ @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub //return mBinder; return null; } /*@Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); @SuppressWarnings("deprecation") Notification notification=new Notification(R.drawable.ic_launcher, "Notification comes",System.currentTimeMillis()); Intent notificationIntent=new Intent(this,MainActivity.class); PendingIntent pendingIntent=PendingIntent.getActivity(this, 0,notificationIntent, 0); notification.setLatestEventInfo(this, "this is title", "this is content", pendingIntent); startForeground(1, notification); 可以看到,這里只是修改了onCreate()辦法中的代碼,信賴這部分代碼你會異常眼熟。這就是我們前面進修的 創(chuàng)建通知的辦法。只不過此次在構(gòu)建出Notification對象并沒有應(yīng)用NotificationManager來精曉知顯示 出來,而是調(diào)用了startForeground()辦法。這個辦法接收兩個參數(shù),第一個參數(shù)是通知的id,類似于notify()辦法 的第一個參數(shù),第二個參數(shù)則是構(gòu)建出來的Notification對象。調(diào)用startForeground()辦法后就會讓MyService變成 一個前臺辦事,并在體系狀況顯示出來。 Log.d("MyService", "onCreate()"); } */ /*@Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.d("MyService", "onDestroy()"); }*/ @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub Log.d("MyService", "onStartCommand"); new Thread(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub //處理具體的邏輯 } }).start(); return super.onStartCommand(intent, flags, startId); } }
然則,這種辦事一旦啟動之后,就會一向處于運行狀況,必須調(diào)用stopService()或者stopSelf()辦法才能讓辦事停止下來。所以,如不雅想要實現(xiàn)一個辦事履行完畢后主動停止的功能,就可以如許寫:
package com.jack.servicetest; import android.app.Notification; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; public class MyService extends Service { /*private DownloadBinder mBinder=new DownloadBinder(); class DownloadBinder extends Binder{ public void startDownload(){ Log.d("MyService", "startdownload executed"); } public int getProgress(){ Log.d("MyService", "getProgress executed"); return 0; } }*/ @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub //return mBinder; return null; } /*@Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); @SuppressWarnings("deprecation") Notification notification=new Notification(R.drawable.ic_launcher, "Notification comes",System.currentTimeMillis()); Intent notificationIntent=new Intent(this,MainActivity.class); PendingIntent pendingIntent=PendingIntent.getActivity(this, 0,notificationIntent, 0); notification.setLatestEventInfo(this, "this is title", "this is content", pendingIntent); startForeground(1, notification); 可以看到,這里只是修改了onCreate()辦法中的代碼,信賴這部分代碼你會異常眼熟。這就是我們前面進修的 創(chuàng)建通知的辦法。只不過此次在構(gòu)建出Notification對象并沒有應(yīng)用NotificationManager來精曉知顯示 出來,而是調(diào)用了startForeground()辦法。這個辦法接收兩個參數(shù),第一個參數(shù)是通知的id,類似于notify()辦法 的第一個參數(shù),第二個參數(shù)則是構(gòu)建出來的Notification對象。調(diào)用startForeground()辦法后就會讓MyService變成 一個前臺辦事,并在體系狀況顯示出來。 Log.d("MyService", "onCreate()"); } */ /*@Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.d("MyService", "onDestroy()"); }*/ @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub Log.d("MyService", "onStartCommand"); new Thread(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub //處理具體的邏輯 stopSelf(); } }).start(); return super.onStartCommand(intent, flags, startId); } }
固然這種寫法并不復(fù)雜,然則總會有一些人忘記開啟線程,或者忘記調(diào)用stopSelf()辦法。為了可以簡單地創(chuàng)建一個異步的,會主動停止的辦事,android專門供給了一個IntentService類,這個類就很好的解決了前面所提到的兩種難堪,下面我們來看下它的用法。
新建一個MyIntentService類持續(xù)IntentService,代碼如下所示:
package com.jack.servicetest; import android.app.IntentService; import android.content.Intent; import android.util.Log; public class MyIntentService extends IntentService { /* 這里起首是供給了一個無參的構(gòu)造函數(shù),并且必須在其內(nèi)部調(diào)用父類的有參構(gòu)造函數(shù)。然后要在子類中去實現(xiàn) onHandleIntent()這個抽象辦法,在這個辦法中可以處理一些具體的邏輯,并且不消擔(dān)心ANR的問題,因為 這個辦法已經(jīng)是在子線程中運行的了。這里為了證實一下,我們在onHandleIntent()辦法中打印了當前哨程的id。 別的根據(jù)IntentService的特點,這個辦事在運行停止后應(yīng)當是會主動停止的,所以我們又重寫了onDestroy()辦法,在 這里也打印l一行日記,以證實是不是停止掉落了。 */ public MyIntentService() { super("MyIntentService");//調(diào)用父類的有參構(gòu)造函數(shù) // TODO Auto-generated constructor stub } @Override protected void onHandleIntent(Intent arg0) { // TODO Auto-generated method stub //打印當前哨程的id Log.d("MyIntentService", "Thread id is "+Thread.currentThread().getId()); } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.d("MyIntentService", "onDestroy() executed"); } }
接下來修改activity_main.xml中的代碼,參加一個用于啟動MyIntentService這個辦事的按鈕,如下所示:
<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" > <Button android:id="@+id/start_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="start service" /> <Button android:id="@+id/stop_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="stop service" /> <Button android:id="@+id/bind_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="bind service" /> <Button android:id="@+id/unbind_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="unbind service" /> <Button android:id="@+id/start_intent_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="start intentservice" /> </LinearLayout>
然后修改MainActivity中的代碼,如下所示:
package com.jack.servicetest; //import com.jack.servicetest.MyService.DownloadBinder; import android.app.Activity; 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.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity implements OnClickListener{ private Button startService; private Button stopService; private Button bindService; private Button unbindService; private Button startIntentService; //private MyService.DownloadBinder downloadBinder; private ServiceConnection connection=new ServiceConnection() { /* * 這里創(chuàng)建了一個ServiceConnection的匿名類,在這里重寫了onServiceConnected辦法和 * onServiceDisconnected辦法,這兩個辦法分別會在晃蕩與辦事成功綁定以及解除綁定的時刻調(diào)用。 * 在onServiceConnected辦法中,我們又經(jīng)由過程向下轉(zhuǎn)型獲得了DownloadBinder的實例,有了這個 * 實例,晃蕩和辦事之間的關(guān)系就變得異常慎密了,如今我們可以在晃蕩中根據(jù)具體的場景來調(diào)用DownloadBinder * 中的任何public辦法,及實現(xiàn)了批示辦事干什么,辦事就干什么的功能,這里只做了簡單的測試,在onServiceConnected * 中調(diào)用了DownloadBinder的startDownload(),getProgress()辦法。 * */ @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub } @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub /*downloadBinder=(MyService.DownloadBinder) service; downloadBinder.startDownload(); downloadBinder.getProgress();*/ } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startService=(Button) findViewById(R.id.start_service); stopService=(Button) findViewById(R.id.stop_service); startService.setOnClickListener(this); stopService.setOnClickListener(this); bindService = (Button) findViewById(R.id.bind_service); unbindService = (Button) findViewById(R.id.unbind_service); bindService.setOnClickListener(this); unbindService.setOnClickListener(this); startIntentService=(Button) findViewById(R.id.start_intent_service); startIntentService.setOnClickListener(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public void onClick(View v) { // TODO Auto-generated method stub switch(v.getId()){ case R.id.start_service: Intent startIntent =new Intent(this,MyService.class); startService(startIntent);//啟動辦事 break; case R.id.stop_service: Intent stopIntent =new Intent(this,MyService.class); stopService(stopIntent);//停止辦事 break; case R.id.bind_service: /* *如今我們須要進行晃蕩和辦事的綁定,構(gòu)建一個Intent對象,然后調(diào)用bindService()辦法將 *MainActivity()和MyService進行綁定。 bindService辦法接收留個參數(shù),第一個參數(shù)就是 *膳綾擎創(chuàng)建出的Intent對象,第二個參數(shù)就是前面創(chuàng)建出的ServiceConnection的實例,第三個 *參數(shù)則是一個標記位,這里傳入BIND_AUTO_CREATE表示在晃蕩和辦事進行綁定后主動創(chuàng)建辦事。 *這會使得MyService中的onCreate()辦法獲得履行,但onStartCommand()辦法不會履行。 * */ Intent bindIntent=new Intent(this,MyService.class); bindService(bindIntent, connection, BIND_AUTO_CREATE);//綁定辦事 break; case R.id.unbind_service: /* * 如不雅我們想解除晃蕩和辦事之間的綁定,調(diào)用一下unbindService()辦法就可以了。 * */ unbindService(connection);//解綁辦事 break; case R.id.start_intent_service: //打印主線程的id Log.d("MainActivity", "Thread id is"+Thread.currentThread().getId()); Intent intentService=new Intent(this,MyIntentService.class); startService(intentService); break; default: break; } } } /* 辦事也有本身的生命周期,前面我們應(yīng)用到的onCreate(),onStartCommand(),onBind()和onDestroy()等辦法 都是在辦事的生命周期內(nèi)可能回掉落的辦法。 一旦在項目標任何地位調(diào)用了Context的startService()辦法,響應(yīng)的辦事就會啟動起來,并回調(diào)onStartCommand()。如不雅 這個辦事之前還沒創(chuàng)建過,onCreate()辦法會先于onStartCommand()辦法履行。辦事啟動了之后一向保持運行狀況, 直到stopService()或stopSelf()辦法被調(diào)用。留意固然每調(diào)用一次startService()辦法,onStartCommand()就會 履行一次,但實際膳綾強個辦事都只會存在一個實例。所以不管你調(diào)用了若干次startService()辦法,只需調(diào)用一次stopService() 或stopSelf()辦法,辦事就會停止下來了。 別的,還可聲調(diào)用Context的bindService()來獲取一個辦事的持久連接,這時就會回調(diào)辦事中的onBind()辦法。類似地, 如不雅這個辦事之前還沒有創(chuàng)建過,onCreate()辦法會先于onBind()辦法履行。之后,調(diào)用方可以獲取到onBind()辦法里 返回的IBinder對象的實例,如許就能自由地和辦事進行通信了。只要調(diào)用方和辦事之間的連接沒有斷開,辦事就會一向保持運行狀況。 當調(diào)用了startService()辦法后,又去調(diào)用stopService()辦法,這時辦事中的onDestroy()辦法就會履行,表示 辦事已經(jīng)燒毀了。類似地,當調(diào)用了bindService()辦法后,又去調(diào)用unbindService()辦法,onDestroy()辦法也會履行,這 兩種情況都很好懂得。然則須要留意,我們是完全有可能對一個辦事既調(diào)用了startService()辦法,又調(diào)用了bindService()辦法的, 這種情況下該若何才能讓辦事燒毀掉落?根據(jù)android體系的機制,一個辦事只要被啟動或者綁定了之后就會一向處于運行狀況,必須要讓以上兩種前提同時 不知足,辦事才能被燒毀。所以,這種情況下須要同時調(diào)用stopService()和unbindService()辦法,onDestroy()辦法才會履行。 */
可以看到,我們在start intentservice按鈕的點擊事沂攀瑯綾擎去啟動MyIntentService這個辦事,并在這里打印了一下主線程的id,其實IntentService的用法和通俗的辦事沒什么兩樣。
在AndroidManifest.xml里注冊,如下所示:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.jack.servicetest" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="13" android:targetSdkVersion="17" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.jack.servicetest.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="com.jack.servicetest.MyService"></service> <service android:name="com.jack.servicetest.MyIntentService"></service> </application> </manifest>
從新運行法度榜樣,界面如下所示:
[img]http://img.blog.csdn.net/20150105182349250?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvajkwMzgyOTE4Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
點擊start intentservice按鈕后,不雅察LogCat中打印的日記,如下所示:
[img]http://img.blog.csdn.net/20150105182540578?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvajkwMzgyOTE4Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
可以看到MyIntentService和MainActivity地點的線程id不一樣,并且onDestory()辦法也獲得了履行,解釋MyIntentService在運行完畢后確切主動停止了。集開啟線程和主動停止于一身。
辦事的最佳實踐---------后臺履行的準時義務(wù)
Android中實現(xiàn)準時義務(wù)一般有兩種方法,一種是應(yīng)用java api里供給的Timer類,一種是應(yīng)用android的Alarm機制。
這兩種方法在多半情況下都能實現(xiàn)類似的效不雅,然則Timer有一個明顯的短板,它并不太實用于那些須要經(jīng)久在后臺運行的準時義務(wù)。我們都知道,為了能讓電池加倍耐用,每種手機都邑有本身的休眠策略,andorid手機就會在長時光不操作的情況下主動讓cpu進入的到睡眠狀況,這就有可能導(dǎo)致Timer中的準時義務(wù)無法正常運行。而Alarm機制不存在這種情況,它具有喚醒cpu的功能,即可以包管每次須要履行準時義務(wù)的時刻cpu都能正常工作。須要留意,這里的喚醒cpu和喚醒屏幕完全不是同一個概念,不要弄混淆了。
我們來看看Alarm機制的用法吧,重要須要借助AlarmManager類來實現(xiàn)。這個類和NotificationManager有點類似,都是經(jīng)由過程調(diào)用Context的getSystemService()辦法來獲取實例的,只是這里須要傳入的參數(shù)是Context.ALARM_SERVICE.
是以,獲取一個AlarmManager的實例就可以寫成:
AlarmManager manager=(AlarmManager)getSystemService(Context.ALARM_SERVICE);
接下來調(diào)用AarmManager的set()辦法就可以設(shè)置一個準時義務(wù)了,比如說想要設(shè)定一個義務(wù)在10秒后履行,就可以寫成:
long triggerAtTime=SystemClock.elapsedRealtime()+10*1000;
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime,pendingIntent);
第一個參數(shù)是一個整形參數(shù),用于指定AlarmManager的工作類型,有四種值可選,分別是ELAPSED_REALTIME,ELAPSED_REALTIME_WAKEUP,
RTC 和 RTC_WAKEUP。個中ELAPSED_REALTIME表示讓準時義務(wù)的觸發(fā)大年夜體系開機開端算起,但不會喚醒cpu。
ELAPSED_REALTIME_WAKEUP同樣表示讓準時義務(wù)的觸發(fā)時光大年夜體系開機開端算起,但會喚醒cpu。
RTC表示讓準時義務(wù)的觸發(fā)時光大年夜1970年1月1日0點開端算起,但不會喚醒cpu。
RTC_WAKEUP同樣表示讓準時義務(wù)的觸發(fā)時光大年夜1970年1月1日0點開端算起,但會喚醒cpu。應(yīng)用SystemClock.elapsedRealtime()辦法
可以獲取到體系開機至今所歷經(jīng)的毫秒數(shù),應(yīng)用System.currentTimeMillis()辦法可以獲取到1970年1月1日0點
至今所經(jīng)歷時光的毫秒數(shù)。
第二個參數(shù)就是準時義務(wù)觸發(fā)的時光,以毫秒為單位。如不雅第一個參數(shù)應(yīng)用的是ELAPSED_REALTIME或ELAPSED_REALTIME_WAKEUP則這里傳入開機至今的時光在加上延遲履行的時光。如不雅第一個參數(shù)應(yīng)用的是RTC或RTC_WAKEUP,則這里傳入1970年1月1日0點至今的時光再加上延遲履行的時光。
第三個參數(shù)是一個PendingIntent,對于它應(yīng)當不會陌生了 吧。這里我們一般會調(diào)用getBroadcast()辦法來
獲取一個可以或許履行廣播的PendingIntent。如許當準時義務(wù)被觸發(fā)的時刻,廣播接收器的onReceive()辦法就可以獲得履行。
懂得了 set()辦法的每個參數(shù)之后,你應(yīng)當能想到,設(shè)定一個義務(wù)在10秒后履行還可以寫成:
long triggerAtTime=System.curentTimeMillis()+10*1000;
manager.set(AlarmManager.RTC_WAKEUP,triggerAtTime,pendingIntent);
如今已經(jīng)控制了Alarm機制的根本用法,下面我們就來創(chuàng)建一個可以經(jīng)久在后臺履行準時義務(wù)的辦事。創(chuàng)建一個ServiceBestPractice項目,
然后新增一個LongRunningService類,代碼如下所示:
package com.jcak.servicebestpractice; import java.util.Date; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.SystemClock; import android.util.Log; public class LongRunningService extends Service { @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub new Thread(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub Log.d("LongRunningService","executed at "+new Date().toString()); } }).start(); AlarmManager manager=(AlarmManager) getSystemService(ALARM_SERVICE); int anHour=10*1000; long triggerAtTime=SystemClock.elapsedRealtime()+anHour; Intent i=new Intent(this,AlarmReceiver.class); PendingIntent pi=PendingIntent.getBroadcast(this, 0, i, 0); manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi); return super.onStartCommand(intent, flags, startId); } }
在onStartCommand()辦法中開啟了一個子線程,然后在子線程里就可以履行具體的邏輯操作了,這里簡單的,只是打印了當前的時光。
創(chuàng)建線程之后的代碼就是膳綾擎講解的Alarm機制的用法,先是獲取到了AlarmManager的實例,然后定義義務(wù)的觸發(fā)時光為10秒,在應(yīng)用PendingIntent指定處理準時義務(wù)的廣播接收器為AlarmReceiver,最后調(diào)用set()辦法完成設(shè)定。顯然,AlarmReceiver不存在,我們就創(chuàng)建一個,代碼如下所示:
package com.jcak.servicebestpractice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; public class AlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub Intent i=new Intent(context,LongRunningService.class); context.startService(i); } }
onReceiver()辦法里的代碼異常簡單,就是構(gòu)建出了一個Intent對象,然后去啟動LongRunningService這個辦事
。這就已經(jīng)將一個經(jīng)久辦事在后臺準時運行的辦事完成了。因為一旦啟動了LongRunningService,就會在onStartCommand()辦法里設(shè)定一個準時義務(wù),如許10秒后AlarmReceiver的onReceive()辦法就將獲得履行了,然后我們在這里再次啟動LongRunningService,如許就形成了一個永遠的輪回,包管LongRunningService可以每隔10秒就會啟動一次,這個經(jīng)久在后臺運行的辦事就完成了。
接下來,我們須要在打開法度榜樣的時刻啟動一次LongRunningService,之后LongRunningService就可以一向運行了。修改MainActivity中的代碼,如下所示:
package com.jcak.servicebestpractice; import android.os.Bundle; import android.app.Activity; import android.content.Intent; import android.view.Menu; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent=new Intent(this,LongRunningService.class); startService(intent); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
最后要注冊辦事和廣播,代碼如下所示:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.jcak.servicebestpractice" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="13" android:targetSdkVersion="17" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.jcak.servicebestpractice.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="com.jcak.servicebestpractice.LongRunningService"></service> <receiver android:name="com.jcak.servicebestpractice.AlarmReceiver"></receiver> </application> </manifest>
如今運行一下法度榜樣,然后不雅察LogCat中打印的日記,如圖所示:
[img]http://img.blog.csdn.net/20150105220927069?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvajkwMzgyOTE4Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
可以看到LongRunningService每隔10秒打印一條日記。
別的須要留意的是,大年夜android4.4版開端,Alarm義務(wù)的觸發(fā)時光將會變得不精確,有可能會延遲一段時光后義務(wù)才能獲得履行。這并不是bug,而是體系在耗電方面進行的優(yōu)化。體系會主動檢測今朝有若干Alarm義務(wù)存在,然后將觸發(fā)時光將近的幾個義務(wù)存放在一路履行,這就可以大年夜幅度削減cpu被喚醒的次數(shù),大年夜而有效延長電池的應(yīng)用時光。
當然,如不雅請求Alarm義務(wù)的履行時光必須精確無誤,android仍然供給l解決籌劃。應(yīng)用AlarmManager的setExact()辦法來替代set()辦法,就可以包管義務(wù)準時履行了。
http://blog.csdn.net/j903829182/article/details/41320241
相關(guān)案例查看更多
相關(guān)閱讀
- .net網(wǎng)站
- 云南網(wǎng)絡(luò)推廣
- 云南網(wǎng)站建設(shè)列表網(wǎng)
- 旅游網(wǎng)站建設(shè)
- 小程序密鑰
- 昆明網(wǎng)站開發(fā)
- 云南小程序定制
- 云南微信小程序開發(fā)
- 網(wǎng)絡(luò)公司電話
- web開發(fā)
- web
- 智慧農(nóng)貿(mào)市場
- 做小程序被騙
- uniapp開發(fā)小程序
- 云南網(wǎng)站建設(shè)百度
- vue開發(fā)小程序
- 前端開發(fā)
- 做網(wǎng)站
- 云南做百度小程序的公司
- 小程序開發(fā)費用
- 網(wǎng)站建設(shè)高手
- 昆明做網(wǎng)站建設(shè)的公司排名
- 海南小程序制作公司
- php網(wǎng)站
- 迪慶小程序開發(fā)
- 網(wǎng)站建設(shè)需要多少錢
- 汽車報廢回收管理軟件
- 百度推廣
- 小程序
- python開發(fā)小程序