程序员人生 网站导航

翻看谷歌源码 那些让人感兴趣的东西--通知的好用功能

栏目:综合技术时间:2016-06-03 18:37:50

转载请注明出处:王亟亟的大牛之路

上周写完那篇Blog以后就1直做着被分配到的Web任务,也就没继续捯饬N那些事,然后今天还在看Notification这部份,然后看到了LNotification这个包,读完源码以后继续给大家做简单的分析,由于源码触及翻墙所以代码和自己加的注释丢到Git了

安理下我的收纳库:https://github.com/ddwhan0123/Useful-Open-Source-Android

首先我们来看下这个项目在哪一个目录下
这里写图片描述

地址以下:https://developer.android.com/samples/LNotifications/index.html

跟我们上次的Messaging Service是邻居。

那我们来看下演示效果(部份)

他在桌面icon也有 类似 待处理事件的通知
这里写图片描述

实现点击触发复琐事件和通知排序

这里写图片描述

这里写图片描述

OK,由于是Sample所以好看难看我们不管,我们来看看分别能做甚么,有3个功能块(都是Fragment)的,1个1个来分析


首先是HeadsUpNotificationFragment(这部份注释很详细了,就不过量分析了)

主要是实现这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创建的通知将显示为Heads-Up通知。 */ private CheckBox mUseHeadsUpCheckbox; /** * 使用此工厂方法来创建新实例 * 该Fragment使用提供的参数。 * * @return 新的HeadsUpNotificationFragment的实例. */ public static HeadsUpNotificationFragment newInstance() { HeadsUpNotificationFragment fragment = new HeadsUpNotificationFragment(); fragment.setRetainInstance(true); return fragment; } public HeadsUpNotificationFragment() { // 空构造 } @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段话,告知用户已触发点击事件 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); } /** * 创建1个新的取决于参数的通知。 * * @param makeHeadsUpNotification 1个布尔值判断是不是通知将作为heads-up通知来创建。 * <ul> * <li>true : heads-up通知</li> * <li>false : 普统统知</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的各种现实情况,Public Private Secret
可应对与所需的1些业务场景,诸如需要输入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; /** * 构建不同的ID,让他被区分对待 */ private Integer mIncrementalNotificationId = Integer.valueOf(0); /** * 按钮,显示通知用 */ private Button mShowNotificationButton; /** * 使用此工厂方法来创建使用提供的参数,该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); } /** * 创建1个具有不同级别可视性的通知。 * * @param visibility 要创建的通知的可见性 * @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

他可以根据用户操作做1些列诸如邮件,电话,闹钟提示等功能,并对通知进行轻重缓急的排序

/** * Fragment that demonstrates how to attach metadata introduced in Android L, such as * priority data, notification category and person data. * 通知列表会根据优先级高低进行排序 */ public class OtherMetadataFragment extends Fragment { private static final String TAG = OtherMetadataFragment.class.getSimpleName(); /** * 用于采摘联系人要求的代码。 */ public static final int REQUEST_CODE_PICK_CONTACT = 1; /** * Incremental Integer used for ID for notifications so that each notification will be * treated differently. * 构建不同的ID,让他被区分对待 */ 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)}. * 设置类型的下拉选择栏 */ private Spinner mCategorySpinner; /** * Spinner that holds possible priorities used for a notification as * {@link Notification.Builder#setPriority(int)}. * 设置优先级的下拉选择栏 */ private Spinner mPrioritySpinner; /** * Holds a URI for the person to be attached to the notification. * 持有的URI的人要附加到该通知。 */ //@VisibleForTesting Uri mContactUri; /** * 使用此工厂方法来创建使用提供的参数,该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里填东西,然后发送通知 Priority selectedPriority = (Priority) mPrioritySpinner.getSelectedItem(); Category selectedCategory = (Category) mCategorySpinner.getSelectedItem(); showNotificationClicked(selectedPriority, selectedCategory, mContactUri); } }); //填充数据 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个操作排序的次序。

测试的时候分别对,默许,最高和最低进行了测试,结果也如大家所看到的,最高就会在最上面,最低就出现在通知栏最下面了,然后就是行动类型,用户在产生通知之前需要选择他的行动类型和该类型所需的1些参数诸如通讯录联系人的号码啊,邮箱地址甚么的,有些需要图片操作的源码里也做了相应实现大家需要的可以调用就好了。(由于测试机没通讯录,所以没有测的很深,大家可以自己插卡试试,这部份如何暂时保存意见,但是排序是绝对有效的)

以上是对这个包里3个实现Fragment的简单分析,然后提1下注意点,使用处景在 安卓 L 就是 棒棒糖版本版本太低的有问题就是自己适配了。

最重要的1点是 这些通知 都会在桌面的利用 ICON产生 1 2 3这类未读数的统计

源码地址:https://github.com/ddwhan0123/BlogSample/blob/master/LNotifications.zip?raw=true

谢谢各位观众老爷,有问题可以微信M我(活人不是公众号)

这里写图片描述

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