一个 toast 是在屏幕上弹出一条信息,它的大小总是包裹着需要显示的内容,并且当前的 Activity 依然是可见并且可互动的。toast会自动消失,并且不接受任何互动事件。因为 toast 可以在后台的 Service 中创建,所以即使这个应用程序没有显示在屏幕上,仍然可以弹出
toast.
toast 最好用来显示简要的信息,比如断定用户正在注意屏幕时,弹出"File saved". toast 不能接受任何用户互动事件,如果需要用户响应并采取操作,考虑使用 Status Notification 来替代.。
下图显示了Alarm应用的一个toast通知的例子。当一个闹铃开启的时候,一条toast消息显示出来提醒你设置闹铃成功。

Context context = getApplicationContext();CharSequence text = "Hello toast!"intduration = Toast.LENGTH_SHORT;Toast toast = Toast.makeText(context, text, duration);toast.show();
你也可以直接调用该方法已避免保留一个Toast对象,例如:
Toast.makeText(context, text, duration).show();
toast.setGravity(Gravity.TOP | Gravity.LEFT, 0, 0);
如果一个简单的文本消息已经无法满足你的需求,你可以自己定义一个toast通知的布局layout。在XML或者代码中定义一个View的布局,并根View对象传递给setView(View)方法。
例如,你可以用如下所示XML创建右图中的toast通知的布局(保存为toast_layout.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/toast_layout_root"android:orientation="horizontal"android:layout_width="fill_parent"android:layout_height="fill_parent"android:padding="10dp"android:background="#DAAA" ><ImageView android:id="@+id/image"android:layout_width="wrap_content"android:layout_height="fill_parent"android:layout_marginRight="10dp"/><TextView android:id="@+id/text"android:layout_width="wrap_content"android:layout_height="fill_parent"android:layout_textColor="#FFF"/></LinearLayout>
LayoutInflater inflater = getLayoutInflater();View layout = inflater.inflate(R.layout.toast_layout,(ViewGroup) findViewById(R.id.toast_layout_root));ImageView image = (ImageView) layout.findViewById(R.id.image);image.setImageResource(R.drawable.android);TextView text = (TextView) layout.findViewById(R.id.text);text.setText("Hello! This is a custom toast!");Toast toast = new Toast(getApplicationContext());toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);toast.setDuration(Toast.LENGTH_LONG);toast.setView(layout);toast.show();
Notification 和NotificationManager.Notification 的一个实例定义你状态通知的属性,如状态图标,通知消息,和扩展设置(播放提示音等)。 NotificationManager 是安卓系统服务,它执行和管理所有的状态通知。
你不要直接实例化 NotificationManager 。应该使用getSystemService() 方法来获取 NotificationManager 对象的引用。然后,通过notify() 方法将你的 Notification 发送出去。NotificationManager的引用:
String ns = Context.NOTIFICATION_SERVICE;NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
Notification:int icon = R.drawable.notification_icon;CharSequence tickerText = "Hello";long when = System.currentTimeMillis();Notification notification = new Notification(icon, tickerText, when);
PendingIntent:Context context = getApplicationContext();CharSequence contentTitle = "My notification";CharSequence contentText = "Hello World!";Intent notificationIntent = new Intent(this, MyClass.class);PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
private static final int HELLO_ID = 1;mNotificationManager.notify(HELLO_ID, notification);
makeMessageIntentStack(),它构造了代表新的acticity栈中的
intents.(如果使用fragments,你会需要初始化你的 fragment和应用状态,以便当用户点击返回时,会返回到fragment的上一个状态)
这个方法的核心代码是 Intent.makeRestartActivityTask() 方法,它会使用合适的标志创建
activity 栈中的根 activity,比如 Intent.FLAG_ACTIVITY_CLEAR_TASK./*** 这个方法创建了一个Intent 对象数组,这些intent 代表了activity 栈中传入的消息细节,当从通知中启动时会被使用。*/static Intent[] makeMessageIntentStack(Context context, CharSequence from,CharSequence msg) {// 用户深入应用程序中时,一个代表数据的典型通知发布了出来// 为了实现这个,需要创建一个intents 数组来表示显示的层级顺序。.Intent[] intents = new Intent[4];// First:该实例的跟activity// 这是一个让Intent 启动或重置应用栈的简便方法intents[0] = Intent.makeRestartActivityTask(new ComponentName(context,com.example.android.apis.ApiDemos.class));// "App"intents[1] = new Intent(context, com.example.android.apis.ApiDemos.class);intents[1].putExtra("com.example.android.apis.Path", "App");// "App/Notification"intents[2] = new Intent(context, com.example.android.apis.ApiDemos.class);intents[2].putExtra("com.example.android.apis.Path", "App/Notification");// 现在,这个activity展示在了用户面前。当然它的所有数据也一并展示。intents[3] = new Intent(context, IncomingMessageView.class);intents[3].putExtra(IncomingMessageView.KEY_FROM, from);intents[3].putExtra(IncomingMessageView.KEY_MESSAGE, msg);return intents;}/*** 状态栏通知相关的图标和扩展条目*/void showAppNotification() {// 查找 notification manager serviceNotificationManager nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);// 模拟数据的细节CharSequence from = "Joe";CharSequence message;switch ((new Random().nextInt()) % 3) {case 0: message = "r u hungry? i am starved"; break;case 1: message = "im nearby u"; break;default: message = "kthx. meet u for dinner. cul8r"; break;}// 当用户点击这个通知时,PendingIntent 会启动我们的activity// 注意FLAG_CANCEL_CURRENT// 如果已经有一个匹配的intent 在等待,取消并替换它为数组中最新的intentPendingIntent contentIntent = PendingIntent.getActivities(this, 0,makeMessageIntentStack(this, from, message), PendingIntent.FLAG_CANCEL_CURRENT);// The ticker text, this uses a formatted string so our message could be localizedString tickerText = getString(R.string.imcoming_message_ticker_text, message);// 构造Notification object.Notification notif = new Notification(R.drawable.stat_sample, tickerText,System.currentTimeMillis());// 在通知面板显示的信息notif.setLatestEventInfo(this, from, message, contentIntent);// 我们要这个通知发出提示音,震动和闪烁led灯// 注:如果你要使用这些功能,你应该有一个选项面板以便于用户可以根据自己喜好开启或关闭这些功能,notif.defaults = Notification.DEFAULT_ALL;//注:我们使用的是R.layout.incoming_message_panel 作为我们通知的id// 它可以是你想的任何整数// 但是为了方便,使用了与字符有个的资源id// 它在你的应用中永远会是独一的数字。nm.notify(R.string.imcoming_message_ticker_text, notif);}
在一个日历的通知中,通知启动的界面通常不属于应用程序的进程。比如当用户收到日历的通知时,选择这个通知将会启动一个特殊界面来显示代办事项—这个界面仅能从通知中启动,无法通过日历导航过去.
下面的代码发送了一条这样的通知,与上面的通知相似,但是 PendingIntent 只能展示一个activity,也就是专门用来显示代办事项的activity.
/*** 这个通知是状态栏通知*/void showInterstitialNotification() {//查找 the notification manager serviceNotificationManager nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);// The details of our fake messageCharSequence from = "Dianne";CharSequence message;switch ((new Random().nextInt()) % 3) {case 0: message = "i am ready for some dinner"; break;case 1: message = "how about thai down the block?"; break;default: message = "meet u soon. dont b late!"; break;}// The PendingIntent to launch our activity if the user selects this// notification. Note the use of FLAG_CANCEL_CURRENT so that, if there// is already an active matching pending intent, cancel it and replace// it with the new Intent.Intent intent = new Intent(this, IncomingMessageInterstitial.class);intent.putExtra(IncomingMessageView.KEY_FROM, from);intent.putExtra(IncomingMessageView.KEY_MESSAGE, message);intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);PendingIntent contentIntent = PendingIntent.getActivity(this, 0,intent, PendingIntent.FLAG_CANCEL_CURRENT);// The ticker text, this uses a formatted string so our message could be localizedString tickerText = getString(R.string.imcoming_message_ticker_text, message);// construct the Notification object.Notification notif = new Notification(R.drawable.stat_sample, tickerText,System.currentTimeMillis());// Set the info for the views that show in the notification panel.notif.setLatestEventInfo(this, from, message, contentIntent);// We‘ll have this notification do the default sound, vibration, and led.// Note that if you want any of these behaviors, you should always have// a preference for the user to turn them off.notif.defaults = Notification.DEFAULT_ALL;// Note that we use R.layout.incoming_message_panel as the ID for// the notification. It could be any integer you want, but we use// the convention of using a resource id for a string related to// the notification. It will always be a unique number within your// application.nm.notify(R.string.imcoming_message_ticker_text, notif);}
android:launchMode="singleTask", android:taskAffinity="" 和 android:excludeFromRecents="true".完整的描述如下:<activity android:name=".app.IncomingMessageInterstitial"android:label="You have messages"android:theme="@style/ThemeHoloDialog"android:launchMode="singleTask"android:taskAffinity=""android:excludeFromRecents="true"></activity>
makeMessageIntentStack() 方法,完成类似下面的点击事件:/*** 切换app 一个新的activity 栈已经开启代替目前运行的activity之后,该activity 结束。*/void switchToApp() {//展示给给用户选择启动哪个app//CharSequence from = getIntent().getCharSequenceExtra(IncomingMessageView.KEY_FROM);CharSequence msg = getIntent().getCharSequenceExtra(IncomingMessageView.KEY_MESSAGE);// Build the new activity stack, launch it, and finish this UI.Intent[] stack = IncomingMessage.makeMessageIntentStack(this, from, msg);startActivities(stack);finish();}
String ns = Context.NOTIFICATION_SERVICE;NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
notify(int,
Notification).方法将 Notification 传递给 NotificationManager。first 第一个参数是通知的唯一ID,第二个参数是Notification 对象。ID是你应用中通知的唯一标识。ID是必要的,如果你需要更新通知或者(如果你应用中组织了各种各样的通知)当用户通过定义在通知中的
intent 返回你的应用时,需要选择合适的 action.Notification.添加"FLAG_AUTO_CANCEL"flag
。也可以通过cancel(int)手动清除,传递给它通知的ID,或者清除所有的通知cancelAll().PendingIntent,
当通知被选中时激活。Notification(int,
CharSequence, long) 构造器和setLatestEventInfo(Context,
CharSequence, CharSequence, PendingIntent) 方法。他们定义了一个通知的所需的配置。下面的片段创建了一个基本通知:int icon = R.drawable.notification_icon; // icon from resourcesCharSequence tickerText = "Hello"; // ticker-textlong when = System.currentTimeMillis(); // notification timeContext context = getApplicationContext(); // application ContextCharSequence contentTitle = "My notification"; // message titleCharSequence contentText = "Hello World!"; // message textIntent notificationIntent = new Intent(this, MyClass.class);PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);// the next two lines initialize the Notification, using the configurations aboveNotification notification = new Notification(icon, tickerText, when);notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
NotificationManager 管理的整数ID,你可以通过调用setLatestEventInfo()附加新的值来修改你的通知,改变一些通知的字段值,然后再次调用notify()notify() 来更新通知。(当然,如果你用的是自定义的通知布局,更新这些标题和文本值是没有任何意义的)notification.defaults |= Notification.DEFAULT_SOUND;
notification.sound = Uri.parse("file:///sdcard/notification/ringer.mp3");
notification.sound = Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "6");
这个示例中,音频文件的ID是已知的并且被附到 Uri 后面。如果不知到确切的
ID值,必须通过 ContentResolver 去查询所有存储在 MediaStore 中的音频文件。怎样使用 ContentResolver 可以在 Content
Providers 中查看。
如果你需要一直循环播放声音直到用户点击通知或者取消通知,给通知的 flags 属性添加 FLAG_INSISTENT 值。
注:如果 defaults 属性中有 DEFAULT_SOUND 这个值,那么默认的声音将会覆盖 sound 属性中设置的声音。
notification.defaults |= Notification.DEFAULT_VIBRATE;
long[] vibrate = {0,100,200,300};notification.vibrate = vibrate;
使用闪光灯来提示用户,可以使用默认的闪光灯,也可以在程序中自定义闪光灯的颜色和形式.
要使用默认的闪光灯设置,需要给 defaults 属性设置添加一个 DEFAULT_LIGHTS 值:
notification.defaults |= Notification.DEFAULT_LIGHTS;
FLAG_SHOW_LIGHTS 标志:notification.ledARGB = 0xff00ff00;notification.ledOnMS = 300;notification.ledOffMS = 1000;notification.flags |= Notification.FLAG_SHOW_LIGHTS;
还可以使用 Notification 的属性和标志增加更多的功能,一些常用的如下:
FLAG_AUTO_CANCEL 标志FLAG_INSISTENT flagFLAG_ONGOING_EVENT flagFLAG_NO_CLEAR flagnumber fieldiconLevel fieldLevelListDrawable 的等级。你可以通过切换你定义在LevelListDrawable中的图片,来让你通知的图标动起来。阅读 LevelListDrawable 获取更多信息.
查看 Notification 来去找到更多你可以使用的功能.
RemoteViews.来自定义通知布局。custom_notification.xml:<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/layout"android:layout_width="fill_parent"android:layout_height="fill_parent"android:padding="10dp" ><ImageView android:id="@+id/image"android:layout_width="wrap_content"android:layout_height="fill_parent"android:layout_alignParentLeft="true"android:layout_marginRight="10dp" /><TextView android:id="@+id/title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_toRightOf="@id/image"style="@style/NotificationTitle" /><TextView android:id="@+id/text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_toRightOf="@id/image"android:layout_below="@id/title"style="@style/NotificationText" /></RelativeLayout>
res/values/styles.xml 中的样式:<?xml version="1.0" encoding="utf-8"?><resources><style name="NotificationText"><item name="android:textColor">?android:attr/textColorPrimary</item></style><style name="NotificationTitle"><item name="android:textColor">?android:attr/textColorPrimary</item><item name="android:textStyle">bold</item></style><!-- If you want a slightly different color for some text,consider using ?android:attr/textColorSecondary --></resources>
<?xml version="1.0" encoding="utf-8"?><resources><style name="NotificationText" parent="android:TextAppearance.StatusBar.EventContent" /><style name="NotificationTitle" parent="android:TextAppearance.StatusBar.EventContent.Title" /></resources>
RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.custom_notification_layout);contentView.setImageViewResource(R.id.image, R.drawable.notification_image);contentView.setTextViewText(R.id.title, "Custom notification");contentView.setTextViewText(R.id.text, "This is a custom layout");notification.contentView = contentView;
setImageViewResource() 和setTextViewText()为ImageView 和TextView定义内容。将你要设置的View
的 ID 和对应的值一起传给这些方法。最后将 RemoteViews 对象传给通知的 contentView 属性。Intent notificationIntent = new Intent(this, MyClass.class);PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);notification.contentIntent = contentIntent;
mNotificationManager.notify(CUSTOM_VIEW_ID, notification);
对话框是在当前 activity 上弹出一个小的窗口,对话框下面的 activity 将是去焦点,对话框开始与用户互动。对话框通常显示在正在运行的程序的 notification 和 activity 中。
当你需要显示进度条或者需要用户确认时(比如带有 "OK" 和 "Cancel"按钮),应该弹出对话框。你可以将对话框作为应用 UI 的组成部分,还可以使用它来处理不使用 notification 的情况。各种各样的对话框样式,请见 Dialogs 部分。
原文:http://blog.csdn.net/yh_android_blog/article/details/51858691