Android开发笔记(五十二)通知推送Notification

PendingIntent

准备工作复习一下PendingIntent,前面的博文《 Android开发笔记(五十)定时器AlarmManager》已经提到了它。PendingIntent意即延迟的Intent,主要用于非立即响应的通信场合。上回的博文,博主介绍了PendingIntent的用法,下面再列出有用到它的场合:
1、用于定时器AlarmManager,处理时刻到达后的提醒动作
2、用于通知推送Notification,处理点击通知后的相应动作
3、用于远程视图RemoteViews,处理远程控件上的点击动作
4、用于发送短信SmsManager,处理短信发送完的后续动作


Notification

Android的消息通知栏放的是APP想即时提醒用户的消息,Notification就是这么一个由APP提供的通知推送内容,每条通知基本都有这些元素:图标、标题、内容、时间等等,它的参数通过建造者模式来构建。下面是Notification.Builder常用的构建参数方法:
setWhen : 设置推送时间,以“小时:分钟”格式显示
setShowWhen : 设置是否显示推送时间
setUsesChronometer : 设置是否显示时间计数。为true时将不显示推送时间,动态显示从通知被推送到当前的时间间隔,以“分钟:秒钟”格式显示
setSmallIcon : 设置状态栏里面的图标(小图标)
setTicker : 设置状态栏里面的提示文本
setLargeIcon : 设置下拉列表里面的图标(大图标)
setContentTitle : 设置下拉列表里面的标题文本
setContentText : 设置下拉列表里面的内容文本
setSubText : 设置下拉列表里面的附加说明文本,位于内容文本下方。若调用该方法,则setProgress的设置将失效
setProgress : 设置进度条与当前进度。进度条位于标题文本与内容文本中间
setNumber : 设置下拉列表右下方的数字,可与setProgress联合使用,表示进度条的当前进度数值
setContentInfo : 设置下拉列表右下方的文本。若调用该方法,则setNumber的设置将失效
setContentIntent : 设置内容的PendingIntent,在点击该通知时触发Intent动作
setDeleteIntent : 设置删除的PendingIntent,在滑掉该通知时触发Intent动作
setAutoCancel : 设置该通知是否自动清除。若为true,点击该通知后,通知会自动消失;若为false,点击该通知后,通知不会消失。
setSound : 设置通知推送时的声音
setVibrate : 设置通知推送时的震动方式
setOngoing : 设置该通知是否保持在下拉列表中。为true时用户将不能从下拉列表中去掉该通知
setPriority : 设置该通知的优先级
setExtras : 设置该通知的Bundle参数信息
setContent : 设置一个定制视图RemoteViews,用于取代Builder的默认视图模板
build : 构建方法。在以上参数都设置完毕后,调用该方法会返回Notification对象


NotificationManager

Notification只是生成通知的内容,实际推送动作还需要借助于系统的通知服务来实现。NotificationManager便是系统通知服务的管理类,它的常用方法如下:
notify : 推送指定通知到状态栏和下拉列表
cancel : 取消指定通知。调用该方法后,状态栏和下拉列表中的指定通知将消失
cancelAll : 取消所有通知


下面是NotificationManager的调用代码例子:
			NotificationManager notifyMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
			notifyMgr.notify(R.string.app_name, notify);

Notification除了可由NotificationManager进行推送,也可由Service的startForeground方法推送,从而使得后台服务保持在前台运行,详细说明见《 Android开发笔记(四十一)Service的生命周期》。


RemoteViews

远程视图RemoteViews与页面视图一样也是从layout下的布局文件中得到,二者之间的区别主要有:
1、远程视图主要用于桌面部件与通知栏部件,而页面视图用于APP页面;
2、远程视图只支持少数几种控件,如TextView、ImageView、Button、ImageButton、ProcessBar、Chronometer(计时器)、AnalogClock(模拟时钟);
3、远程视图不可直接设置控件信息,只能通过RemoteViews对象的set方法来设置;


下面是RemoteViews的常用方法:
RemoteViews : 构造函数。第一个参数是包名,第二个参数是布局文件id
setViewVisibility : 设置控件是否可见
setViewPadding : 设置控件的间距
setTextViewText : 设置TextView和Button的文本内容
setTextViewTextSize : 设置TextView和Button的文本大小
setTextColor : 设置TextView和Button的文本颜色
setTextViewCompoundDrawables : 设置TextView的周围图标
setImageViewResource : 设置ImageView和ImageButton的图片id
setImageViewBitmap : 设置ImageView和ImageButton的图片位图
setChronometer : 设置计时器信息
setProgressBar : 设置进度条信息
setOnClickPendingIntent : 设置控件点击的响应动作


使用示例

为演示本文提到的几种推送,博主编码实现了下列三种方式的推送:
1、采用默认模板推送一个通知;
2、采用RemoteViews方式推送通知,并可根据部件上的点击事件改变通知内容;
3、采用RemoteViews方式让后台服务保持在前台运行,并可由后台服务的运行进度来实时更新通知内容;


下面是采用RemoteViews方式的通知推送效果图:


下面是通知推送的示例代码:
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.RemoteViews;

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class NotificationActivity extends Activity implements OnClickListener {

	private static final String TAG = "NotificationActivity";
	private String mSong = "《两只老虎》";
	private String PLAY_EVENT = "";
	private boolean bPlay = true;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_notification);

		Button btn_default = (Button) findViewById(R.id.btn_default);
		Button btn_custom = (Button) findViewById(R.id.btn_custom);
		Button btn_service = (Button) findViewById(R.id.btn_service);
		btn_default.setOnClickListener(this);
		btn_custom.setOnClickListener(this);
		btn_service.setOnClickListener(this);

		PLAY_EVENT = getResources().getString(R.string.play_event);
	}
	
	private void sendDefaultNotify() {
		Intent clickIntent = new Intent(this, MainActivity.class);
		PendingIntent contentIntent = PendingIntent.getActivity(this,
				R.string.app_name, clickIntent,
				PendingIntent.FLAG_UPDATE_CURRENT);
		Intent cancelIntent = new Intent(this, MessengerActivity.class);
		PendingIntent deleteIntent = PendingIntent.getActivity(this,
				R.string.app_name, cancelIntent,
				PendingIntent.FLAG_UPDATE_CURRENT);

		Notification.Builder builder = new Notification.Builder(this);
		builder.setContentIntent(contentIntent)
				.setDeleteIntent(deleteIntent)
				.setUsesChronometer(true)
				.setProgress(100, 60, false)
				.setSubText("这里是副本")
				.setNumber(99)
				.setAutoCancel(false)
				.setSmallIcon(R.drawable.tt_s)
				.setTicker("提示文本")
				//.setWhen(System.currentTimeMillis())
				.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.tt_s))
				.setContentTitle("标题文本")
				.setContentText("内容文本");
		Notification notify = builder.build();

		NotificationManager notifyMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
		notifyMgr.notify(R.string.app_name, notify);
	}
	
	private void sendCustomNotify(boolean is_play) {
		bPlay = !bPlay;
		Intent pIntent = new Intent(PLAY_EVENT);
		PendingIntent nIntent = PendingIntent.getBroadcast(
				this, R.string.app_name, pIntent, PendingIntent.FLAG_UPDATE_CURRENT);
		RemoteViews widget_notify = new RemoteViews(getPackageName(), R.layout.widget_notify);
		if (is_play == true) {
			widget_notify.setTextViewText(R.id.btn_play, "暂停");
			widget_notify.setTextViewText(R.id.tv_play, mSong+"正在播放");
			widget_notify.setProgressBar(R.id.pb_play, 100, 10, false);
			widget_notify.setOnClickPendingIntent(R.id.btn_play, nIntent);
			widget_notify.setChronometer(R.id.chr_play, SystemClock.elapsedRealtime(), "%s", true);
		} else {
			widget_notify.setTextViewText(R.id.btn_play, "继续");
			widget_notify.setTextViewText(R.id.tv_play, mSong+"暂停播放");
			widget_notify.setProgressBar(R.id.pb_play, 100, 60, false);
			widget_notify.setChronometer(R.id.chr_play, SystemClock.elapsedRealtime(), "%s", false);
		}
		widget_notify.setOnClickPendingIntent(R.id.btn_play, nIntent);
		Intent intent = new Intent(this, MainActivity.class);
		PendingIntent contentIntent = PendingIntent.getActivity(this,
				R.string.app_name, intent,
				PendingIntent.FLAG_UPDATE_CURRENT);

		Notification.Builder builder = new Notification.Builder(this);
		builder.setContentIntent(contentIntent)
				.setContent(widget_notify)
				.setTicker(mSong)
				.setSmallIcon(R.drawable.tt_s);
		Notification notify = builder.build();
		
		NotificationManager notifyMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
		notifyMgr.notify(R.string.app_name, notify);
	}

	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.btn_default) {
			sendDefaultNotify();
		} else if (v.getId() == R.id.btn_custom) {
			sendCustomNotify(bPlay);
		} else if (v.getId() == R.id.btn_service) {
			Intent intent = new Intent(this, MusicService.class);
			intent.putExtra("is_play", bPlay);
			intent.putExtra("song", mSong);
			if (bPlay == true) {
				startService(intent);
			} else {
				stopService(intent);
			}
			bPlay = !bPlay;
		}
	}

	@Override
	public void onStart() {
		super.onStart();
		notifyReceiver = new NotifyReceiver();
		IntentFilter filter = new IntentFilter(PLAY_EVENT);
        registerReceiver(notifyReceiver, filter);
	}

	@Override
	public void onStop() {
        unregisterReceiver(notifyReceiver);
		super.onStop();
	}

    private NotifyReceiver notifyReceiver;
    public class NotifyReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent != null) {
        		sendCustomNotify(bPlay);
            }
        }
    }

}


下面是后台服务的示例代码:
import android.annotation.TargetApi;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;
import android.widget.RemoteViews;

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class MusicService extends Service {
	private static final String TAG = "MusicService";
	private final IBinder mBinder = new LocalBinder();

	public class LocalBinder extends Binder {
		public MusicService getService() {
			return MusicService.this;
		}
	}

	@Override
	public IBinder onBind(Intent intent) {
		Log.d(TAG, "onBind");
		return mBinder;
	}

	private String mSong;
	private String PAUSE_EVENT = "";
	private boolean bPlay = true;

	private long mBaseTime;
	private long mPauseTime = 0;
	private int mProcess = 0;
	private Handler mHandler = new Handler();
	private Runnable mPlay = new Runnable() {
		@Override
		public void run() {
			if (bPlay == true) {
				if (mProcess < 100) {
					mProcess+=2;
				} else {
					mProcess = 0;
				}
				mHandler.postDelayed(this, 200);
			}
			refresh();
		}
	};
	
	private void refresh() {
		Intent pIntent = new Intent(PAUSE_EVENT);
		PendingIntent nIntent = PendingIntent.getBroadcast(
				this, R.string.app_name, pIntent, PendingIntent.FLAG_UPDATE_CURRENT);
		RemoteViews widget_notify = new RemoteViews(getPackageName(), R.layout.widget_notify);
		if (bPlay == true) {
			widget_notify.setTextViewText(R.id.btn_play, "暂停");
			widget_notify.setTextViewText(R.id.tv_play, mSong+"正在播放");
			widget_notify.setProgressBar(R.id.pb_play, 100, mProcess, false);
			widget_notify.setOnClickPendingIntent(R.id.btn_play, nIntent);
			widget_notify.setChronometer(R.id.chr_play, mBaseTime, "%s", true);
		} else {
			widget_notify.setTextViewText(R.id.btn_play, "继续");
			widget_notify.setTextViewText(R.id.tv_play, mSong+"暂停播放");
			widget_notify.setProgressBar(R.id.pb_play, 100, mProcess, false);
			widget_notify.setChronometer(R.id.chr_play, mBaseTime, "%s", false);
		}
		widget_notify.setOnClickPendingIntent(R.id.btn_play, nIntent);
		Intent intent = new Intent(this, MainActivity.class);
		PendingIntent contentIntent = PendingIntent.getActivity(this,
				R.string.app_name, intent,
				PendingIntent.FLAG_UPDATE_CURRENT);

		Notification.Builder builder = new Notification.Builder(this);
		builder.setContentIntent(contentIntent)
				.setContent(widget_notify)
				.setTicker(mSong)
				.setSmallIcon(R.drawable.tt_s);
		Notification notify = builder.build();
		startForeground(1, notify);
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startid) {
		mBaseTime = SystemClock.elapsedRealtime();
		bPlay = intent.getBooleanExtra("is_play", true);
		mSong = intent.getStringExtra("song");
		Log.d(TAG, "bPlay="+bPlay+", mSong="+mSong);
		mHandler.postDelayed(mPlay, 200);
		
		return START_STICKY;
	}
	
	@Override
	public void onCreate() {
		PAUSE_EVENT = getResources().getString(R.string.pause_event);
		pauseReceiver = new PauseReceiver();
		IntentFilter filter = new IntentFilter(PAUSE_EVENT);
        registerReceiver(pauseReceiver, filter);
		super.onCreate();
	}
	
	@Override
	public void onDestroy() {
        unregisterReceiver(pauseReceiver);
		super.onDestroy();
	}

    private PauseReceiver pauseReceiver;
    public class PauseReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent != null) {
            	bPlay = !bPlay;
            	if (bPlay == true) {
            		mHandler.postDelayed(mPlay, 200);
            		if (mPauseTime > 0) {
                		long gap = SystemClock.elapsedRealtime() - mPauseTime;
                		mBaseTime += gap;
            		}
            	} else {
            		mPauseTime = SystemClock.elapsedRealtime();
            	}
            }
        }
    }

}





点此查看Android开发笔记的完整目录
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值