在系统发生事件的时候,需要使用某种方法通知用户。在Android系统中,用户通知过程通常不宜打断用户当前的操作。
Android的用户通知方法包含以下三种。
Status Bar Notification:状态栏通知;
在几种通知方式中,Dialog在实现上属于活动的一部分,只能用于活动。Toast通知和Status Bar通知可以用于后台程序。当Service和BroadcastReceiver中的某个“事件”被激发的时候,常常使用Toast和Status Bar在不打断用户操作的情况下,对用户进行提示。
è 6.5.1 Toast通知Toast是一种简单的通知方式,消息可以自动消失,可以使用布局文件构建较为复杂的Toast,但是不能和用户进行交互。
Toast通知主要需要使用android.widget包中的Toast类来完成,几个通过Toast实现的通知效果如图6-7所示。
图6-7 Toast通知效果(左:基本;中:定义位置;右:使用布局)
1.基本使用方法Toast具有以下两个静态的方法,用于得到一个Toast的实例:
static Toast makeText(Context context, CharSequence text, int duration)
static Toast makeText(Context context, int resId, int duration)
makeText()需要传入当前的上下文,再附加文本信息或者资源文件id,持续时间(可义设置为LENGTH_SHORT 和 LENGTH_LONG两个数值)。直接在代码中使用akeText(),就可以启动一个Toast。
如图6-7中左图所示,一个简单的Toast使用的代码如下:
public void toast_1(Context context)
{
Toast toast = Toast.makeText(context, "Toast 1\n"
+"1. long duration\n"
+"2. Default Position.\n"
+"3. Default layout.", Toast.LENGTH_LONG);
toast.show(); // 显示Toast
}
如图6-7中中图所示,一个带有位置控制的Toast使用的代码如下:
public void toast_2(Context context)
{
Toast toast = Toast.makeText(context, "Toast 2\n"
+"1. long duration\n"
+"2. Custom Position.\n"
+"3. Default layout.", Toast.LENGTH_LONG);
toast.setGravity(Gravity.LEFT | Gravity.CENTER, 20,20);
toast.show(); // 显示Toast
}
由于使用setGravity()进行了设置,将Toast的内容置于了居中偏左的位置。
2.扩展的使用方法Toast中包含一些设置接口,甚至可以将一个View设置到其中。Toast类中一些额外的方法如下所示:
public void setText(CharSequence s) // 设置文本
public void setDuration(int duration) // 设置持续时间
public void setGravity(int gravity, int xOffset, int yOffset) // 设置对齐
public void setMargin(float horizontalMargin, float verticalMargin) // 设置边缘
public void setView(View view) // 设置其中的视图
setDuration()和setDuration ()用于设置Toast中的文本和持续时间;setGravity()和setMargin()方法用于设置Toast的对齐方式和边缘。setView()方法用于定义Toast中的内容视图,可以结合LayoutInflater和布局文件来使用。
自定义其中内容使用Toast的方法如下所示。
public void toast_3(Context context)
{
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(R.layout.toast_notification,null);
TextView tv = (TextView)v.findViewById(R.id.text);
tv.setText("Layout Toast.\nNote: Can't use Button !");
Toast toast = new Toast(context); // 建立Toast
toast.setView(v); // 设置其中的View
toast.show(); // 显示Toast
}
其中使用的布局文件toast_notification.xml的内容如下所示:
android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="@android:drawable/picture_frame"> android:background="#ff7f0000" android:layout_width="100dp" android:layout_height="100dp" /> android:textSize="25dp" android:textColor="#ff000000" android:layout_width="wrap_content" android:layout_height="wrap_content" /> android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical" > android:layout_width="wrap_content" android:layout_height="wrap_content" />
Toast持续的时间有限,并且默认不能接收事件,因此即使自定义了布局,也不能在其中使用Button等控件处理事件。
è 6.5.2 Status Bar通知Status Bar表示Android系统的状态栏,它不属于任何一个Activity。因此状态栏可以作为整个Android系统的公共区域来使用,通知的内容可以发送到状态栏上。
1.基本使用方法状态栏通知使用android.app包中的NotificationManager和Notification类来完成。
NotificationManager类是一个Android中的“系统服务”,以Context.NOTIFICATION_SERVICE为参数调用Context类的getSystemService()方法可以获得一个NotificationManager的实例。Notification则表示了一个具体通知的呈现方式,这些内容以Notification类的一些公共属性来表示。
一个Notification包含以下的内容:
展开后的文本(对应tickerText属性,表示从状态栏展开看到的文本);
打开通知(对应PendingIntent类型的deleteIntent属性);
ticker-text(可选,对应tickerText属性,表示反复显示的文本);
指示灯(可选,对应ledARGB、ledOnMS、ledOffMS等属性);
一个发送短信息的状态栏通知如图6-8所示。
图6-8 状态栏通知(左:状态栏通知;中:状态栏通知展开;右:启动设置程序)
状态通知发生后,会显示其图标到状态栏上。每一个状态栏通知可以被展开,展开之后将显示文本、图标、通知时间等信息。
一个简单的状态栏通知可以按照如下步骤进行。
第一步,创建NotificationManager,代码如下所示:
NotificationManager mnotificationManager = (NotificationManager)context
.getSystemService(Context.NOTIFICATION_SERVICE);
第二步,初始化Notification,代码如下所示:
int icon = android.R.drawable.btn_star_big_on;
CharSequence tickerText = "Ticker Text"; // 通知在状态栏的信息
long when = System.currentTimeMillis(); // 通知的时间
CharSequence contentTitle = "Content Title"; // 通知展开后的标题
CharSequence contentText = "Content Text : Settings ...... ! "; // 通知展开后的内容
第三步,构建通知的Intent,代码如下所示:
Notification notification = new Notification(icon, tickerText, when);
Intent intent = new Intent();
intent.setClassName("com.android.settings", // 建立Intent
"com.android.settings.Settings");
PendingIntent contentIntent = // 用于处理通知的PendingIntent事件
PendingIntent.getActivity(context, 0, intent, 0);
notification.setLatestEventInfo(context, contentTitle, // 设置通知的信息
contentText, contentIntent);
第四步,实现通知,代码如下所示:
mnotificationManager.notify(1, notification); // 进行状态栏通知
在状态栏通知的实现过程中,当通知内容在状态栏被展开之后,将进行通知的事件,这些事件将使用PendingIntent来表示。使用这种方式可以引领用户进入通知的构造者希望进入的场景,一般情况下是启动一个Activity。
以上程序的执行结果如6-8图所示。
此外,NotificationManager的cancel()方法用于清除一个通知,其参数为int类型 id,此数值的含义和notify()方法中的id相同。
2.使用远程视图状态栏还可以配合RemoteViews来使用,以此通知展开后的外观。此时的外观需要使用“远程视图”的方式来构建,这是因为对于状态栏通知展开后的外观属于状态栏程序,而这个外观的实现者一般是通知的发起者,属于另外一个应用程序包。这种在另外的一个应用程序包中呈现外观的方式,就是“远程视图”。
android.widget包中的RemoteViews类表示一个远程视图。这个类并不是一个View的继承者。
RemoteViews的构造函数和主要方法如下所示:
RemoteViews(String packageName, int layoutId)
public void setTextViewText(int viewId, CharSequence text)
public void setImageViewBitmap(int viewId, Bitmap bitmap)
public void setImageViewResource(int viewId, int srcId)
public void setImageViewUri(int viewId, Uri uri)
public void setProgressBar(int viewId,int max,int progress,boolean indeterminate)
public void setViewVisibility(int viewId,int visibility)
public void setChronometer(int viewId, long base, String format, boolean started)
public void setOnClickPendingIntent(int viewId, PendingIntent pendingIntent)
在构造的时候,传入一个布局文件表示RemoteViews的外观。构建完成后,可以通过setTextViewText(),setImageViewResource()等方法根据资源id设置RemoteViews中的内容;setOnClickPendingIntent()用于设置某个id被点击时发送的PendingIntent。
RemoteViews并不能像本地的视图和布局那样灵活的时候,它对设置在其中的布局文件有所要求:
RemoteViews中只能使用FrameLayout、LinearLayout和RelativeLayout几种布局。
RemoteViews中只能使用AnalogClock,Button,Chronometer,ImageButton,ImageView,ProgressBar和TextView几种控件。
由于要在两个包之间使用,RemoteViews对事件响应的处理也比较简单,只能在被点击的时候发送一个PendingIntent。
Notification类有一个公有属性contentView,类型为RemoteViews。一个使用RemoteViews的程序的运行结果如图6-9所示。
图6-9 使用RemoteViews的程序的运行结果(左:状态栏通知;中:状态栏通知展开;右:启动浏览器)
程序的主要代码如下所示:
public void statusbar_2(Context context)
{
NotificationManager mNotificationManager = (NotificationManager)context
.getSystemService(Context.NOTIFICATION_SERVICE);
int icon = android.R.drawable.ic_delete;
CharSequence tickerText = "Hello"; // 通知在状态栏的信息
long when = System.currentTimeMillis(); // 通知的时间
Notification notification = new Notification(icon, tickerText, when);
// 建立通知对应的Intent
Uri uri = Uri.parse("about://blank");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
PendingIntent contentIntent = // 建立PendingIntent
PendingIntent.getActivity(context, 0, intent, 0);
// 设置通知的事件信息
notification.setLatestEventInfo(context,"","",contentIntent);
RemoteViews contentView = new RemoteViews( // 建立RemoteViews
context.getPackageName(),R.layout.statusbar_notification);
notification.contentView = contentView; // 设置RemoteViews
mNotificationManager.notify(2, notification); // 进行状态栏通知
}
在以上的程序中,由于为id为statusbar_notification的布局文件设置了RemoteViews,因此这个布局文件中的内容就是呈现在Notification下拉列表中的内容。
statusbar_notification.xml布局文件的内容如下所示:
android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" android:gravity="center_vertical" > android:layout_width="wrap_content" android:layout_height="wrap_content" /> android:layout_width="wrap_content" android:layout_height="wrap_content" /> android:layout_width="wrap_content" android:layout_height="wrap_content" />
从运行结果中可以得知,当设置了Notification中的contentView之后,将使用其中的布局表示展开后的内容,不再使用以contentTitle和contentText为内容的默认布局,根据这种方法可以自定义StatusBar通知展开后布局。
提示:在状态栏通知中,RemoteViews表示的远程布局作为整体使用,为其中的一个控件设置setOnClickPendingIntent将没有效果。