Android notification progress bar

Android Notifications. Оповещения через Status Bar

Добрый день, хабровчане. Давно занимаюсь разработкой под Android и хотелось бы рассказать сообществу о правильном подходе к созданию уведомлений.

На хабре уже есть статья по уведомлениям в статус баре для андроид . В ней рассматриваются основы отображения стандартного и конфигурируемого layout в статус баре.

Ниже, помимо описанного ранее, мы рассмотрим добавление прогрессбара, обработку события по нажатию на уведомлений, различные варианты состояний уведомлений. Рассмотрим добавленный на днях в Compatibility library Notification.Builder. А также поговорим о рекомендациям по UI (design guidlines), которые гугл рекомендует соблюдать при создании уведомлений.

Guidlines
Как советуют разработчики Android в официальном гайдлайне

Когда показывать уведомления:
  • Мы показываем уведомления, когда не хотим отвлекать пользователя, перекрывая ему экран нашими диалогами или переходом на экран уведомления. Мы не отвлекаем пользователя, но при этом не лишаем его возможности узнать содержание нашего уведомления в любой момент.
  • Чаще всего уведомления не всплывают спонтанно, а появляются в моменты, когда пользователь ожидает реакции от приложения.
  • В первую очередь уведомления должны отражать события, зависящие от времени. Как то: события календаря, входящие сообщения, запросы из социальных сетей.
Когда не стоит показывать уведомления:
  1. Не нужно показывать уведомления для не важных псевдо-зависящих от времени событий. Например, новости из социальных сетей.
  2. Нет необходимости показывать то, что уже отображено в UI приложения.
  3. Не стоит отображать ход низкоуровневых операций, вроде обращения к БД.
  4. Если приложение быстро само исправляет ошибку, то не нужно вовсе показывать эту ошибку, тем более уведомлением.
  5. Не показывайте уведомления о сервисах, которые пользователь не может контролировать.
  6. Плохим подходом является создание большого числа уведомлений, с целью напоминать пользователю о приложении, показывая постоянно его иконку и имя.
Хорошая практика:

  1. По клику на уведомление, пользователю должен открываться соответствующий экран приложения. В некоторых случаях достаточно, чтобы по клику уведомление просто убиралось.
  2. Указание времени события в уведомлении, также является хорошим подходом.
  3. Рекомендуется схожие события складывать в одно уведомление, а не отображать на каждое событие своё.
  4. Всегда убирать из статус-бара уведомления, с которыми пользователь уже ознакомился и произвел соответствующие действия.
  5. Показывать маленькое превью уведомления при его создании в свёрнутом статус-баре
  6. Позволять пользователю отключать уведомления в настройках приложения.
  7. Использовать иконки, обозначающие принадлежность уведомления определённому приложению. Иконки делать монохромными. Для этого рекомндуется воспользоваться специальным онлайн-редактором
  8. В случае, если событие требует непосредственной реакции пользователя — вместо уведомлений использовать диалоги.
Архитектура:

В качестве утилитки, отвечающей за уведомления, я в своих приложениях использую singleton, к которому можно обратиться из любого класса приложения, нужно лишь иметь ссылку на context.

В ней всегда хранятся ссылки на все созданные во время работы приложения уведомления, которые ещё отображены в статус-баре.

А для присвоения новому уведомлению уникального id используется нехитрый механизм обращения к приватному целочисленному полю, которое каждый раз увеличивается на единицу.

private static final String TAG = NotificationUtils. class .getSimpleName();

private static NotificationUtils instance;

private static Context context;
private NotificationManager manager; // Системная утилита, упарляющая уведомлениями
private int lastId = 0; //постоянно увеличивающееся поле, уникальный номер каждого уведомления
private HashMap notifications; //массив ключ-значение на все отображаемые пользователю уведомления

Читайте также:  Android gravity and layout gravity

//приватный контструктор для Singleton
private NotificationUtils(Context context) <
this .context = context;
manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notifications = new HashMap ();
>
/**
* Получение ссылки на синглтон
*/
public static NotificationUtils getInstance(Context context) <
if(instance== null ) <
instance = new NotificationUtils(context);
> else <
instance.context = context;
>
return instance;
>

* This source code was highlighted with Source Code Highlighter .

Создание уведомления с помощью NotificationCompat.Builder:
Для того чтобы воспользоваться классами, входящими в библиотеку поддержки прошлых версий (Compatibility library), нужно добавить в проект библиотеку из папки /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 .

Создание уведомления с произвольным отображением (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;
>

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″/>

в андроид 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 >

А для поддержки 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» );

И во время выполнения потока постоянно обновляем прогресс вызовом:

В итоге получаем:

Как видно — нижнее уведомление, созданное нами при помощи билдера может быть удалено в любой момент. А уведомление с прогресс-баром размещается в верхнем блоке уведомлений, в котором пользователь не может очистить уведомления.

