andriod如何搭建自己的輪詢框架
很多時候Android應(yīng)用需要每間隔一段時間向服務(wù)器請求數(shù)據(jù),如果服務(wù)器數(shù)據(jù)有更新則通知界面變化。Android中最常用的紅點(diǎn)一般采用的就是輪詢,紅點(diǎn)是為了在數(shù)據(jù)有更新時及時的提醒用戶,比如朋友圈更新,當(dāng)用戶的朋友圈更新時就會顯示紅點(diǎn),就是通過移動端不斷的向服務(wù)器查詢朋友圈的更新狀態(tài)。
相關(guān)知識點(diǎn)
在實(shí)現(xiàn)輪詢框架時會主要會要到下面兩個類,會結(jié)合輪詢框架對這三個類進(jìn)行講解,在應(yīng)用中分析會理解更加深刻。
1、IntentService IntentService是一種特殊的Service,繼承了Service并且是一個抽象類,必須創(chuàng)建它的子類才能用。IntentService可以用于執(zhí)行后臺耗時的任務(wù),當(dāng)任務(wù)執(zhí)行后會自動停止,IntentService的優(yōu)先級比一般的線程高,比較適合執(zhí)行一些優(yōu)先級高的后臺任務(wù)。
2、PendingIntent PendingIntent是延遲的intent,主要用來在某個事件完成后執(zhí)行特定的Action。PendingIntent包含了Intent及Context,所以就算Intent所屬程序結(jié)束,PendingIntent依然有效,可以在其他程序中使用。PendingIntent一般作為參數(shù)傳給某個實(shí)例,在該實(shí)例完成某個操作后自動執(zhí)行PendingIntent上的Action,也可以通過PendingIntent的send函數(shù)手動執(zhí)行,并可以在send函數(shù)中設(shè)置OnFinished表示send成功后執(zhí)行的動作。
輪詢框架實(shí)現(xiàn)
要實(shí)現(xiàn)輪詢,可以借鑒Handler中的looper機(jī)制,如下圖,維護(hù)一個消息隊(duì)列,循環(huán)的從消息隊(duì)列中取出消息來執(zhí)行,輪詢框架可以定時的向消息隊(duì)列中加入消息,然后循環(huán)中消息隊(duì)列中取出消息執(zhí)行。
可以自己實(shí)現(xiàn)一個Looper,但是IntentService中已經(jīng)包含了一個Looper和一個HandlerThread。因此輪詢框架中使用IntentService作為循環(huán)框架。繼承IntentService接口來實(shí)現(xiàn)處理消息訪問服務(wù)器。
PollingService 用于每次輪詢時向請求服務(wù)器接口數(shù)據(jù)。
public class PollingService extends IntentService { public static final String ACTION_CHECK_CIRCLE_UPDATE="ACTION_CHECK_CIRCLE_UPDATE"; public static final long DEFAULT_MIN_POLLING_INTERVAL = 60000;//最短輪詢間隔1分鐘 public PollingService() { super("PollingService"); } @Override protected void onHandleIntent(Intent intent) { if (intent == null) return; final String action = intent.getAction(); if (ACTION_CHECK_Circle_UPDATE.equals(action)) { CheckCircleOfFriendsUpdate();//這個是訪問服務(wù)器獲取朋友圈是否更新 } } }
PollingService 用來處理接到輪詢的消息之后在 onHandleIntent(Intent intent)
中根據(jù)Intent所帶有的action不同來進(jìn)行訪問服務(wù)器不同的接口獲取數(shù)據(jù)。
PollingUtil 用于控制輪詢服務(wù)的開始和結(jié)束 使用PollingUtil中的startPollingService來根據(jù)action和context生成一個PendingIntent,并將PendingIntent交給PollingScheduler來處理。PollingScheduler是一個線程池控制類。
public class PollingUtil { /** * 開始輪詢服務(wù) */ public static void startPollingService(final Context context, String action) { //包裝需要執(zhí)行Service的Intent Intent intent = new Intent(context, PollingService.class); intent.setAction(action); PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); PollingScheduler.getInstance().addScheduleTask(pendingIntent, 0, PollingService.DEFAULT_MIN_POLLING_INTERVAL); } } /** * 停止輪詢服務(wù) * * @param context */ public static void stopPollingServices(Context context, String action) { PollingScheduler.getInstance().clearScheduleTasks(); } }
PollingScheduler實(shí)現(xiàn)定時向IntentService的Looper中加入消息 PollingScheduler中生成一個單線程池,addScheduleTask中定時的執(zhí)行pendingIntent.send(),其中PendingIntent是由 PendingIntent pendingIntent = PendingIntent.getService(context, 0,intent, PendingIntent.FLAG_UPDATE_CURRENT);
生成的,pendingIntent.send()函數(shù)會調(diào)用Service.startService()來開啟一個服務(wù)。
public class PollingScheduler { private static PollingScheduler sInstance; private ScheduledExecutorService mScheduler; private PollingScheduler() { mScheduler = Executors.newSingleThreadScheduledExecutor(); } public static synchronized PollingScheduler getInstance() { if (sInstance == null) { sInstance = new PollingScheduler(); } if (sInstance.mScheduler.isShutdown()) { sInstance.mScheduler = Executors.newSingleThreadScheduledExecutor(); } return sInstance; } public void addScheduleTask(final PendingIntent pendingIntent, long initialDelay, long period) { Runnable command = new Runnable() { @Override public void run() { try { pendingIntent.send(); } catch (PendingIntent.CanceledException e) { e.printStackTrace(); } } }; mScheduler.scheduleAtFixedRate(command, initialDelay, period, TimeUnit.MILLISECONDS); } public void clearScheduleTasks() { mScheduler.shutdownNow(); } }
代碼分析
先給出類圖之間的關(guān)系如下:
PollingService繼承了IntentService,并且在PollingUtil的startPollingService方法中通過 Intent intent = new Intent(context, PollingService.class);
和將PendingIntent 與PollingService關(guān)聯(lián)起來,并將PendingIntent加入到定時執(zhí)行的線程池中,在PollingScheduler 中使用 pendingIntent.send();
由于PendingIntent與PollingService關(guān)聯(lián),所以執(zhí)行pendingIntent.send()的時候會調(diào)用PollingIntentServide中的onStart()方法。onStart()方法是IntentService中的方法,代碼如下:
@Override public void onStart(@Nullable Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); }
在onstart()中有一個 mServiceHandler.sendMessage(msg);
,找到mServiceHandler的生成位置:
@Override public void onCreate() { super.onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); }
在IntentService的onCreate方法中生成了一個HandlerThread,一個mServiceLooper,一個mServiceHandler,其中mServiceHandler.sendMessage(msg)中的msg都會放到mServiceLooper,執(zhí)行時從mServiceLooper中取出執(zhí)行,其中ServiceHandler 的代碼如下
private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); } }
handleMessage(Message msg)中會調(diào)用onHandleIntent((Intent)msg.obj);方法,也就是在PollingService中重寫的onHandleIntent方法。 因此我們在addScheduleTask中不斷的執(zhí)行pending.send()方法,會不斷的調(diào)用IntentService中的onStart方法中的mServiceHandler.sendMessage(msg);不斷的向消息隊(duì)列中發(fā)消息,然后在onHandleIntent處理消息。 這樣一個輪詢框架就完成了。
總結(jié)
本文的輪詢框架利用了IntentService中的handler和Looper機(jī)制來實(shí)現(xiàn)循環(huán)的處理消息,由于IntentService具有服務(wù)的特性因此特別適合后臺輪詢訪問服務(wù)器數(shù)據(jù)。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android實(shí)現(xiàn)毛玻璃效果彈出菜單動畫
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)毛玻璃效果彈出菜單動畫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-08-08Android BroadcastReceiver廣播注冊方式總結(jié)
這篇文章主要介紹了Android BroadcastReceiver廣播注冊方式總結(jié)的相關(guān)資料,需要的朋友可以參考下2017-01-01Android 輕松實(shí)現(xiàn)圖片倒影效果實(shí)例代碼
這篇文章主要介紹了Android 輕松實(shí)現(xiàn)圖片倒影效果實(shí)例代碼,有需要的朋友可以參考一下2014-01-01系統(tǒng)應(yīng)用根據(jù)Uri授予權(quán)限方法詳解
這篇文章主要為大家介紹了系統(tǒng)應(yīng)用根據(jù)Uri授予權(quán)限方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09Android Studio如何獲取SQLite數(shù)據(jù)并顯示到ListView上
這篇文章主要介紹了Android Studio獲取SQLite數(shù)據(jù)并顯示到ListView上,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03