<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ## 本節引言 > 上節我們學習了Service的生命周期,以及兩種啟動Service的兩種方法, 本節繼續來深入了解Service中的IntentService,Service的使用實例: 前臺服務與輪詢的實現! * * * ## 1.IntentService的使用 在上一節后我們已經知道了如何去定義和啟動Service,但是如果我們直接把 耗時線程放到Service中的onStart()方法中,雖然可以這樣做,但是很容易 會引起ANR異常(Application Not Responding),而Android的官方在介紹 Service有下面這樣一段話: ![](https://box.kancloud.cn/2015-12-01_565da6a9c4698.jpg) **直接翻譯:** > 1.Service不是一個單獨的進程,它和它的應用程序在同一個進程中 > 2.Service不是一個線程,這樣就意味著我們應該避免在Service中進行耗時操作 于是乎,Android給我們提供了解決上述問題的替代品,就是下面要講的**IntentService**; IntentService是繼承與Service并處理異步請求的一個類,在IntentService中有 一個工作線程來處理耗時操作,請求的Intent記錄會加入隊列 **工作流程:** > 客戶端通過startService(Intent)來啟動IntentService; 我們并不需要手動地區控制IntentService,當任務執行完后,IntentService會自動停止; 可以啟動IntentService多次,每個耗時操作會以工作隊列的方式在IntentService的 onHandleIntent回調方法中執行,并且每次只會執行一個工作線程,執行完一,再到二這樣! 再接著是代碼演示,網上大部分的代碼都是比較Service與IntentService的, 定義足夠長的休眠時間,演示Service的ANR異常,然后引出IntentService有多好! 這里就不演示Service了,網上的都是自定義Service,然后在onStart()方法 中Thread.sleep(20000)然后引發ANR異常,有興趣的可以自己寫代碼試試, 這里的話只演示下IntentService的用法! **TestService3.java** ~~~ public class TestService3 extends IntentService { private final String TAG = "hehe"; //必須實現父類的構造方法 public TestService3() { super("TestService3"); } //必須重寫的核心方法 @Override protected void onHandleIntent(Intent intent) { //Intent是從Activity發過來的,攜帶識別參數,根據參數不同執行不同的任務 String action = intent.getExtras().getString("param"); if(action.equals("s1"))Log.i(TAG,"啟動service1"); else if(action.equals("s2"))Log.i(TAG,"啟動service2"); else if(action.equals("s3"))Log.i(TAG,"啟動service3"); //讓服務休眠2秒 try{ Thread.sleep(2000); }catch(InterruptedException e){e.printStackTrace();} } //重寫其他方法,用于查看方法的調用順序 @Override public IBinder onBind(Intent intent) { Log.i(TAG,"onBind"); return super.onBind(intent); } @Override public void onCreate() { Log.i(TAG,"onCreate"); super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG,"onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void setIntentRedelivery(boolean enabled) { super.setIntentRedelivery(enabled); Log.i(TAG,"setIntentRedelivery"); } @Override public void onDestroy() { Log.i(TAG,"onDestroy"); super.onDestroy(); } } ~~~ **AndroidManifest.xml注冊下Service** ~~~ <service android:name=".TestService3" android:exported="false"> <intent-filter > <action android:name="com.test.intentservice"/> </intent-filter> </service> ~~~ **在MainActivity啟動三次服務:** ~~~ public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent it1 = new Intent("com.test.intentservice"); Bundle b1 = new Bundle(); b1.putString("param", "s1"); it1.putExtras(b1); Intent it2 = new Intent("com.test.intentservice"); Bundle b2 = new Bundle(); b2.putString("param", "s2"); it2.putExtras(b2); Intent it3 = new Intent("com.test.intentservice"); Bundle b3 = new Bundle(); b3.putString("param", "s3"); it3.putExtras(b3); //接著啟動多次IntentService,每次啟動,都會新建一個工作線程 //但始終只有一個IntentService實例 startService(it1); startService(it2); startService(it3); } } ~~~ **運行截圖:** ![](https://box.kancloud.cn/2015-12-01_565da6aa114ee.jpg) **小結:** > 當一個后臺的任務,需要分成幾個子任務,然后按先后順序執行,子任務 (簡單的說就是異步操作),此時如果我們還是定義一個普通Service然后 在onStart方法中開辟線程,然后又要去控制線程,這樣顯得非常的繁瑣; 此時應該自定義一個IntentService然后再onHandleIntent()方法中完成相關任務! * * * ## 2.Activity與Service通信 我們前面的操作都是通過Activity啟動和停止Service,假如我們啟動的是一個下載 的后臺Service,而我們想知道Service中下載任務的進度!那么這肯定是需要Service 與Activity進行通信的,而他們之間交流的媒介就是Service中的onBind()方法! 返回一個我們自定義的Binder對象! 基本流程如下: * 1.自定義Service中,自定義一個Binder類,然后將需要暴露的方法都寫到該類中! * 2.Service類中,實例化這個自定義Binder類,然后重寫onBind()方法,將這個Binder對象返回! * 3.Activity類中實例化一個ServiceConnection對象,重寫onServiceConnected()方法,然后 獲取Binder對象,然后調用相關方法即可! * * * ## 3.一個簡單前臺服務的實現 學到現在,我們都知道Service一般都是運行在后來的,但是Service的系統優先級 還是比較低的,當系統內存不足的時候,就有可能回收正在后臺運行的Service, 對于這種情況我們可以使用前臺服務,從而讓Service稍微沒那么容易被系統殺死, 當然還是有可能被殺死的...所謂的前臺服務就是狀態欄顯示的Notification! 實現起來也很簡單,最近做的項目剛好用到這個前臺服務,就把核心的代碼摳出來 分享下: 在自定義的Service類中,重寫onCreate(),然后根據自己的需求定制Notification; 定制完畢后,調用startForeground(1,notification對象)即可!?**核心代碼如下:** ~~~ public void onCreate() { super.onCreate(); Notification.Builder localBuilder = new Notification.Builder(this); localBuilder.setContentIntent(PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0)); localBuilder.setAutoCancel(false); localBuilder.setSmallIcon(R.mipmap.ic_cow_icon); localBuilder.setTicker("Foreground Service Start"); localBuilder.setContentTitle("Socket服務端"); localBuilder.setContentText("正在運行..."); startForeground(1, localBuilder.getNotification()); } ~~~ **運行效果截圖:** ![](https://box.kancloud.cn/2015-12-01_565da6ab3c8e0.jpg) * * * ## 4.簡單定時后臺線程的實現 除了上述的前臺服務外,實際開發中Service還有一種常見的用法,就是執行定時任務, 比如輪詢,就是每間隔一段時間就請求一次服務器,確認客戶端狀態或者進行信息更新 等!而Android中給我們提供的定時方式有兩種使用Timer類與Alarm機制! > 前者不適合于需要長期在后臺運行的定時任務,CPU一旦休眠,Timer中的定時任務 就無法運行;Alarm則不存在這種情況,他具有喚醒CPU的功能,另外,也要區分CPU 喚醒與屏幕喚醒! **使用流程:** > * **Step 1:獲得Service:**?AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE); > * **Step 2:通過set方法設置定時任務**?int anHour = 2 * 1000; long triggerAtTime = SystemClock.elapsedRealtime() + anHour; manager.set(AlarmManager.RTC_WAKEUP,triggerAtTime,pendingIntent); > * **Step 3:定義一個Service**?在onStartCommand中開辟一條事務線程,用于處理一些定時邏輯 > * **Step 4:定義一個Broadcast(廣播),用于啟動Service**?最后別忘了,在AndroidManifest.xml中對這Service與Boradcast進行注冊! **參數詳解:**?**set(int type,long startTime,PendingIntent pi)** > **①type:**?有五個可選值: > **AlarmManager.ELAPSED_REALTIME:**?鬧鐘在手機睡眠狀態下不可用,該狀態下鬧鐘使用相對時間(相對于系統啟動開始),狀態值為3;? > **AlarmManager.ELAPSED_REALTIME_WAKEUP**?鬧鐘在睡眠狀態下會喚醒系統并執行提示功能,該狀態下鬧鐘也使用相對時間,狀態值為2;? > **AlarmManager.RTC**?鬧鐘在睡眠狀態下不可用,該狀態下鬧鐘使用絕對時間,即當前系統時間,狀態值為1; > **AlarmManager.RTC_WAKEUP**?表示鬧鐘在睡眠狀態下會喚醒系統并執行提示功能,該狀態下鬧鐘使用絕對時間,狀態值為0;? > **AlarmManager.POWER_OFF_WAKEUP**?表示鬧鐘在手機關機狀態下也能正常進行提示功能,所以是5個狀態中用的最多的狀態之一, 該狀態下鬧鐘也是用絕對時間,狀態值為4;不過本狀態好像受SDK版本影響,某些版本并不支持; PS:第一個參數決定第二個參數的類型,如果是REALTIME的話就用: SystemClock.elapsedRealtime( )方法可以獲得系統開機到現在經歷的毫秒數 如果是RTC的就用:System.currentTimeMillis()可獲得從1970.1.1 0點到 現在做經歷的毫秒數 > **②startTime:**?鬧鐘的第一次執行時間,以毫秒為單位,可以自定義時間,不過一般使用當前時間。 需要注意的是,本屬性與第一個屬性(type)密切相關,如果第一個參數對應的鬧鐘 使用的是相對時間(**ELAPSED_REALTIME**和**ELAPSED_REALTIME_WAKEUP**),那么本屬 性就得使用相對時間(相對于系統啟動時間來說),比如當前時間就表示為: SystemClock.elapsedRealtime();如果第一個參數對應的鬧鐘使用的是絕對時間 (RTC、RTC_WAKEUP、POWER_OFF_WAKEUP),那么本屬性就得使用絕對時間, 比如當前時間就表示為:System.currentTimeMillis()。 > > **③PendingIntent:**?綁定了鬧鐘的執行動作,比如發送一個廣播、給出提示等等。PendingIntent 是Intent的封裝類。 > 需要注意的是,如果是通過啟動服務來實現鬧鐘提示的話, PendingIntent對象的獲取就應該采用Pending.getService (Context c,int i,Intent intent,int j)方法; > 如果是通過廣播來實現鬧鐘提示的話, PendingIntent對象的獲取就應該采用 PendingIntent.getBroadcast (Context c,int i,Intent intent,int j)方法; > 如果是采用Activity的方式來實現鬧鐘提示的話,PendingIntent對象的獲取 就應該采用 PendingIntent.getActivity(Context c,int i,Intent intent,int j) 方法。 > 如果這三種方法錯用了的話,雖然不會報錯,但是看不到鬧鐘提示效果。 **另外:** 從4.4版本后(API 19),Alarm任務的觸發時間可能變得不準確,有可能會延時,是系統 對于耗電性的優化,如果需要準確無誤可以調用setExtra()方法~ **核心代碼:** ~~~ public class LongRunningService extends Service { @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { //這里開辟一條線程,用來執行具體的邏輯操作: new Thread(new Runnable() { @Override public void run() { Log.d("BackService", new Date().toString()); } }).start(); AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE); //這里是定時的,這里設置的是每隔兩秒打印一次時間=-=,自己改 int anHour = 2 * 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); } } ~~~ **AlarmReceiver.java** ~~~ public class AlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Intent i = new Intent(context,LongRunningService.class); context.startService(i); } } ~~~ * * * ## 本節小結: 本節我們繼續對Service進行更深入的學習,IntentService以及Service 在實際開發中的兩個常用的案例:前臺Service的實現,以及Service后臺 Service的實現!下一節中我們會繼續研究Service的AIDL,跨進程通信, 敬請期待~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看