为了账号安全,请及时绑定邮箱和手机立即绑定

Android后台线程轮询服务器获取推送消息

标签:
Android

简介

本文通过建立一个线程,在后台持续轮询获取服务器推送消息,主要实现以下几个功能:

  • 建立线程类,做到可直接调用,于后台自动轮询服务器消息,并对获取的消息进行处理

  • 获取广告等推广信息,通过notification通知用户,点击跳转到相关网页

  • 获取app推送消息,弹出更新对话框,提示符合条件的用户进行升级,下载并安装

实现原理

  • Handler.postDelayed用于以固定时间间隔去获取服务器消息

  • Notification用于显示推广信息,同时将接收到的图片url转化为bitmap,显示于上

  • AlertDialog用于app更新提示,点击升级

  • annotation中的@SharedPref方法存储消息ID号及消息提示间隔,在时间间隔到后才弹出消息

核心代码

后台线程类

@EBeanpublic class PushThread extends Thread {    private Handler advertisementHandler;    private Handler appPushHandler;    private Context mContext;    private int period = 2000;    private NotificationManager mNM;    private Notification notification;    private boolean run; 
    @Pref
    MyPrefs_ myPrefs;    /**
     * 构造方法,初始化参数
     * @param mContext
     */
    public PushThread(Context mContext) {        this.mContext = mContext;
    }   /**
     * 启动线程
     */
    public void startThread() {
        L.d("[PushThread] startThread");
        run = true;
        advertisementHandler = new Handler();
        appPushHandler  = new Handler();
        advertisementHandler.postDelayed(getAdvertisementRunable, period);
        L.d("PushThread run");
    }    /**
     * 停止线程
     */
    public void stopThread() {
        L.d("[PushThread] stopThread");
        run = false;
        advertisementHandler.removeCallbacks(getAdvertisementRunable);
        appPushHandler.removeCallbacks(getAppPushRunable);
    }
}

startThread()初始化Handler,启动线程;stopThread()移除线程,标志位run用来确保关闭所有线程。

Handler实现轮询获取消息

获取推广信息

 /**
 * 获取advertisement的线程
 */Runnable getAdvertisementRunable = new Runnable() {
	@Override	public void run() {
		L.d("getAdvertisementRunable");
		IotClass.getAdvertisementInfo("advertisement", new IotClass.OnPushInfoListener() {
			@Override			public void receive(String respons) {
				Gson gson = new Gson();
				AdvertismentBean advertismentBean = gson.fromJson(respons, AdvertismentBean.class);
				L.d("respons advertismentBean: " + advertismentBean);//                    L.d("respons: " + respons);
				if (myPrefs.advertisementId().get() == advertismentBean.getMessageId()) {					if (myPrefs.advertisementFrequency().get() <= (System.currentTimeMillis() / 1000)) {
						L.d("[PushThread] getAdvertisementRunable time to show");
						showNotification(advertismentBean);
					} else {
						L.d("[PushThread] getAdvertisementRunable wait...");
					}
				} else {
					L.d("[PushThread] getAdvertisementRunable first show");
					showNotification(advertismentBean);
				}
			}
		});		 if (run)
		appPushHandler.postDelayed(getAppPushRunable, period);
	}
};

IotClass是自己写好的一个网络请求的类,IotClass.getAdvertisementInfo方法获取推送消息,结果回调后进行处理,通过Gjson序列化成对象:

Gson gson = new Gson();
AdvertismentBean advertismentBean = gson.fromJson(respons, AdvertismentBean.class);

后面是判断messageId,如果是第一次获取到messageId则显示消息,否则等到时间间隔过了后再显示,最后通过appPushHandler.postDelayed(getAppPushRunable, period);继续去轮询APP更新推送

获取APP更新推送

/**
     * 获取app推送信息的线程
     */
    Runnable getAppPushRunable = new Runnable() {
        @Override        public void run() {
            IotClass.getAdvertisementInfo("android", new IotClass.OnPushInfoListener() {
                @Override                public void receive(String respons) {
                    String description;
                    Gson gson = new Gson();
                    AppBean appBean = gson.fromJson(respons, AppBean.class);
                    L.d("respons appBean: " + appBean);//                    L.d("respons: " + respons);
                    if (myPrefs.appPushId().get() == appBean.getMessageId()){                        if (myPrefs.appPushFrequency().get() <= (System.currentTimeMillis()/1000))
                        {
                            description = getAppDescription(appBean);
                            showUpgradeDialog(appBean, Utils.appDowanloadUrl+appBean.getAndroid_filename(), description);
                            L.d("[PushThread] getAppPushRunable time to show");
                        }                        else{
                            L.d("[PushThread] getAppPushRunable wait...");
                        }
                    }else{
                        description = getAppDescription(appBean);
                        showUpgradeDialog(appBean, Utils.appDowanloadUrl+appBean.getAndroid_filename(), description);
                        L.d("[PushThread] getAppPushRunable first show");
                    }
                }
            });if (run)      advertisementHandler.postDelayed(getAdvertisementRunable, period);
        }
    };

同理,获取app更新推送的处理与获取推广信息的方式类似,在最后通过advertisementHandler.postDelayed(getAdvertisementRunable, period);重新去获取推广信息的推送,相互调用,达到后台线程持续轮询推送消息的效果,其中getAppDescription用来判断系统语言,用于选择更新提示中用英文还是中文描述:

