Notification使用詳解之四:由後臺服務向Activity傳送進度資訊
上次講到了如何在Activity中監聽後臺服務的進度資訊,實現的方式是讓Activity與後臺服務繫結,通過中間物件Binder的例項操作後臺服務。從效果上來講,這種方式是可行的,不過這種實現有個缺點,那就是Activity的任務太重了,為了監聽服務的狀態,我們不得不繫結服務,然後還需不斷地定時的獲取最新的進度,我們為何不換一下形式呢,讓Service主動將進度傳送給Activity,我們在Activity中只需拿到進度資料,然後更新UI介面。這種新形式就像上次結尾提到的,就像兩個男人同時喜歡一個女人,都通過自己的手段試圖從那個女人那裡獲取愛情,現在我們要讓那個女人變為主動方,將愛情同時傳遞給那兩個男人。
要實現以上方式,我們需要用到BroadcastReceiver,如果不太瞭解的朋友們,可以查閱相關資料補充一下。
關於整個流程的的截圖,我在這裡就不在貼出了,大家可以參看Notification詳解之三的流程截圖。佈局檔案也沒有變化,所以這裡也不在貼出。
我們主要看一下MainActivity、DownloadService、FileMgrActivity這幾個元件的實現形式。
首先是MainActivity:
- package com.scott.notification;
- import android.app.Activity;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.TextView;
- public class MainActivity extends Activity {
- private MyReceiver receiver;
- private TextView text;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- text = (TextView) findViewById(R.id.text);
- receiver = new MyReceiver();
- IntentFilter filter = new IntentFilter();
- filter.addAction("android.intent.action.MY_RECEIVER");
- //註冊
- registerReceiver(receiver, filter);
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- //不要忘了這一步
- unregisterReceiver(receiver);
- }
- public void start(View view) {
- Intent intent = new Intent(this, DownloadService.class);
- //這裡不再使用bindService,而使用startService
- startService(intent);
- }
- /**
- * 廣播接收器
- * @author user
- *
- */
- private class MyReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Bundle bundle = intent.getExtras();
- int progress = bundle.getInt("progress");
- text.setText("downloading..." + progress + "%");
- }
- }
- }
上面的程式碼中,我們的MyReceiver類是繼承了BroadcastReceiver,在onReceive方法中,定義了收到進度資訊並更新UI的邏輯,在onCreate中,我們註冊了這個接受者,並指定action為android.intent.action.MY_RECEIVER,如此一來,如果其他元件向這個指定的action傳送訊息,我們就能夠接收到;另外要注意的是,不要忘了在Activity被摧毀的時候呼叫unregisterReceiver取消註冊。
然後再來看一下DownloadService有什麼變化:
- package com.scott.notification;
- 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.Handler;
- import android.os.IBinder;
- import android.os.Message;
- import android.widget.RemoteViews;
- public class DownloadService extends Service {
- private static final int NOTIFY_ID = 0;
- private boolean cancelled;
- private Context mContext = this;
- private NotificationManager mNotificationManager;
- private Notification mNotification;
- private Handler handler = new Handler() {
- public void handleMessage(android.os.Message msg) {
- switch (msg.what) {
- case 1:
- int rate = msg.arg1;
- if (rate < 100) {
- //更新進度
- RemoteViews contentView = mNotification.contentView;
- contentView.setTextViewText(R.id.rate, rate + "%");
- contentView.setProgressBar(R.id.progress, 100, rate, false);
- } else {
- //下載完畢後變換通知形式
- mNotification.flags = Notification.FLAG_AUTO_CANCEL;
- mNotification.contentView = null;
- Intent intent = new Intent(mContext, FileMgrActivity.class);
- // 告知已完成
- intent.putExtra("completed", "yes");
- //更新引數,注意flags要使用FLAG_UPDATE_CURRENT
- PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
- mNotification.setLatestEventInfo(mContext, "下載完成", "檔案已下載完畢", contentIntent);
- }
- // 最後別忘了通知一下,否則不會更新
- mNotificationManager.notify(NOTIFY_ID, mNotification);
- if (rate >= 100) {
- stopSelf(); //停止服務
- }
- break;
- case 0:
- // 取消通知
- mNotificationManager.cancel(NOTIFY_ID);
- break;
- }
- };
- };
- @Override
- public void onCreate() {
- super.onCreate();
- mNotificationManager = (NotificationManager) getSystemService(android.content.Context.NOTIFICATION_SERVICE);
- }
- @Override
- public void onStart(Intent intent, int startId) {
- super.onStart(intent, startId);
- int icon = R.drawable.down;
- CharSequence tickerText = "開始下載";
- long when = System.currentTimeMillis();
- mNotification = new Notification(icon, tickerText, when);
- // 放置在"正在執行"欄目中
- mNotification.flags = Notification.FLAG_ONGOING_EVENT;
- RemoteViews contentView = new RemoteViews(mContext.getPackageName(), R.layout.download_notification_layout);
- contentView.setTextViewText(R.id.fileName, "AngryBird.apk");
- // 指定個性化檢視
- mNotification.contentView = contentView;
- Intent intnt = new Intent(this, FileMgrActivity.class);
- PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intnt, PendingIntent.FLAG_UPDATE_CURRENT);
- // 指定內容意圖
- mNotification.contentIntent = contentIntent;
- mNotificationManager.notify(NOTIFY_ID, mNotification);
- new Thread() {
- public void run() {
- startDownload();
- };
- }.start();
- }
- @Override
- public void onDestroy() {
- super.onDestroy();
- cancelled = true; //停止下載執行緒
- }
- private void startDownload() {
- cancelled = false;
- int rate = 0;
- while (!cancelled && rate < 100) {
- try {
- //模擬下載進度
- Thread.sleep(500);
- rate = rate + 5;
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- Message msg = handler.obtainMessage();
- msg.what = 1;
- msg.arg1 = rate;
- handler.sendMessage(msg);
- //傳送特定action的廣播
- Intent intent = new Intent();
- intent.setAction("android.intent.action.MY_RECEIVER");
- intent.putExtra("progress", rate);
- sendBroadcast(intent);
- }
- if (cancelled) {
- Message msg = handler.obtainMessage();
- msg.what = 0;
- handler.sendMessage(msg);
- }
- }
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
- }
可以看到,我們在onBind方法裡不在返回自定義的Binder例項了,因為現在的Service和Activitys之間並沒有繫結關係了,他們是獨立的;在下載過程中,我們會呼叫sendBroadcast方法,向指定的action傳送一個附帶有進度資訊的intent,這樣的話,所有註冊過action為android.intent.action.MY_RECEIVER的Activity都能收到這條進度訊息了。
最後再來看一下FileMgrActivity:
- package com.scott.notification;
- import android.app.Activity;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.ProgressBar;
- public class FileMgrActivity extends Activity {
- private MyReceiver receiver;
- private ProgressBar progressBar;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.filemgr);
- progressBar = (ProgressBar) findViewById(R.id.progress);
- if ("yes".equals(getIntent().getStringExtra("completed"))) {
- progressBar.setProgress(100);
- }
- receiver = new MyReceiver();
- IntentFilter filter = new IntentFilter();
- filter.addAction("android.intent.action.MY_RECEIVER");
- //註冊
- registerReceiver(receiver, filter);
- }
- public void cancel(View view) {
- Intent intent = new Intent(this, DownloadService.class);
- stopService(intent);
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- //不要忘了這一步
- unregisterReceiver(receiver);
- }
- /**
- * 廣播接收器
- * @author user
- *
- */
- private class MyReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Bundle bundle = intent.getExtras();
- int progress = bundle.getInt("progress");
- progressBar.setProgress(progress);
- }
- }
- }
我們發現,FileMgrActivity的模式和MainActivity差不多,也是註冊了相同的廣播接收者,對於DownloadService來說自己是廣播基站,MainActivity和FileMgrActivity就是聽眾,訊號能夠同時到達多個聽眾,對於程式碼而言,與之前的程式碼比較一下,發現簡潔了許多,顯然這種方式更好一些。
對於我們上面提到的男女關係,DownloadService就是那個女人,然後兩個男人將自己的手機號告知了女人,等於註冊了接收器,然後女人將簡訊群發給兩個男人。不過在這種情況下,兩個男人互相都不知道對方的存在,以為女人深深的愛著自己,等到發現一切的時候,就是痛苦的時候。相信大家如果遇到這種情況都會很痛苦吧,至於你們信不信,我反正是信的。哈哈。
其實關於Notification的講解最後兩篇涉及到Notification的不多,主要是圍繞Notification做一些實際的應用示例,希望對於朋友們平時遇到的問題會有所幫助,如果這方面有了新的研究總結,我會再及時更新的,謝謝大家。相關文章
- Notification使用詳解之三:通過服務更新進度通知&在Activity中監聽服務進度
- Notification使用詳解之二:可更新進度的通知
- python向後端Flask服務傳送檔案並在後端處理Python後端Flask
- Android入門教程 | 四大元件之Service(前臺服務,後臺服務)Android元件
- 可執行資訊和傳送訊息的服務?
- 關於Activity之間傳送資料
- jQuery向後臺傳送json資料進行處理程式碼例項jQueryJSON
- stm32之CAN傳送、接收詳解
- JSP向後臺傳遞引數的四種方式JS
- PHP-Socket服務端客戶端傳送接收通訊例項詳解PHP服務端客戶端
- HttpSendRequest向服務端傳送資料,構造請求http頭HTTP服務端
- .net 後臺 傳送http請求HTTP
- 某大神C#框架後臺傳送資訊的查詢及破解C#框架
- 向任意應用程式(包括後臺的)傳送任意按鍵訊息
- ORACLE DG之後臺程式詳解Oracle
- HttpSendRequest向服務端傳送資料,構造請求http頭薦HTTP服務端
- 使用Linux命令來傳送資訊Linux
- Android實時獲得經緯度,傳送給c++服務端AndroidC++服務端
- Android Notification 詳解Android
- 後臺向vue頁面傳值Vue
- SMTP操作使用詳解並透過python進行smtp郵件傳送示例Python
- 前端傳送的請求,是如何請求到後端服務的?前端後端
- 後臺管理系統之詳解(一)
- 使用微信公眾平臺傳送報警資訊(Python版)薦Python
- Android郵件傳送詳解Android
- Android郵件傳送詳解 .Android
- Android多種進度條使用詳解Android
- Rsync服務詳解
- SMB服務詳解
- Windows服務詳解Windows
- oreo上的notification詳解
- Android Notification 通知詳解Android
- 詳解Android中的四大元件之一:Activity詳解Android元件
- Node.js:上傳檔案,服務端如何獲取檔案上傳進度Node.js服務端
- GWT1.7學習之後臺傳送pojo到前臺頁面.RPC呼叫POJORPC
- win10使用自帶郵箱傳送郵件時直接進傳送箱裡無法完成傳送怎麼解決Win10
- gateway(二)微服務之間傳遞使用者資訊Gateway微服務
- NeuChar 平臺使用及開發教程(四):使用 NeuChar 的素材服務