android中涉及到將服務器中數據變化信息通知用戶通常有兩種辦法,推送和輪詢。 java
消息推送是服務端主動發消息給客戶端,由於第一時間知道數據發生變化的是服務器本身,因此推送的優點是實時性高。但服務器主動推送須要單獨開發一套能讓客戶端持久鏈接的服務端程序,不過如今已經有不少開源的代碼實現了基於xmmp協議的推送方案,並且還可使用谷歌的推送方案。但有些狀況下並不須要服務端主動推送,而是在必定的時間間隔內客戶端主動發起查詢。 android
譬若有這樣一個app,實時性要求不高,天天只要能獲取10次最新數據就能知足要求了,這種狀況顯然輪詢更適合一些,推送顯得太浪費,並且更耗電。 apache
可是不論是輪詢仍是推送都須要不管應用程序是否正在運行或者關閉的狀況下能給用戶發送通知,所以都須要用到service。咱們有兩種方案來使用service達到此目的: json
方案一:service +Thread 安全
在service中開啓一個帶有while循環的線程,使其不斷的從服務器查詢數據(必定時間間隔內),當發現有須要通知用戶的狀況下發送notification。這種方案的代碼大體是: 服務器
import org.apache.http.Header; import org.json.JSONObject; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.widget.Toast; import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.AsyncHttpResponseHandler; /** * * 短信推送服務類,在後臺長期運行,每一個一段時間就向服務器發送一次請求 * * @author jerry * */ public class PushSmsService extends Service { private MyThread myThread; private NotificationManager manager; private Notification notification; private PendingIntent pi; private AsyncHttpClient client; private boolean flag = true; @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } @Override public void onCreate() { System.out.println("oncreate()"); this.client = new AsyncHttpClient(); this.myThread = new MyThread(); this.myThread.start(); super.onCreate(); } @Override public void onDestroy() { this.flag = false; super.onDestroy(); } private void notification(String content, String number, String date) { // 獲取系統的通知管理器 manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notification = new Notification(R.drawable.ic_menu_compose, content, System.currentTimeMillis()); notification.defaults = Notification.DEFAULT_ALL; // 使用默認設置,好比鈴聲、震動、閃燈 notification.flags = Notification.FLAG_AUTO_CANCEL; // 但用戶點擊消息後,消息自動在通知欄自動消失 notification.flags |= Notification.FLAG_NO_CLEAR;// 點擊通知欄的刪除,消息不會依然不會被刪除 Intent intent = new Intent(getApplicationContext(), ContentActivity.class); intent.putExtra("content", content); intent.putExtra("number", number); intent.putExtra("date", date); pi = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0); notification.setLatestEventInfo(getApplicationContext(), number + "發來短信", content, pi); // 將消息推送到狀態欄 manager.notify(0, notification); } private class MyThread extends Thread { @Override public void run() { String url = "你請求的網絡地址"; while (flag) { System.out.println("發送請求"); try { // 每一個10秒向服務器發送一次請求 Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } // 採用get方式向服務器發送請求 client.get(url, new AsyncHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { try { JSONObject result = new JSONObject(new String( responseBody, "utf-8")); int state = result.getInt("state"); // 假設偶數爲未讀消息 if (state % 2 == 0) { String content = result.getString("content"); String date = result.getString("date"); String number = result.getString("number"); notification(content, number, date); } } catch (Exception e) { e.printStackTrace(); } } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { Toast.makeText(getApplicationContext(), "數據請求失敗", 0) .show(); } }); } } } }
方案二:service+AlarmManager+Thread 網絡
雖然alarm的意思是鬧鐘,並且在原生android自帶的鬧鐘應用中AlarmManager也確實很是重要,但並不表明AlarmManager只是用來作鬧鐘應用的,做爲一個一種系統級別的提示服務,確定應該有着很是重要的地位,實際上android中不少東西均可以利用AlarmManager來實現。 app
AlarmManager在特定的時刻爲咱們廣播一個指定的Intent。簡單的說就是咱們設定一個時間,而後在該時間到來時,AlarmManager爲咱們廣播一個咱們設定的Intent。這個intent能夠指向一個activity,也能夠指向一個service。 異步
下面就是使用alarm定時調用service實現輪詢的實現方法: ide
1、新建輪詢工具類PollingUtils.java
public class PollingUtils { //開啓輪詢服務 public static void startPollingService(Context context, int seconds, Class<?> cls,String action) { //獲取AlarmManager系統服務 AlarmManager manager = (AlarmManager) context .getSystemService(Context.ALARM_SERVICE); //包裝須要執行Service的Intent Intent intent = new Intent(context, cls); intent.setAction(action); PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); //觸發服務的起始時間 long triggerAtTime = SystemClock.elapsedRealtime(); //使用AlarmManger的setRepeating方法設置按期執行的時間間隔(seconds秒)和須要執行的Service manager.setRepeating(AlarmManager.ELAPSED_REALTIME, triggerAtTime, seconds * 1000, pendingIntent); } //中止輪詢服務 public static void stopPollingService(Context context, Class<?> cls,String action) { AlarmManager manager = (AlarmManager) context .getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, cls); intent.setAction(action); PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); //取消正在執行的服務 manager.cancel(pendingIntent); } }
public class PollingService extends Service { public static final String ACTION = "com.ryantang.service.PollingService"; private Notification mNotification; private NotificationManager mManager; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { initNotifiManager(); } @Override public void onStart(Intent intent, int startId) { new PollingThread().start(); } //初始化通知欄配置 private void initNotifiManager() { mManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); int icon = R.drawable.ic_launcher; mNotification = new Notification(); mNotification.icon = icon; mNotification.tickerText = "New Message"; mNotification.defaults |= Notification.DEFAULT_SOUND; mNotification.flags = Notification.FLAG_AUTO_CANCEL; } //彈出Notification private void showNotification() { mNotification.when = System.currentTimeMillis(); //Navigator to the new activity when click the notification title Intent i = new Intent(this, MessageActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, i, Intent.FLAG_ACTIVITY_NEW_TASK); mNotification.setLatestEventInfo(this, getResources().getString(R.string.app_name), "You have new message!", pendingIntent); mManager.notify(0, mNotification); } /** * Polling thread * 模擬向Server輪詢的異步線程 * @Author Ryan * @Create 2013-7-13 上午10:18:34 */ int count = 0; class PollingThread extends Thread { @Override public void run() { System.out.println("Polling..."); count ++; //當計數能被5整除時彈出通知 if (count % 5 == 0) { showNotification(); System.out.println("New message!"); } } } @Override public void onDestroy() { super.onDestroy(); System.out.println("Service:onDestroy"); } }
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Start polling service System.out.println("Start polling service..."); PollingUtils.startPollingService(this, 5, PollingService.class, PollingService.ACTION); } @Override protected void onDestroy() { super.onDestroy(); //Stop polling service System.out.println("Stop polling service..."); PollingUtils.stopPollingService(this, PollingService.class, PollingService.ACTION); } }