/**
 * 判断系统语言版本,返回相应的更新说明
 * @param appBean
 * @return
 */private String getAppDescription(AppBean appBean) {	if (Tools.isZh(mContext))
	{		return  appBean.getDescription();
	}else {		return appBean.getDescription_en();
	}
}

下面是AppBean的类

public class AppBean {
    String result;    int messageId;    long frequency;    int android_build;
    String versionCode;
    String description;
    String description_en;
    String android_filename;
    String android_file_size;
    String android_id;    @Override
    public String toString() {        return "AppBean [result=" + result + ", messageId=" + messageId + ", frequency=" + frequency
                + ", android_build=" + android_build + ", versionCode=" + versionCode + ", description=" + description + ", description_en=" + description_en
                + ", android_filename=" + android_filename + ", android_file_size=" + android_file_size + ", android_id=" + android_id
                + "]";
    }    public String getResult() {        return result;
    }    public void setResult(String result) {        this.result = result;
    }    public int getMessageId() {        return messageId;
    }    public void setMessageId(int messageId) {        this.messageId = messageId;
    }    public long getFrequency() {        return frequency;
    }    public void setFrequency(long frequency) {        this.frequency = frequency;
    }    public int getAndroid_build() {        return android_build;
    }    public void setAndroid_build(int android_build) {        this.android_build = android_build;
    }    public String getVersionCode() {        return versionCode;
    }    public void setVersionCode(String versionCode) {        this.versionCode = versionCode;
    }    public String getDescription() {        return description;
    }    public void setDescription(String description) {        this.description = description;
    }    public String getDescription_en() {        return description_en;
    }    public void setDescription_en(String description_en) {        this.description_en = description_en;
    }    public String getAndroid_filename() {        return android_filename;
    }    public void setAndroid_filename(String android_filename) {        this.android_filename = android_filename;
    }    public String getAndroid_file_size() {        return android_file_size;
    }    public void setAndroid_file_size(String android_file_size) {        this.android_file_size = android_file_size;
    }    public String getAndroid_id() {        return android_id;
    }    public void setAndroid_id(String android_id) {        this.android_id = android_id;
    }
}

AdvertismentBean与此类似,就不占篇幅了

推送消息显示等处理

Notification显示推广信息

Notification常规消息设置
/**
     * notification通知advertisement
     * @param advertismentBean
     */
    private void showNotification(AdvertismentBean advertismentBean) {
        myPrefs.advertisementId().put(advertismentBean.getMessageId());
        myPrefs.advertisementFrequency().put((int) (System.currentTimeMillis()/1000 + advertismentBean.getFrequency()));        // The PendingIntent to launch our activity if the user selects this notification
        String url = advertismentBean.getUrl();
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(Uri.parse(url));
        PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);        //get largeIcon from url
        Bitmap largeIcon = getBitmap(advertismentBean.getLargeIcon());        // Set the info for the views that show in the notification panel.
        notification = new Notification.Builder(mContext)
                .setSmallIcon(R.drawable.logo)
                .setLargeIcon(largeIcon)
                .setWhen(System.currentTimeMillis())
                .setTicker(advertismentBean.getContentTitle())
                .setContentTitle(advertismentBean.getContentTitle())
                .setContentText(advertismentBean.getContentText())
                .setSubText(advertismentBean.getSubText())
                .setContentIntent(contentIntent)
                .build();        // Send the notification.
        mNM.notify(advertismentBean.getMessageId(), notification);
    }

首先是存储ID号和时间间隔,以便下次轮询判断使用,后面设置点击事件,跳转到相应网页页面

 String url = advertismentBean.getUrl();
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(Uri.parse(url));
        PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);

其他的则是常规的notification的消息内容设置,另外,下面用于获取推送消息中的图片url并显示于notification上:

Notification获取网络图片用作图标显示
 /**
     * 通过URL获取图片,生成bitmap
     * @param path
     * @return
     */
    public static Bitmap getBitmap(String path) {        try {
            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setRequestMethod("GET");            if (conn.getResponseCode() == 200) {
                InputStream inputStream = conn.getInputStream();
                Bitmap bitmap = BitmapFactory.decodeStream(inputStream);                return bitmap;
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (ProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }        return null;
    }

该方法实现通过url转化为bitmap,用于notification大图标显示

AlertDialog提示更新推送

    /**
     * 更新检测对话框
     * @param downloadUrl
     * @param newVersionInfo
     */
    @UiThread
    void showUpgradeDialog(AppBean appBean, final String downloadUrl, String newVersionInfo) {
        myPrefs.appPushId().put(appBean.getMessageId());
        myPrefs.appPushFrequency().put((int) (System.currentTimeMillis()/1000 + appBean.getFrequency()));        final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
        builder.setTitle(R.string.Found_new_version).setMessage(newVersionInfo);
        builder.setPositiveButton(R.string.upgrade, new DialogInterface.OnClickListener() {            @Override
            public void onClick(DialogInterface dialog, int which) {
                IotClass.downLoadAppOrBin(mContext, downloadUrl, new ProgressDialog(mContext), IotClass.TYPE_APP);
            }
        }).setNegativeButton(R.string.show_next_time, null).show();
    }

与消息推送类似,点击升级按钮后下载并安装,下载及安装的操作封装在IotClass.downLoadAppOrBin中,此处不做具体展示。

总结

主要的代码到这里基本结束,感觉还比较粗糙,耦合性比较大,后续还可以进行封装,比如设置接口,将一些设置或处理暴露给外面进行处理等,这方面目前也在学习中,有什么建议欢迎一起探讨!


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消