andriod搭建本身的轮询框架

前言

不少时候Android应用须要每间隔一段时间向服务器请求数据,若是服务器数据有更新则通知界面变化。Android中最经常使用的红点通常采用的就是轮询,红点是为了在数据有更新时及时的提醒用户,好比朋友圈更新,当用户的朋友圈更新时就会显示红点,就是经过移动端不断的向服务器查询朋友圈的更新状态。java

相关知识点

在实现轮询框架时会主要会要到下面两个类,会结合轮询框架对这三个类进行讲解,在应用中分析会理解更加深入。git

一、IntentService IntentService是一种特殊的Service,继承了Service而且是一个抽象类,必须建立它的子类才能用。IntentService能够用于执行后台耗时的任务,当任务执行后会自动中止,IntentService的优先级比通常的线程高,比较适合执行一些优先级高的后台任务。github

二、PendingIntent PendingIntent是延迟的intent,主要用来在某个事件完成后执行特定的Action。PendingIntent包含了Intent及Context,因此就算Intent所属程序结束,PendingIntent依然有效,能够在其余程序中使用。PendingIntent通常做为参数传给某个实例,在该实例完成某个操做后自动执行PendingIntent上的Action,也能够经过PendingIntent的send函数手动执行,并能够在send函数中设置OnFinished表示send成功后执行的动做。服务器

轮询框架实现

要实现轮询,能够借鉴Handler中的looper机制,以下图,维护一个消息队列,循环的从消息队列中取出消息来执行,轮询框架能够定时的向消息队列中加入消息,而后循环中消息队列中取出消息执行。 框架

在这里插入图片描述
能够本身实现一个Looper,可是IntentService中已经包含了一个Looper和一个HandlerThread。所以轮询框架中使用IntentService做为循环框架。继承IntentService接口来实现处理消息访问服务器。

PollingService 用于每次轮询时向请求服务器接口数据ide

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();//这个是访问服务器获取朋友圈是否更新
        }
    }
}
复制代码

PollingService 用来处理接到轮询的消息以后在onHandleIntent(Intent intent)中根据Intent所带有的action不一样来进行访问服务器不一样的接口获取数据。函数

PollingUtil 用于控制轮询服务的开始和结束 使用PollingUtil中的startPollingService来根据action和context生成一个PendingIntent,并将PendingIntent交给PollingScheduler来处理。PollingScheduler是一个线程池控制类。oop

public class PollingUtil {
    /** * 开始轮询服务 */
    public static void startPollingService(final Context context, String action) {
            //包装须要执行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);
        }
    }
    /** * 中止轮询服务 * * @param context */
    public static void stopPollingServices(Context context, String action) {
            PollingScheduler.getInstance().clearScheduleTasks();
        }
    }
复制代码

PollingScheduler实现定时向IntentService的Looper中加入消息 PollingScheduler中生成一个单线程池,addScheduleTask中定时的执行pendingIntent.send(),其中PendingIntent是由PendingIntent pendingIntent = PendingIntent.getService(context, 0,intent, PendingIntent.FLAG_UPDATE_CURRENT);生成的,pendingIntent.send()函数会调用Service.startService()来开启一个服务。post

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();
    }
}
复制代码

代码分析

先给出类图之间的关系以下:测试

在这里插入图片描述
PollingService继承了IntentService,而且在PollingUtil的startPollingService方法中经过 Intent intent = new Intent(context, PollingService.class);和将PendingIntent 与PollingService关联起来,并将PendingIntent加入到定时执行的线程池中,在PollingScheduler 中使用 pendingIntent.send();因为PendingIntent与PollingService关联,因此执行pendingIntent.send()的时候会调用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,执行时从mServiceLooper中取出执行,其中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)中会调用onHandleIntent((Intent)msg.obj);方法,也就是在PollingService中重写的onHandleIntent方法。所以咱们在addScheduleTask中不断的执行pending.send()方法,会不断的调用IntentService中的onStart方法中的mServiceHandler.sendMessage(msg);不断的向消息队列中发消息,而后在onHandleIntent处理消息。 这样一个轮询框架就完成了。

总结

本文的轮询框架利用了IntentService中的handler和Looper机制来实现循环的处理消息,因为IntentService具备服务的特性所以特别适合后台轮询访问服务器数据。

更改

通过评论区的提醒,又测试了几遍发现每次轮询确实都会新建和销毁IntentService,这样就没有利用到消息队列,因此重写了一个PollingIntentService类继承Service,使得每次使用时不会重写建立Service,达到复用的效果。同时增长了enterPollingQueue()方法,能够直接往PollingIntentService的队列中增长轮询的Intent消息。 PollingIntentService代码

* Created time 11:40.
 *
 * @author huhanjun
 * @since 2019/1/7
 */
public abstract class PollingIntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent) msg.obj);
        }
    }

    public PollingIntentService(String name) {
        super();
        mName = name;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate");
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
	//进入轮询队列
    public void enterPollingQueue(@Nullable Intent intent, int startId) {
        Log.d(TAG, "enterPollingQueue");
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand");
        enterPollingQueue(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }
	//中止服务
    public void onStopService() {
        stopSelf();
    }

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
        Log.d(TAG, "onDestroy");
    }

    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }

    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);

}
复制代码

PollingIntentService 继承Service,在ServiceHandler 的handleMessage方法执行后并不执行stopSelf方法,而是专门提供了onStopService方法来中止整个Service。另外暴露出enterPollingQueue方法,能够直接经过这个方法往轮询队列中加入轮询消息。 使用: 只需将

PollingService extends IntentService{
}
复制代码

改成

PollingService extends PollingIntentService{
}
复制代码

源码地址:github.com/hankinghu/P…

轮询框架重构

根据评论区的反馈,我将会使用WorkManager对轮询框架进行重构,重构文章连接:juejin.im/post/5c4472…

个人scdn

blog.csdn.net/u013309870

相关文章
相关标签/搜索