简介
本文通过建立一个线程,在后台持续轮询获取服务器推送消息,主要实现以下几个功能:
建立线程类,做到可直接调用,于后台自动轮询服务器消息,并对获取的消息进行处理
获取广告等推广信息,通过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中,此处不做具体展示。
总结
主要的代码到这里基本结束,感觉还比较粗糙,耦合性比较大,后续还可以进行封装,比如设置接口,将一些设置或处理暴露给外面进行处理等,这方面目前也在学习中,有什么建议欢迎一起探讨!
共同學習,寫下你的評論
評論加載中...
作者其他優質文章