И напоследок маленькая хитрость:

Если не хотите дублирования в стеке одних и тех же Activity — поставьте в манифесте к нужной activity
android:launchMode=»singleTop»

Источник

Android Progress Notification with Examples

In android, Progress Notification is used to show the progress of an ongoing operation in the notification bar. By using progress notification, we can easily know how much percentage of the current operation completed and how long the operation will run to complete the remaining operation.

In android, two types of progress indicators available, one is determinate and another one is indeterminate. If we are known about how long the operation will take to complete, then we can use the determinate form of the indicator. In case if we are not aware of how long the operation will run then we can use the indeterminate form of indicator.

Following is the pictorial representation of using a different type of android progress indicators (determinate and indeterminate) to show the progress of current operation in notification.

Generally, the progress indicators in android are implemented by using the ProgressBar class. To display the progress indicators in our app, we need to add the progress bar to our notification by calling setProgress(max, progress, false) method and then issue the notification.

Here the third argument in setProgress() method is used to indicate whether the progress bar is determinate (false) or indeterminate (true). As our operation proceeds, we need to increase the value of progress and update the status of notification. At the end of operation, the progress value must be equal to max value. The better way to call setProgress() is to set max value to 100 and then increment progress as a percent complete value for the operation.

Once the operation is done leave the progress bar showing or remove it by calling setProgress(0,0, false) and update the notification text to show that the operation is complete.

Now we will see how to create and show the progress bar in an android notification bar with examples.

Android Progress Notification Example

Create a new android application using android studio and give names as ProgressNotification. In case if you are not aware of creating an app in android studio check this article Android Hello World App.

Читайте также:  Вылечить андроид от вирусов через компьютер

Now open an activity_main.xml file from \res\layout path and write the code like as shown below

activity_main.xml

xml version= «1.0» encoding= «utf-8» ?>
LinearLayout xmlns: android = «http://schemas.android.com/apk/res/android»
android :layout_width= «match_parent»
android :layout_height= «match_parent»
android :orientation= «vertical» >
Button
android :id= «@+id/btnShow»
android :layout_width= «wrap_content»
android :layout_height= «wrap_content»
android :text= «Show Notification»
android :layout_marginTop= «100dp» android :layout_marginLeft= «120dp»/>
LinearLayout >

If you observe above code we created a one Button control in XML Layout file to show the progress indicator in notification when we click on Button.

Once we are done with creation of layout with required controls, we need to load the XML layout resource from our activity onCreate() callback method, for that open main activity file MainActivity.java from \java\com.tutlane.progressnotification path and write the code like as shown below.

MainActivity.java

package com.tutlane.progressnotification;
import android.app.NotificationManager;
import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.app.NotificationCompat;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity <
private NotificationManager mNotifyManager ;
private NotificationCompat.Builder mBuilder ;
int id = 1 ;
@Override
protected void onCreate(Bundle savedInstanceState) <
super .onCreate(savedInstanceState);
setContentView(R.layout. activity_main );
Button b1 = (Button) findViewById(R.id. btnShow );
b1.setOnClickListener( new View.OnClickListener() <
@Override
public void onClick(View v) <
mNotifyManager = (NotificationManager) getSystemService(Context. NOTIFICATION_SERVICE );
mBuilder = new NotificationCompat.Builder(MainActivity. this );
mBuilder .setContentTitle( «File Download» )
.setContentText( «Download in progress» )
.setSmallIcon(R.drawable. download );
// Start a the operation in a background thread
new Thread(
new Runnable() <
@Override
public void run() <
int incr;
// Do the «lengthy» operation 20 times
for (incr = 0 ; incr 100 ; incr+= 5 ) <
// Sets the progress indicator to a max value, the current completion percentage and «determinate» state
mBuilder .setProgress( 100 , incr, false );
// Displays the progress bar for the first time.
mNotifyManager .notify( id , mBuilder .build());
// Sleeps the thread, simulating an operation
try <
// Sleep for 1 second
Thread.sleep( 1 * 1000 );
> catch (InterruptedException e) <
Log.d( «TAG» , «sleep failure» );
>
>
// When the loop is finished, updates the notification
mBuilder .setContentText( «Download completed» )
// Removes the progress bar
.setProgress( 0 , 0 , false );
mNotifyManager .notify( id , mBuilder .build());
>
>
// Starts the thread by calling the run() method in its Runnable
).start();
>
>);
>
>

If you observe above code we are created a progress notification using setProgress() method and showing the progress notification on Button click.

Generally, during the launch of our activity, the onCreate() callback method will be called by the android framework to get the required layout for an activity.

Output of Android Progress Notification Example

When we run the above example using android virtual device (AVD) we will get a result like as shown below.

If you observe above result we created a progress notification and shown it on Button click based on our requirements.

This is how we can use progress notification in our android applications based on our requirements.

Источник

Оцените статью