Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android資訊 >> Android後台線程輪詢服務器獲取推送消息

Android後台線程輪詢服務器獲取推送消息

編輯:Android資訊

簡介

本文通過建立一個線程,在後台持續輪詢獲取服務器推送消息,主要實現以下幾個功能:

  • 建立線程類,做到可直接調用,於後台自動輪詢服務器消息,並對獲取的消息進行處理
  • 獲取廣告等推廣信息,通過notification通知用戶,點擊跳轉到相關網頁
  • 獲取app推送消息,彈出更新對話框,提示符合條件的用戶進行升級,下載並安裝

實現原理

  • Handler.postDelayed用於以固定時間間隔去獲取服務器消息
  • Notification用於顯示推廣信息,同時將接收到的圖片url轉化為bitmap,顯示於上
  • AlertDialog用於app更新提示,點擊升級
  • annotation中的@SharedPref方法存儲消息ID號及消息提示間隔,在時間間隔到後才彈出消息

核心代碼

後台線程類

@EBean
public 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中,此處不做具體展示。

總結

主要的代碼到這裡基本結束,感覺還比較粗糙,耦合性比較大,後續還可以進行封裝,比如設置接口,將一些設置或處理暴露給外面進行處理等,這方面目前也在學習中,有什麼建議歡迎一起探討!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved