- PVSM.RU - https://www.pvsm.ru -
Добрый день. Давно занимаюсь разработкой под Android и хотелось бы рассказать сообществу о правильном подходе к созданию уведомлений.
На хабре уже есть статья по уведомлениям в статус баре для андроид [1]. В ней рассматриваются основы отображения стандартного и конфигурируемого layout в статус баре.
Ниже, помимо описанного ранее, мы рассмотрим добавление прогрессбара, обработку события по нажатию на уведомлений, различные варианты состояний уведомлений. Рассмотрим добавленный на днях в Compatibility library Notification.Builder. А также поговорим о рекомендациям по UI (design guidlines [2]), которые гугл рекомендует соблюдать при создании уведомлений.
Guidlines
Как советуют разработчики Android в официальном гайдлайне [3]
В качестве утилитки, отвечающей за уведомления, я в своих приложениях использую singleton [6], к которому можно обратиться из любого класса приложения, нужно лишь иметь ссылку на context [7].
В ней всегда хранятся ссылки на все созданные во время работы приложения уведомления, которые ещё отображены в статус-баре.
А для присвоения новому уведомлению уникального id используется нехитрый механизм обращения к приватному целочисленному полю, которое каждый раз увеличивается на единицу.
public class NotificationUtils {
private static final String TAG = NotificationUtils.class.getSimpleName();
private static NotificationUtils instance;private Context context;
private NotificationManager manager; // Системная утилита, упарляющая уведомлениями
private int lastId = 0; //постоянно увеличивающееся поле, уникальный номер каждого уведомления
private HashMap<Integer, Notification> notifications; //массив ключ-значение на все отображаемые пользователю уведомления
//приватный контструктор для Singleton
private NotificationUtils(Context context){
this.context = context;
manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notifications = new HashMap<Integer, Notification>();
}
/**
* Получение ссылки на синглтон
*/
public static NotificationUtils getInstance(Context context){
if(instance==null){
instance = new NotificationUtils(context);
}
return instance;
}* This source code was highlighted with Source Code Highlighter [8].
Создание уведомления с помощью NotificationCompat.Builder:
Для того чтобы воспользоваться классами, входящими в библиотеку поддержки прошлых версий (Compatibility library) [9], нужно добавить в проект библиотеку из папки /extras/android/support/v4/android-support-v4.jar
Если же проект нацелен на Android 3.0 и выше, то добавлять ничего не нужно достаточно обратиться к Notification.Builder
public int createInfoNotification(String message){
Intent notificationIntent = new Intent(context, HomeActivity.class); // по клику на уведомлении откроется HomeActivity
NotificationCompat.Builder nb = new NotificationCompat.Builder(context)
//NotificationCompat.Builder nb = new NotificationBuilder(context) //для версии Android > 3.0
.setSmallIcon(R.drawable.ic_action_picture) //иконка уведомления
.setAutoCancel(true) //уведомление закроется по клику на него
.setTicker(message) //текст, который отобразится вверху статус-бара при создании уведомления
.setContentText(message) // Основной текст уведомления
.setContentIntent(PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT))
.setWhen(System.currentTimeMillis()) //отображаемое время уведомления
.setContentTitle("AppName") //заголовок уведомления
.setDefaults(Notification.DEFAULT_ALL); // звук, вибро и диодный индикатор выставляются по умолчаниюNotification notification = nb.getNotification(); //генерируем уведомление
manager.notify(lastId, notification); // отображаем его пользователю.
notifications.put(lastId, notification); //теперь мы можем обращаться к нему по id
return lastId++;
}* This source code was highlighted with Source Code Highlighter [8].
Создание уведомления с произвольным отображением (Custom layout):
/**
* Создание уведомления с прогрессбаром о загрузке
* @param fileName - текст, отображённый в заголовке уведомления.
*/
public int createDownloadNotification(String fileName){
String text = context.getString(R.string.notification_downloading).concat(" ").concat(fileName); //текст уведомления
RemoteViews contentView = createProgressNotification(text, context.getString(R.string.notification_downloading)); //View уведомления
contentView.setImageViewResource(R.id.notification_download_layout_image, R.drawable.ic_stat_example); // иконка уведомления
return lastId++; //увеличиваем id, которое будет соответствовать следующему уведомлению
}/**
* генерация уведомления с ProgressBar, иконкой и заголовком
*
* @param text заголовок уведомления
* @param topMessage сообщение, уотображаемое в закрытом статус-баре при появлении уведомления
* @return View уведомления.
*/
private RemoteViews createProgressNotification(String text, String topMessage) {
Notification notification = new Notification(R.drawable.ic_stat_example, topMessage, System.currentTimeMillis());
RemoteViews contentView = new RemoteViews(context.getPackageName(), R.layout.notification_download_layout);
contentView.setProgressBar(R.id.notification_download_layout_progressbar, 100, 0, false);
contentView.setTextViewText(R.id.notification_download_layout_title, text);
notification.contentView = contentView;
notification.flags = Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT | Notification.FLAG_ONLY_ALERT_ONCE;Intent notificationIntent = new Intent(context, NotificationUtils.class);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.contentIntent = contentIntent;
manager.notify(lastId, notification);
notifications.put(lastId, notification);
return contentView;
}
notification_download_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="65sp"
android:padding="10dp"
android:orientation="vertical" ><LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" ><ImageView
android:id="@+id/notification_download_layout_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_stat_example"
android:layout_gravity="center_vertical" /><TextView
android:id="@+id/notification_download_layout_title"
style="@style/NotificationTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="10dip"
android:singleLine="true"
android:text="notification_download_layout_title"
android:layout_gravity="center_vertical" />
</LinearLayout><ProgressBar
android:id="@+id/notification_download_layout_progressbar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:progress="0" /></LinearLayout>
в андроид 2.3 и выше ( API >10) был создан специальный ресурс, в котором системная тема указывает цвета текста уведомений. Из-за этого в старых версиях приходится использовать костыль:
В файл 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>
</resources>
А для поддержки API >10 Создаем файл res/values-v9/styles.xml и вписываем:
<?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>
Теперь из кода нашего приложения обращаемся к утилите:
NotificationUtils n = NotificationUtils.getInstance(getActivity());
n.createInfoNotification("info notification");
Создаем уведомление с прогресс-баром:
int pbId = NotificationUtils.getInstance(getActivity()).createDownloadNotification("downloading video");
И во время выполнения потока постоянно обновляем прогресс вызовом:
NotificationUtils.getInstance(getActivity()).updateProgress(pbId, YOUR_PROGRESS);
В итоге получаем:
Как видно — нижнее уведомление, созданное нами при помощи билдера может быть удалено в любой момент. А уведомление с прогресс-баром размещается в верхнем блоке уведомлений, в котором пользователь не может очистить уведомления.
И напоследок маленькая хитрость:
Если не хотите дублирования в стеке одних и тех же Activity — поставьте в манифесте к нужной activity
android:launchMode="singleTop"
Автор: nekdenis
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/android-development/4461
Ссылки в тексте:
[1] уведомлениям в статус баре для андроид : http://habrahabr.ru/blogs/android_development/111238
[2] design guidlines: http://developer.android.com/design/index.html
[3] официальном гайдлайне: http://developer.android.com/design/patterns/notifications.html
[4] диалогами: http://developer.android.com/guide/topics/ui/dialogs.html
[5] онлайн-редактором: http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html#group-icon-generators
[6] singleton: http://habrahabr.ru/post/129494/
[7] context: http://developer.android.com/reference/android/content/Context.html
[8] Source Code Highlighter: http://virtser.net/blog/post/source-code-highlighter.aspx
[9] библиотеку поддержки прошлых версий (Compatibility library): http://developer.android.com/sdk/compatibility-library.html
Нажмите здесь для печати.