上周寫完那篇Blog以后就1直做著被分配到的Web任務(wù),也就沒繼續(xù)捯飭N那些事,然后今天還在看Notification這部份,然后看到了LNotification這個包,讀完源碼以后繼續(xù)給大家做簡單的分析,由于源碼觸及翻墻所以代碼和自己加的注釋丟到Git了
安理下我的收納庫:https://github.com/ddwhan0123/Useful-Open-Source-Android
首先我們來看下這個項目在哪一個目錄下
地址以下:https://developer.android.com/samples/LNotifications/index.html
跟我們上次的Messaging Service是鄰居。
那我們來看下演示效果(部份)
他在桌面icon也有 類似 待處理事件的通知
實現(xiàn)點擊觸發(fā)復(fù)瑣事件和通知排序
OK,由于是Sample所以好看難看我們不管,我們來看看分別能做甚么,有3個功能塊(都是Fragment)的,1個1個來分析
首先是HeadsUpNotificationFragment(這部份注釋很詳細(xì)了,就不過量分析了)
主要是實現(xiàn)這1點 用戶點擊通知會在Activity Task中生成1個新的實例
/**
* Fragment that demonstrates options for displaying Heads-Up Notifications.
* 這類模式下,用戶點擊通知會在Activity Task中生成1個新的實例
*/
public class HeadsUpNotificationFragment extends Fragment {
/**
* NotificationId用于從此Fragment的通知。
*/
private static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
/**
* 按鈕用于點擊顯示通知
*/
private Button mShowNotificationButton;
/**
* 如果選中,該Fragment創(chuàng)建的通知將顯示為Heads-Up通知。
*/
private CheckBox mUseHeadsUpCheckbox;
/**
* 使用此工廠方法來創(chuàng)建新實例
* 該Fragment使用提供的參數(shù)。
*
* @return 新的HeadsUpNotificationFragment的實例.
*/
public static HeadsUpNotificationFragment newInstance() {
HeadsUpNotificationFragment fragment = new HeadsUpNotificationFragment();
fragment.setRetainInstance(true);
return fragment;
}
public HeadsUpNotificationFragment() {
// 空構(gòu)造
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//初始化NotificationManager
mNotificationManager = (NotificationManager) getActivity().getSystemService(Context
.NOTIFICATION_SERVICE);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// 填充UI
return inflater.inflate(R.layout.fragment_heads_up_notification, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mShowNotificationButton = (Button) view.findViewById(R.id.show_notification_button);
//點擊按鈕就Toast1段話,告知用戶已觸發(fā)點擊事件
mShowNotificationButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mNotificationManager.notify(NOTIFICATION_ID, createNotification(
mUseHeadsUpCheckbox.isChecked()));
Toast.makeText(getActivity(), "Show Notification clicked", Toast.LENGTH_SHORT).show();
}
});
mUseHeadsUpCheckbox = (CheckBox) view.findViewById(R.id.use_heads_up_checkbox);
}
/**
* 創(chuàng)建1個新的取決于參數(shù)的通知。
*
* @param makeHeadsUpNotification 1個布爾值判斷是不是通知將作為heads-up通知來創(chuàng)建。
* <ul>
* <li>true : heads-up通知</li>
* <li>false : 普統(tǒng)統(tǒng)知</li>
* </ul>
* @return 1個Notification 實例.
*/
//@VisibleForTesting
Notification createNotification(boolean makeHeadsUpNotification) {
//這里就是1些普通的配置
Notification.Builder notificationBuilder = new Notification.Builder(getActivity())
.setSmallIcon(R.drawable.ic_launcher_notification)
.setPriority(Notification.PRIORITY_DEFAULT)
.setCategory(Notification.CATEGORY_MESSAGE)
.setContentTitle("Sample Notification")
.setContentText("This is a normal notification.");
//如果是heads-up通知
if (makeHeadsUpNotification) {
Intent push = new Intent();
push.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
push.setClass(getActivity(), LNotificationActivity.class);
PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(getActivity(), 0,
push, PendingIntent.FLAG_CANCEL_CURRENT);
notificationBuilder
.setContentText("Heads-Up Notification on Android L or above.")
.setFullScreenIntent(fullScreenPendingIntent, true);
}
return notificationBuilder.build();
}
}
然后是 VisibilityMetadataFragment
**主要行動是 在鎖屏條件下Notification的各種現(xiàn)實情況,Public Private Secret
可應(yīng)對與所需的1些業(yè)務(wù)場景,諸如需要輸入1些pin 密碼甚么的才可以做操作的功能**
/**
* Fragment that demonstrates how notifications with different visibility metadata differ on
* a lockscreen.
*在鎖屏情況下不同的通知,默許PUBLIC
*/
public class VisibilityMetadataFragment extends Fragment {
private NotificationManager mNotificationManager;
/**
* {@link RadioGroup} that has Visibility RadioButton in its children.
*/
//用于選擇模式
private RadioGroup mRadioGroup;
/**
* 構(gòu)建不同的ID,讓他被區(qū)分對待
*/
private Integer mIncrementalNotificationId = Integer.valueOf(0);
/**
* 按鈕,顯示通知用
*/
private Button mShowNotificationButton;
/**
* 使用此工廠方法來創(chuàng)建使用提供的參數(shù),該Fragment的新實例。
*
* @return 1個新的NotificationFragment的實例.
*/
public static VisibilityMetadataFragment newInstance() {
VisibilityMetadataFragment fragment = new VisibilityMetadataFragment();
fragment.setRetainInstance(true);
return fragment;
}
public VisibilityMetadataFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNotificationManager = (NotificationManager) getActivity().getSystemService(Context
.NOTIFICATION_SERVICE);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_visibility_metadata_notification, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mShowNotificationButton = (Button) view.findViewById(R.id.show_notification_button);
mShowNotificationButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
NotificationVisibility visibility = getVisibilityFromSelectedRadio(mRadioGroup);
showNotificationClicked(visibility);
}
});
mRadioGroup = (RadioGroup) view.findViewById(R.id.visibility_radio_group);
}
/**
* 創(chuàng)建1個具有不同級別可視性的通知。
*
* @param visibility 要創(chuàng)建的通知的可見性
* @return 通知的實例.
*/
//@VisibleForTesting
Notification createNotification(NotificationVisibility visibility) {
Notification.Builder notificationBuilder = new Notification.Builder(getActivity())
.setContentTitle("Notification for Visibility metadata");
notificationBuilder.setVisibility(visibility.getVisibility());
notificationBuilder.setContentText(String.format("Visibility : %s",
visibility.getDescription()));
notificationBuilder.setSmallIcon(visibility.getNotificationIconId());
return notificationBuilder.build();
}
/**
* Returns a {@link NotificationVisibility} depending on which RadioButton in the radiogroup
* is selected.
*
* @param radiogroup The RadioGroup.
* @return The instance of {@link NotificationVisibility} corresponding to RadioButton.
*/
private NotificationVisibility getVisibilityFromSelectedRadio(RadioGroup radiogroup) {
switch (radiogroup.getCheckedRadioButtonId()) {
case R.id.visibility_public_radio_button:
return NotificationVisibility.PUBLIC;
case R.id.visibility_private_radio_button:
return NotificationVisibility.PRIVATE;
case R.id.visibility_secret_radio_button:
return NotificationVisibility.SECRET;
default:
//If not selected, returns PUBLIC as default.
return NotificationVisibility.PUBLIC;
}
}
/**
* Invoked when {@link #mShowNotificationButton} is clicked.
* Creates a new notification with a different visibility level.
*
* @param visibility The visibility of the notification to be created.
*/
private void showNotificationClicked(NotificationVisibility visibility) {
// Assigns a unique (incremented) notification ID in order to treat each notification as a
// different one. This helps demonstrate how a notification with a different visibility
// level differs on the lockscreen.
mIncrementalNotificationId = new Integer(mIncrementalNotificationId + 1);
mNotificationManager.notify(mIncrementalNotificationId, createNotification(visibility));
Toast.makeText(getActivity(), "Show Notification clicked", Toast.LENGTH_SHORT).show();
}
/**
* Enum indicating possible visibility levels for notifications and related data(String
* representation of visibility levels, an icon ID to create a notification) to
* create a notification.
*/
//@VisibleForTesting
enum NotificationVisibility {
PUBLIC(Notification.VISIBILITY_PUBLIC, "Public", R.drawable.ic_public_notification),
PRIVATE(Notification.VISIBILITY_PRIVATE, "Private", R.drawable.ic_private_notification),
SECRET(Notification.VISIBILITY_SECRET, "Secret", R.drawable.ic_secret_notification);
/**
* Visibility level of the notification.
*/
private final int mVisibility;
/**
* String representation of the visibility.
*/
private final String mDescription;
/**
* Id of an icon used for notifications created from the visibility.
*/
private final int mNotificationIconId;
NotificationVisibility(int visibility, String description, int notificationIconId) {
mVisibility = visibility;
mDescription = description;
mNotificationIconId = notificationIconId;
}
public int getVisibility() {
return mVisibility;
}
public String getDescription() {
return mDescription;
}
public int getNotificationIconId() {
return mNotificationIconId;
}
}
}
還有個就是我們截圖中的類OtherMetadataFragment
他可以根據(jù)用戶操作做1些列諸如郵件,電話,鬧鐘提示等功能,并對通知進行輕重緩急的排序
/**
* Fragment that demonstrates how to attach metadata introduced in Android L, such as
* priority data, notification category and person data.
* 通知列表會根據(jù)優(yōu)先級高低進行排序
*/
public class OtherMetadataFragment extends Fragment {
private static final String TAG = OtherMetadataFragment.class.getSimpleName();
/**
* 用于采摘聯(lián)系人要求的代碼。
*/
public static final int REQUEST_CODE_PICK_CONTACT = 1;
/**
* Incremental Integer used for ID for notifications so that each notification will be
* treated differently.
* 構(gòu)建不同的ID,讓他被區(qū)分對待
*/
private Integer mIncrementalNotificationId = Integer.valueOf(0);
private NotificationManager mNotificationManager;
/**
* 按鈕,顯示通知用
*/
private Button mShowNotificationButton;
/**
* Spinner that holds possible categories used for a notification as
* {@link Notification.Builder#setCategory(String)}.
* 設(shè)置類型的下拉選擇欄
*/
private Spinner mCategorySpinner;
/**
* Spinner that holds possible priorities used for a notification as
* {@link Notification.Builder#setPriority(int)}.
* 設(shè)置優(yōu)先級的下拉選擇欄
*/
private Spinner mPrioritySpinner;
/**
* Holds a URI for the person to be attached to the notification.
* 持有的URI的人要附加到該通知。
*/
//@VisibleForTesting
Uri mContactUri;
/**
* 使用此工廠方法來創(chuàng)建使用提供的參數(shù),該Fragment的新實例。
*
* @return 1個新的NotificationFragment的實例.
*/
public static OtherMetadataFragment newInstance() {
OtherMetadataFragment fragment = new OtherMetadataFragment();
fragment.setRetainInstance(true);
return fragment;
}
public OtherMetadataFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNotificationManager = (NotificationManager) getActivity().getSystemService(Context
.NOTIFICATION_SERVICE);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_other_metadata, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mShowNotificationButton = (Button) view.findViewById(R.id.show_notification_button);
mShowNotificationButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//往spinner里填東西,然后發(fā)送通知
Priority selectedPriority = (Priority) mPrioritySpinner.getSelectedItem();
Category selectedCategory = (Category) mCategorySpinner.getSelectedItem();
showNotificationClicked(selectedPriority, selectedCategory, mContactUri);
}
});
//填充數(shù)據(jù)
mCategorySpinner = (Spinner) view.findViewById(R.id.category_spinner);
ArrayAdapter<Category> categoryArrayAdapter = new ArrayAdapter<Category>(getActivity(),
android.R.layout.simple_spinner_item, Category.values());
categoryArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mCategorySpinner.setAdapter(categoryArrayAdapter);
mPrioritySpinner = (Spinner) view.findViewById(R.id.priority_spinner);
ArrayAdapter<Priority> priorityArrayAdapter = new ArrayAdapter<Priority>(getActivity(),
android.R.layout.simple_spinner_item, Priority.values());
priorityArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mPrioritySpinner.setAdapter(priorityArrayAdapter);
view.findViewById(R.id.attach_person).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
findContact();
}
});
view.findViewById(R.id.contact_entry).setVisibility(View.GONE);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQUEST_CODE_PICK_CONTACT:
if (resultCode == Activity.RESULT_OK) {
Uri contactUri = data.getData();
mContactUri = contactUri;
updateContactEntryFromUri(contactUri);
}
break;
}
}
/**
* Invoked when {@link #mShowNotificationButton} is clicked.
* Creates a new notification and sets metadata passed as arguments.
*
* @param priority The priority metadata.
* @param category The category metadata.
* @param contactUri The URI to be added to the new notification as metadata.
* @return A Notification instance.
*/
//@VisibleForTesting
Notification createNotification(Priority priority, Category category, Uri contactUri) {
Notification.Builder notificationBuilder = new Notification.Builder(getActivity())
.setContentTitle("Notification with other metadata")
.setSmallIcon(R.drawable.ic_launcher_notification)
.setPriority(priority.value)
.setCategory(category.value)
.setContentText(String.format("Category %s, Priority %s", category.value,
priority.name()));
if (contactUri != null) {
notificationBuilder.addPerson(contactUri.toString());
Bitmap photoBitmap = loadBitmapFromContactUri(contactUri);
if (photoBitmap != null) {
notificationBuilder.setLargeIcon(photoBitmap);
}
}
return notificationBuilder.build();
}
/**
* Invoked when {@link #mShowNotificationButton} is clicked.
* Creates a new notification and sets metadata passed as arguments.
*
* @param priority The priority metadata.
* @param category The category metadata.
* @param contactUri The URI to be added to the new notification as metadata.
*/
private void showNotificationClicked(Priority priority, Category category, Uri contactUri) {
// Assigns a unique (incremented) notification ID in order to treat each notification as a
// different one. This helps demonstrate how a priority flag affects ordering.
mIncrementalNotificationId = new Integer(mIncrementalNotificationId + 1);
mNotificationManager.notify(mIncrementalNotificationId, createNotification(priority,
category, contactUri));
Toast.makeText(getActivity(), "Show Notification clicked", Toast.LENGTH_SHORT).show();
}
private void findContact() {
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(intent, REQUEST_CODE_PICK_CONTACT);
}
/**
* Returns a {@link Bitmap} from the Uri specified as the argument.
*
* @param contactUri The Uri from which the result Bitmap is created.
* @return The {@link Bitmap} instance retrieved from the contactUri.
*/
private Bitmap loadBitmapFromContactUri(Uri contactUri) {
if (contactUri == null) {
return null;
}
Bitmap result = null;
Cursor cursor = getActivity().getContentResolver().query(contactUri, null, null, null,
null);
if (cursor != null && cursor.moveToFirst()) {
int idx = cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_ID);
String hasPhoto = cursor.getString(idx);
Uri photoUri = Uri.withAppendedPath(contactUri, ContactsContract.Contacts.Photo
.CONTENT_DIRECTORY);
if (hasPhoto != null) {
try {
result = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver()
, photoUri);
} catch (IOException e) {
Log.e(TAG, String.format("Failed to load resource. Uri %s", photoUri), e);
}
} else {
Drawable defaultContactDrawable = getActivity().getResources().getDrawable(R
.drawable.ic_contact_picture);
result = ((BitmapDrawable) defaultContactDrawable).getBitmap();
}
}
return result;
}
/**
* Updates the Contact information on the screen when a contact is picked.
*
* @param contactUri The Uri from which the contact is retrieved.
*/
private void updateContactEntryFromUri(Uri contactUri) {
Cursor cursor = getActivity().getContentResolver().query(contactUri, null, null, null,
null);
if (cursor != null && cursor.moveToFirst()) {
int idx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
String name = cursor.getString(idx);
idx = cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_ID);
String hasPhoto = cursor.getString(idx);
Uri photoUri = Uri.withAppendedPath(contactUri, ContactsContract.Contacts.Photo
.CONTENT_DIRECTORY);
ImageView contactPhoto = (ImageView) getActivity().findViewById(R.id.contact_photo);
if (hasPhoto != null) {
contactPhoto.setImageURI(photoUri);
} else {
Drawable defaultContactDrawable = getActivity().getResources().getDrawable(R
.drawable.ic_contact_picture);
contactPhoto.setImageDrawable(defaultContactDrawable);
}
TextView contactName = (TextView) getActivity().findViewById(R.id.contact_name);
contactName.setText(name);
getActivity().findViewById(R.id.contact_entry).setVisibility(View.VISIBLE);
getActivity().findViewById(R.id.attach_person).setVisibility(View.GONE);
getActivity().findViewById(R.id.click_to_change).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
findContact();
}
});
Log.i(TAG, String.format("Contact updated. Name %s, PhotoUri %s", name, photoUri));
}
}
/**
* Enum indicating possible categories in {@link Notification} used from
* {@link #mCategorySpinner}.
*/
enum Category {
ALARM("alarm"),
CALL("call"),
EMAIL("email"),
ERROR("err"),
EVENT("event"),
MESSAGE("msg"),
PROGRESS("progress"),
PROMO("promo"),
RECOMMENDATION("recommendation"),
SERVICE("service"),
SOCIAL("social"),
STATUS("status"),
SYSTEM("sys"),
TRANSPORT("transport");
private final String value;
Category(String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
}
/**
* Enum indicating possible priorities in {@link Notification} used from
* {@link #mPrioritySpinner}.
*/
//@VisibleForTesting
enum Priority {
DEFAULT(Notification.PRIORITY_DEFAULT),
MAX(Notification.PRIORITY_MAX),
HIGH(Notification.PRIORITY_HIGH),
LOW(Notification.PRIORITY_LOW),
MIN(Notification.PRIORITY_MIN);
private final int value;
Priority(int value) {
this.value = value;
}
}
}
這部份的代碼比較長,沒有對每部份進行翻譯OR解釋,在這里大致描寫下。
首先聲明了2個枚舉,1個操作類型,1個操作排序的次序。
測試的時候分別對,默許,最高和最低進行了測試,結(jié)果也如大家所看到的,最高就會在最上面,最低就出現(xiàn)在通知欄最下面了,然后就是行動類型,用戶在產(chǎn)生通知之前需要選擇他的行動類型和該類型所需的1些參數(shù)諸如通訊錄聯(lián)系人的號碼啊,郵箱地址甚么的,有些需要圖片操作的源碼里也做了相應(yīng)實現(xiàn)大家需要的可以調(diào)用就好了。(由于測試機沒通訊錄,所以沒有測的很深,大家可以自己插卡試試,這部份如何暫時保存意見,但是排序是絕對有效的)
以上是對這個包里3個實現(xiàn)Fragment的簡單分析,然后提1下注意點,使用處景在 安卓 L 就是 棒棒糖版本版本太低的有問題就是自己適配了。
最重要的1點是 這些通知 都會在桌面的利用 ICON產(chǎn)生 1 2 3這類未讀數(shù)的統(tǒng)計
源碼地址:https://github.com/ddwhan0123/BlogSample/blob/master/LNotifications.zip?raw=true
謝謝各位觀眾老爺,有問題可以微信M我(活人不是公眾號)