上次讲到了如何在Activity中监听后台服务的进度信息,实现的方式是让Activity与后台服务绑定,经过中间对象Binder的实例操做 后台服务。从效果上来说,这种方式是可行的,不过这种实现有个缺点,那就是Activity的任务过重了,为了监听服务的状态,咱们不得不绑定服务,而后 还需不断地定时的获取最新的进度,咱们为什么不换一下形式呢,让Service主动将进度发送给Activity,咱们在Activity中只需拿到进度数 据,而后更新UI界面。这种新形式就像上次结尾提到的,就像两个男人同时喜欢一个女人,都经过本身的手段试图从那个女人那里获取爱情,如今咱们要让那个女 人变为主动方,将爱情同时传递给那两个男人。 java
要实现以上方式,咱们须要用到BroadcastReceiver,若是不太了解的朋友们,能够查阅相关资料补充一下。 android
关于整个流程的的截图,我在这里就不在贴出了,你们能够参看Notification详解之三的流程截图。布局文件也没有变化,因此这里也不在贴出。 app
咱们主要看一下MainActivity、DownloadService、FileMgrActivity这几个组件的实现形式。 ide
首先是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取消注册。 this
而后再来看一下DownloadService有什么变化: spa
- 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都能收到这条进度消息了。 .net
最后再来看一下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作一些实际的应用示例,但愿对于朋友们平时遇到的问题会有所帮助,若是这方面有了新的研究总结,我会再及时更新的,谢谢你们。