KitKat知多少 android 4.4.2 使用技巧大解析

Android 4.4 终于来了。新系统带来多项更新:电话拨号应用可以快速搜索人名、地名;Hangouts 取代原有短信应用,可以直接发送短信、图片以及视频文件;相机加入全新的 HDR+ 模式,支持一次拍摄多张照片,然后从中选出优秀的部分拼接成最佳照片。
Google 也在不久前更新了 Android 4.4 的。Nexus 5 出厂时就已经预装新系统,Nexus 4、Nexus 7 以及 Nexus 10 也都能升级到 Android 4.4。不过新系统目前只出现在 Nexus 5 上,Google 计划未来两周内陆续向老款设备推送 KitKat。
但 2011 年发布的 Galaxy Nexus 就无缘 Android 4.4 了。是两年前发布的 Galaxy Nexus 已经超出 Google 和其它设备商提供的 18 个月的更新周期。但知情人,硬件问题是导致 Galaxy Nexus 无法用上 KitKat 的主要原因——Galaxy Nexus 使用的是德州仪器 OMAP 4460 芯片,而德州仪器在去年裁掉 1700 名员工,宣布。这种情况下,继续为 Galaxy Nexus 优化系统的意义不是很大。
未来只能期望第三方开发者了。不过眼下 CyanogenMod 和 XDA 的开发者都没有公布 Android 4.4 的适配计划,Galaxy Nexus 用户能否用上 KitKat 还需要进一步确认。
阅读、思考、自我反省,相信坚持可以改变人生。10491人阅读
& &&博主参加了2013博客之星评选,谢谢你的的支持,:& & Android团队通过Android开发博客透漏今年会放出Android 4.4 (KitKat) ,同时更新了 SMS 的部分API。博客上讲只有default SMS app才能对短信数据库有写权限,但是用户可以把第三方应用设置为default SMS app。有些中文的报道说“”,本文作者认为是不完全正确的,非default SMS app也能读写短信,只不过是不能写入短信数据库中。我们看一看android开发者博客是怎么讲述其他应用短信接收和发送问题的。1)接收短信问题:Other apps that only want to read new messages can instead receive the
SMS_RECEIVED_ACTION broadcast intent when a new SMS arrives. & & 其他应用可以接收SMS_RECEIVED_ACTION的广播接收到短信,接收到这个广播,短信不会写入短信数据库。2)发送短信问题:When your app is not currently selected as the default SMS app, it's important that you
disable the ability to send new messages from your app because, without the ability to
write to the SMS Provider, any messages you send won't be visible in the user's default SMS app.
& & 没有default SMS app能力的app发送短信,不会出现在短信数据库中。Android开发者博客中重点讲到了3个方面的问题:1、怎么开发default SMS app2、怎么提示用户设置自己的app为default SMS app3、对短信备份恢复类App的一点建议怎么开发default SMS app& & 现存的短信类App不会默认升级为default SMS app,需要完成Android新的规范协议。Android 4.4中,系统收到短信时,只有一个应用能收到SMS_DELIVER_ACTION,这个应用就是default SMS app,WAP_PUSH_DELIVER_ACTION也是类似。如果现存的短信类App不做改造,运行在Android 4.4也不会Crash,但是写入短信数据库数据时会失败。& & 为了使你的应用出现在系统设置的Default SMS app中,你需要在manifest 文件声明一下几种能力。1、接收SMS_DELIVER_ACTION(&android.provider.Telephony.SMS_DELIVER&)的broadcast receiver,这个broadcast receiver需要有BROADCAST_SMS权限。这些是为了让你的应用能接收到SMS messages。2、接收WAP_PUSH_DELIVER_ACTION(&android.provider.Telephony.WAP_PUSH_DELIVER&) 的broadcast receiver,这个需要BROADCAST_WAP_PUSH权限。这些是为了让你的应用能接收到MMS &messages。3、实现发送短信功能,需要有个Activity完成(&android.intent.action.SENDTO&)intent filter,并使用schemas,&sms:,&smsto:,&mms:, 以及&mmsto:。这可以使其他应用调用你的发短信能力。4、实现一个提供intent filter for&(&android.intent.action.RESPOND_VIA_MESSAGE&) with schemas,&sms:,&smsto:,&mms:, and&mmsto服务。这个服务需要&权限。这允许用户使用您的应用程序提供即时短信回应电话呼入。下面是一个manifest文件的例子:&manifest&
&application&
&!-- BroadcastReceiver that listens for incoming SMS messages --&
&receiver android:name=&.SmsReceiver&
android:permission=&android.permission.BROADCAST_SMS&&
&intent-filter&
&action android:name=&android.provider.Telephony.SMS_DELIVER& /&
&/intent-filter&
&/receiver&
&!-- BroadcastReceiver that listens for incoming MMS messages --&
&receiver android:name=&.MmsReceiver&
android:permission=&android.permission.BROADCAST_WAP_PUSH&&
&intent-filter&
&action android:name=&android.provider.Telephony.WAP_PUSH_DELIVER& /&
&data android:mimeType=&application/vnd.wap.mms-message& /&
&/intent-filter&
&/receiver&
&!-- Activity that allows the user to send new SMS/MMS messages --&
&activity android:name=&.ComposeSmsActivity& &
&intent-filter&
&action android:name=&android.intent.action.SEND& /&
&action android:name=&android.intent.action.SENDTO& /&
&category android:name=&android.intent.category.DEFAULT& /&
&category android:name=&android.intent.category.BROWSABLE& /&
&data android:scheme=&sms& /&
&data android:scheme=&smsto& /&
&data android:scheme=&mms& /&
&data android:scheme=&mmsto& /&
&/intent-filter&
&/activity&
&!-- Service that delivers messages from the phone &quick response& --&
&service android:name=&.HeadlessSmsSendService&
android:permission=&android.permission.SEND_RESPOND_VIA_MESSAGE&
android:exported=&true& &
&intent-filter&
&action android:name=&android.intent.action.RESPOND_VIA_MESSAGE& /&
&category android:name=&android.intent.category.DEFAULT& /&
&data android:scheme=&sms& /&
&data android:scheme=&smsto& /&
&data android:scheme=&mms& /&
&data android:scheme=&mmsto& /&
&/intent-filter&
&/service&
&/application&
&/manifest&& & Android 4.4可以使用SMS_RECEIVED_ACTION广播来观察收到了短信,这样可以知道特定的短信收到了,但是我们不能对接收到短信做处理。设置自己的app为default SMS app& & Android4.4中提供了新的方法&Telephony.Sms.getDefaultSmsPackage(),可以获取到当前Default SMS app的包名。用户打开你的应用时可以通过判断知道自己的应用是否为Default SMS app。如果不是,可以通过&方法启动类似如下的Dialog。具体实现可参考下面的代码。public class ComposeSmsActivity extends Activity {
protected void onResume() {
super.onResume();
final String myPackageName = getPackageName();
if (!Telephony.Sms.getDefaultSmsPackage(this).equals(myPackageName)) {
// App is not default.
// Show the &not currently set as the default SMS app& interface
View viewGroup = findViewById(R.id.not_default_app);
viewGroup.setVisibility(View.VISIBLE);
// Set up a button that allows the user to change the default SMS app
Button button = (Button) findViewById(R.id.change_default_app);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent =
new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME,
myPackageName);
startActivity(intent);
// App is the default.
// Hide the &not currently set as the default SMS app& interface
View viewGroup = findViewById(R.id.not_default_app);
viewGroup.setVisibility(View.GONE);
}对短信备份恢复类App的一点建议& & 短信备份恢复类应用没有Default SMS app的能力,不能写入短信数据库数据,就起不到恢复短信的作用了。Android开发者博客给出的建议是临时的设置自己的应用为Default SMS app,临时获取一次写入短信数据库数据能力,等短信恢复完成再改回原来的应用为Default SMS app。1、获取默认App的包名并保存。String defaultSmsApp = Telephony.Sms.getDefaultSmsPackage(context);2、让用户修改你的app为Default SMS appIntent intent = new Intent(context, Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Sms.Intents.EXTRA_PACKAGE_NAME, context.getPackageName());
startActivity(intent);3、恢复完短信,再让用户修改回Default SMS app,使用第一步保存的包名。Intent intent = new Intent(context, Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Sms.Intents.EXTRA_PACKAGE_NAME, defaultSmsApp);
startActivity(intent);& & 上面是一些Android4.4短信变化的介绍,大部分是翻译自Android开发者博客,由于作者英语水平有限,可能与原作者的理解有些出入,敬请读者谅解。/*** @author 张兴业* &* &iOS入门群:* &android开发进阶群:* &我的新浪微博:*/参考:
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:2071064次
积分:22805
积分:22805
排名:第89名
原创:270篇
转载:195篇
译文:20篇
评论:1327条
android 开发交流
济南移动互联网:
文章:10篇
阅读:124003
文章:18篇
阅读:132411
阅读:51344
文章:11篇
阅读:69822
文章:14篇
阅读:86986
文章:59篇
阅读:612949
(2)(1)(2)(4)(2)(3)(1)(2)(6)(1)(6)(5)(11)(3)(1)(7)(7)(7)(4)(5)(1)(1)(5)(1)(10)(11)(7)(5)(1)(2)(1)(8)(4)(4)(8)(23)(23)(1)(1)(1)(3)(9)(15)(34)(11)(5)(3)(3)(1)(5)(2)(5)(14)(23)(22)(25)(46)(7)(9)(30)(8)(1)(5)(1)& & & &&Android在4.3的版本中(即API 18)加入了NotificationListenerService,根据SDK的描述()可以知道,当系统收到新的通知或者通知被删除时,会触发NotificationListenerService的回调方法。同时在Android
4.4 中新增了Notification.extras 字段,也就是说可以使用NotificationListenerService获取系统通知具体信息,这在以前是需要用反射来实现的。
转载请务必注明出处:http://blog.csdn.net/yihongyuelan
& & & & 对于系统通知,三方APP使用NotificationListenerService主要目的是为了获取系统通知相关信息,主要包括:通知的新增和删除,获取当前通知数量,通知内容相关信息等。这些信息可以通过NotificationListenerService类提供的方法以及StatusBarNotification类对象来获取。
NotificationListenerService主要方法(成员变量):
cancelAllNotifications() :删除系统中所有可被清除的通知;&
cancelNotification(String pkg, String tag, int id) :删除具体某一个通知;
getActiveNotifications() :返回当前系统所有通知到StatusBarNotification[];
onNotificationPosted(StatusBarNotification sbn) :当系统收到新的通知后出发回调;&
onNotificationRemoved(StatusBarNotification sbn) :当系统通知被删掉后出发回调;
以上是NotificationListenerService的主要方法,通过这些方法就可以在应用中操作系统通知,在NotificationListenerService中除了对通知的操作之外,还可以获取到通知的StatusBarNotification对象,通过该对象可以获取通知更详细的数据。
StatusBarNotification主要方法(成员变量):
getId():返回通知对应的id;
getNotification():返回通知对象;
getPackageName():返回通知对应的包名;
getPostTime():返回通知发起的时间;
getTag():返回通知的Tag,如果没有设置返回null;
getUserId():返回UserId,用于多用户场景;
isClearable():返回该通知是否可被清楚,FLAG_ONGOING_EVENT、FLAG_NO_CLEAR;
isOngoing():检查该通知的flag是否为FLAG_ONGOING_EVENT;
正确使用NotificationListenerService需要注意三点:
(1). 新建一个类并继承自NotificationListenerService,override其中重要的两个方法;
public class NotificationMonitor extends NotificationListenerService {
public void onNotificationPosted(StatusBarNotification sbn) {
Log.i(&SevenNLS&,&Notification posted&);
public void onNotificationRemoved(StatusBarNotification sbn) {
Log.i(&SevenNLS&,&Notification removed&);
(2). 在AndroidManifest.xml中注册Service并声明相关权限;
&service android:name=&.NotificationMonitor&
android:label=&@string/service_name&
android:permission=&android.permission.BIND_NOTIFICATION_LISTENER_SERVICE&&
&intent-filter&
&action android:name=&android.service.notification.NotificationListenerService& /&
&/intent-filter&
&/service&(3). 开启NotificationMonitor的监听功能;
& & & &&完成以上两步之后,将程序编译并安装到手机上,但此时该程序是无法监听到新增通知和删除通知的,还需要在&Settings & Security & Notification access&中,勾选NotificationMonitor。此时如果系统收到新的通知或者通知被删除就会打印出相应的log了。
& & & &&这里需要注意,如果手机上没有安装使用NotificationListenerService类的APP,Notification access是不会显示出来的。可以在源码/packages/apps/Settings/src/com/android/settings/SecuritySettings.java中看到,如果没有使用NotificationListenerService的APK,直接就不显示这一项了。
mNotificationAccess = findPreference(KEY_NOTIFICATION_ACCESS);
if (mNotificationAccess != null) {
final int total = NotificationAccessSettings.getListenersCount(mPM);
if (total == 0) {
if (deviceAdminCategory != null) {
deviceAdminCategory.removePreference(mNotificationAccess);
final int n = getNumEnabledNotificationListeners();
if (n == 0) {
mNotificationAccess.setSummary(getResources().getString(
R.string.manage_notification_access_summary_zero));
mNotificationAccess.setSummary(String.format(getResources().getQuantityString(
R.plurals.manage_notification_access_summary_nonzero,
通过前面的讲解(实际上就是对AndroidDeveloper的解释),已经可以正常使用NotificationListenerService了,但对于实际应用中,需要考虑的事情还比较多。比如:
1. 如何检测应用已开启Notification access监听功能?
如果检测到应用没有激活Notification access监听功能,需要提示用户开启;
2. 能不能主动跳转到Notification access监听页面?
如果能够根据第1步的判断自动跳转到对应的页面,那可以省掉很多操作;
3. 如何与NotificationListenerService交互?
涉及到与Service的交互,但又与普通的Service不同,这里后文解释;
4. NotificationListenerService使用过程中有哪些注意事项?
在使用NotificationListenerService过程中自己遇到了一些坑,后文会通过分析给出相应的解决方案;
程序运行截图
图 1 程序运行截图
& & & &&NotificationListenerDemo主要用于获取系统当前通知信息,并可手动创建&可清除通知&,逐条删除&可清除通知&,一次性删除&可清除通知&,以及显示系统当前活动的通知信息。实际上该示例回答了前面使用详解中提出的各项疑问,在实际使用过程中相信大部分人都会遇到,因此这里逐条展开与大家分享。
图 2 主界面
1. 如何检测应用已开启Notification access监听功能?
& & & &&在程序启动时,执行Notification access的检测,查看是否访问Notification的权限。如果用户没有Enable Notification access,则弹出提示对话框,点击OK跳转到Notification access设置页面。
图 3 首次启动 isEnable
& & & &&使用NotificationListenerService的应用如果开启了Notification access,系统会将包名等相关信息写入SettingsProver数据库中,因此可以从数据库中获取相关信息并过滤,从而判断应用是否开启了Notification access,代码如下:
private static final String ENABLED_NOTIFICATION_LISTENERS = &enabled_notification_listeners&;
private boolean isEnabled() {
String pkgName = getPackageName();
final String flat = Settings.Secure.getString(getContentResolver(),
ENABLED_NOTIFICATION_LISTENERS);
if (!TextUtils.isEmpty(flat)) {
final String[] names = flat.split(&:&);
for (int i = 0; i & names. i++) {
final ComponentName cn = ComponentName.unflattenFromString(names[i]);
if (cn != null) {
if (TextUtils.equals(pkgName, cn.getPackageName())) {
}在返回值flat中如果包含了应用的包名,即可确定应用已开启Notification access,反之则表示没有开启。
2. 能不能主动跳转到Notification access监听页面?
& & & &&通过查看可以知道,Notification access界面接收action为&android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS&的intent启动,因此使用startActivity可以很容易的跳转到该页面,从而避免用户在Settings中查找。代码如下:
private static final String ACTION_NOTIFICATION_LISTENER_SETTINGS = &android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS&;
private void openNotificationAccess() {
startActivity(new Intent(ACTION_NOTIFICATION_LISTENER_SETTINGS));
3. 如何与NotificationListenerService交互?
& & & &&因为NotificationListenerService中包含了四个重要的方法,分别是:onNotificationPosted、onNotificationRemoved、cancelNotification、cancelAllNotifications。通过这些方法我们才能实现诸如通知信息的获取以及删除等功能,虽然这些方法是public的,那是不是意味着我们只要拿到NotificationListenerService的对象就可以直接调用这些方法了呢?那如何拿到Service的对象呢?在之前的博文中,曾有提到与Service的交互(
具体可参考拙作《》),可以看到与Service的交互有很多种方法,但如果要拿到Service的对象,归根到底还是需要Binder。
& & & &&也就是说得使用bindService的办法,将onServiceConnected回调中的IBinder对象转型成NotificationListenerService的对象。测试代码如下:
//在MainActivity.java的onCreate方法中使用bindService帮顶NotificationMonitor服务
bindService(new Intent(this,NotificationMonitor.class
), new ServiceConnection() {
public void onServiceDisconnected(ComponentName arg0) {
public void onServiceConnected(ComponentName arg0, IBinder arg1) {
NotificationMonitor.MyBinder localBinder = (MyBinder)arg1;
NotificationMonitor mMonitor = localBinder.getService();
}, BIND_AUTO_CREATE);//NotificationMonitor的onBind方法返回构造的Binder对象
public class NotificationMonitor extends NotificationListenerService {
private MyBinder mBinder = new MyBinder();
class MyBinder extends Binder{
public NotificationMonitor getService(){
return NotificationMonitor.
public IBinder onBind(Intent arg0) {
public void onNotificationPosted(StatusBarNotification sbn) {
getActiveNotifications();
cancelAllNotifications();
public void onNotificationRemoved(StatusBarNotification sbn) {
}那这样操作之后是不是就意味着可以拿到NotificationMonitor的对象并直接调用getActiveNotifications()方法,用于获取当前系统通知的信息了呢?很抱歉,事实证明这样是不行的。这里简单的分析下,在后面的NotificationListenerService原理分析中再详细讲解。在NotificationListenerService的源码中可以看到:@Override
public IBinder onBind(Intent intent) {
if (mWrapper == null) {
mWrapper = new INotificationListenerWrapper();
}这里的INotificationListenerWrapper是NotificationListenerService的一个内部类:
private class INotificationListenerWrapper extends INotificationListener.Stub
而NotificationMonitor继承自NotificationListenerService,默认的onBind方法却是:
public IBinder onBind(Intent intent) {
return super.onBind(intent);
}& & & &&这里注意,一般情况下service的onBind方法返回要么是null要么是Binder对象,可这里直接调用父类NotificationListenerService的onBind方法,而父类返回的是INotificationListenerWrapper的对象。这说明Binder对象已经被指定了,不能再给NotificationMonitor指定其它的Binder对象。如果你非要给NotificationMonitor指定其它的Binder对象,那么就无法使用INotificationListenerWrapper提供的方法。也就是说要么就用系统NotificationListenerService提供的方法,要么就把NotificationMonitor当一个普通的Service来用,系统提供的方法都不能使用。
& & & &&那应该如何使用NotificationListenerService中的方法呢?在拙作《》中,已经提供了很多的例子,这里仅以广播的方式为例。
& & & &&既然NotificationMonitor可以使用NotificationListenerService的方法,那通过NotificationMonitor把通知状态的改变以及数据获取到,并使用static数据进行存储,之后再在MainActivity中直接使用即可。在MainActivity中控制通知的单个删除和全部删除,则使用广播的方式发送给NotificationMonitor进行处理。MainActivity与NotificationMonitor的关系类图如下:
图 4 结构类图
NotificationMonitor和MainActivity关键代码如下:
public class NotificationMonitor extends NotificationListenerService {
private static final String TAG = &SevenNLS&;
private static final String TAG_PRE = &[& + NotificationMonitor.class.getSimpleName() + &] &;
private static final int EVENT_UPDATE_CURRENT_NOS = 0;
public static final String ACTION_NLS_CONTROL = &com.seven.notificationlistenerdemo.NLSCONTROL&;
//用于存储当前所有的Notification的StatusBarNotification对象数组
public static List&StatusBarNotification[]& mCurrentNotifications = new ArrayList&StatusBarNotification[]&();
public static int mCurrentNotificationsCounts = 0;
//收到新通知后将通知的StatusBarNotification对象赋值给mPostedNotification
public static StatusBarNotification mPostedN
//删除一个通知后将通知的StatusBarNotification对象赋值给mRemovedNotification
public static StatusBarNotification mRemovedN
private CancelNotificationReceiver mReceiver = new CancelNotificationReceiver();
private Handler mMonitorHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_UPDATE_CURRENT_NOS:
updateCurrentNotifications();
class CancelNotificationReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if (intent != null && intent.getAction() != null) {
action = intent.getAction();
if (action.equals(ACTION_NLS_CONTROL)) {
String command = intent.getStringExtra(&command&);
if (TextUtils.equals(command, &cancel_last&)) {
if (mCurrentNotifications != null && mCurrentNotificationsCounts &= 1) {
//每次删除通知最后一个
StatusBarNotification sbnn = getCurrentNotifications()[mCurrentNotificationsCounts - 1];
cancelNotification(sbnn.getPackageName(), sbnn.getTag(), sbnn.getId());
} else if (TextUtils.equals(command, &cancel_all&)) {
//删除所有通知
cancelAllNotifications();
public void onCreate() {
super.onCreate();
logNLS(&onCreate...&);
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_NLS_CONTROL);
registerReceiver(mReceiver, filter);
//在onCreate时第一次调用getActiveNotifications()
mMonitorHandler.sendMessage(mMonitorHandler.obtainMessage(EVENT_UPDATE_CURRENT_NOS));
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
public IBinder onBind(Intent intent) {
// a.equals(&b&);
logNLS(&onBind...&);
return super.onBind(intent);
public void onNotificationPosted(StatusBarNotification sbn) {
//当系统收到新的通知后,更新mCurrentNotifications列表
updateCurrentNotifications();
logNLS(&onNotificationPosted...&);
logNLS(&have & + mCurrentNotificationsCounts + & active notifications&);
mPostedNotification =
//通过以下方式可以获取Notification的详细信息
* Bundle extras = sbn.getNotification(). String
* notificationTitle = extras.getString(Notification.EXTRA_TITLE);
* Bitmap notificationLargeIcon = ((Bitmap)
* extras.getParcelable(Notification.EXTRA_LARGE_ICON)); Bitmap
* notificationSmallIcon = ((Bitmap)
* extras.getParcelable(Notification.EXTRA_SMALL_ICON)); CharSequence
* notificationText = extras.getCharSequence(Notification.EXTRA_TEXT);
* CharSequence notificationSubText =
* extras.getCharSequence(Notification.EXTRA_SUB_TEXT);
* Log.i(&SevenNLS&, &notificationTitle:&+notificationTitle);
* Log.i(&SevenNLS&, &notificationText:&+notificationText);
* Log.i(&SevenNLS&, &notificationSubText:&+notificationSubText);
* Log.i(&SevenNLS&,
* &notificationLargeIcon is null:&+(notificationLargeIcon == null));
* Log.i(&SevenNLS&,
* &notificationSmallIcon is null:&+(notificationSmallIcon == null));
public void onNotificationRemoved(StatusBarNotification sbn) {
//当有通知被删除后,更新mCurrentNotifications列表
updateCurrentNotifications();
logNLS(&removed...&);
logNLS(&have & + mCurrentNotificationsCounts + & active notifications&);
mRemovedNotification =
private void updateCurrentNotifications() {
StatusBarNotification[] activeNos = getActiveNotifications();
if (mCurrentNotifications.size() == 0) {
mCurrentNotifications.add(null);
mCurrentNotifications.set(0, activeNos);
mCurrentNotificationsCounts = activeNos.
} catch (Exception e) {
logNLS(&Should not be here!!&);
e.printStackTrace();
//获取当前状态栏显示通知总数
public static StatusBarNotification[] getCurrentNotifications() {
if (mCurrentNotifications.size() == 0) {
logNLS(&mCurrentNotifications size is ZERO!!&);
return mCurrentNotifications.get(0);
private static void logNLS(Object object) {
Log.i(TAG, TAG_PRE + object);
}而MainActivity主要负责界面显示与交互,关键代码如下:
public class MainActivity extends Activity {
private static final String TAG = &SevenNLS&;
private static final String TAG_PRE = &[&+MainActivity.class.getSimpleName()+&] &;
private static final int EVENT_SHOW_CREATE_NOS = 0;
private static final int EVENT_LIST_CURRENT_NOS = 1;
private static final String ENABLED_NOTIFICATION_LISTENERS = &enabled_notification_listeners&;
private static final String ACTION_NOTIFICATION_LISTENER_SETTINGS = &android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS&;
private boolean isEnabledNLS =
private TextView mTextV
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_SHOW_CREATE_NOS:
//显示创建的Notification对应的pkgName、Tag、Id
showCreateNotification();
case EVENT_LIST_CURRENT_NOS:
//显示当前所有的Notification数量及其包名
listCurrentNotification();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.textView);
protected void onResume() {
super.onResume();
//判断是否有开启Notification access
isEnabledNLS = isEnabled();
logNLS(&isEnabledNLS = & + isEnabledNLS);
if (!isEnabledNLS) {
//如果没有开启则显示确认对话框
showConfirmDialog();
public void buttonOnClicked(View view) {
mTextView.setTextColor(Color.BLACK);
switch (view.getId()) {
case R.id.btnCreateNotify:
logNLS(&Create notifications...&);
//创建可清除的Notification
createNotification(this);
//显示当前状态栏中所有Notification数量及其包名
mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_SHOW_CREATE_NOS), 50);
case R.id.btnClearLastNotify:
logNLS(&Clear Last notification...&);
//清除最后一个Notification
clearLastNotification();
//显示当前状态栏中所有Notification数量及其包名
mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_LIST_CURRENT_NOS), 50);
case R.id.btnClearAllNotify:
logNLS(&Clear All notifications...&);
//清除所有&可被清除&的Notification
clearAllNotifications();
mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_LIST_CURRENT_NOS), 50);
case R.id.btnListNotify:
logNLS(&List notifications...&);
listCurrentNotification();
case R.id.btnEnableUnEnableNotify:
logNLS(&Enable/UnEnable notification...&);
//打开Notification access启动/取消界面
openNotificationAccess();
//......省略
4. NotificationListenerService使用过程中有哪些注意事项?
& & & &&如果细心察看代码的童鞋,一定发现代码中有使用Handler,以及一些奇怪但又被注释掉的代码,比如&a.equals(&b&)&。从使用上来说,没有必要使用handler,那干嘛要多次一举?这里就给大家分享一下在写NotificationListenerDemo时遇到的一些坑。
①. NotificationMonitor的onCreate方法中使用handler来调用getActiveNotifications()方法
& & & &&若直接在onCreate或者onBind方法中调用getActiveNotifications()方法是无法获取当前系统通知。主要是因为NotificationMonitor还未完成初始化,而根本原因则是INotificationListenerWrapper对象mWrapper还未初始化,此时使用getActiveNotifications()方法又会调用到mWrapper,因此无法返回正常数据。在NotificationListenerService中可以看到getActiveNotifications()的源码:
public StatusBarNotification[] getActiveNotifications() {
return getNotificationInterface().getActiveNotificationsFromListener(mWrapper);
} catch (android.os.RemoteException ex) {
Log.v(TAG, &Unable to contact notification manager&, ex);
}也就是说只要在onBind方法完成之后,再调用getActiveNotifications()方法就可以正常获取数据了,因此这里使用了handler多线程的方式。当然,为了保险可以使用sendEmptyMessgeDelay加上延时。
②. 如果NotificationMonitor在onCreate或onBind方法中crash,则该service已经失效,需重启手机才能进行后续开发验证
& & & &&如果在onCreate或者onBind方法中,出现异常导致NotificationMonitor发生crash,就算找到问题并将其改正,之后的验证还是无法继续进行的,也就是无法收到通知的新增和删除消息,onNotificationPosted和onNotificationRemoved方法不会被调用。
& & & & 这也是我在onBind方法中故意注释导致空指针异常的代码,有兴趣的童鞋可以把注释去掉后尝试,去掉注释会导致NotificationListenerDemo异常停止,此时你再加上注释再次运行NotificationListenerDemo,虽然程序可以正常启动,但无法正常执行NotificationMonitor中的onNotificationPosted和onNotificationRemoved方法。这个涉及NotificationListenerService的原理,后面会另行分析。
③. MainActivity中onClick方法里使用handler操作
& & & &&当点击删除通知时,系统通知相关状态还未更新,此时还没有回调到NotificationMonitor中,所以获取的数据就还是上一次的数据。为了能够获取到正确的Notification数据,可以使用handler并加上延时,这样再去获取Notification信息时,系统已经触发了NotificationMonitor回调,数据也有正常了。另外,50ms的延时几乎是感知不到的。
④. 为什么要使用ArrayList来保存StatusBarNotification数组对象
& & & &&当新增或者删除通知时,会触发onNotificationPosted或onNotificationRemoved回调,在该方法中调用getActiveNotifications()方法用以获取当前系统通知信息。而getActiveNotifications()返回的是StatusBarNotification[]数组,因为这个数组是可变长的,也就是长度会随时变化,因此无法直接存储。使用ArrayList可以很好的解决这个问题,在ArrayList对象中添加一个StatusBarNotification[]对象,之后使用ArrayList.set(0,statusbar[])方法对数据进行更新即可。
& & & &&NotificationListenerService是Android 4.3 之后新增的接口服务,用于获取系统Notification信息,这在之前的Android版本是无法直接办到的。在Android 4.4中,增加了Notification.extra变量,使得获取Notification相关信息更加丰富,这些接口的开放更加利于三方应用的使用,但同时也会带来一些隐私问题。
& & & &&本文针对NotificationListenerService的使用进行了详细分析,当然其中不乏有失偏颇的地方,本着互联网知识共享精神也将自己的一些记录发布出来,一来可做笔记,二来希望能够给苦苦寻觅的童鞋一些帮助。
& & & &&后续会对NotificationListenerService的原理进行分析,敬请期待。
& & & &&NotificationMonitor代码免积分下载:
& & & &&为了后续能够更新,已经代码传到github上,有兴趣的童鞋可以在github上查看,连接戳。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:324106次
积分:3935
积分:3935
排名:第2647名
原创:53篇
评论:327条
(2)(1)(1)(1)(1)(2)(3)(1)(1)(1)(1)(1)(1)(2)(1)(1)(1)(1)(4)(1)(4)(3)(1)(1)(3)(2)(7)(1)(1)(3)

我要回帖

更多关于 android kitkat 的文章

 

随机推荐