1、问题场景:
安卓混合开发应用中,本地服务service接收服务器推送的告警消息,收到告警消息后发送通知Notification,当点击通知栏上的告警消息,需要跳转到前端实现的某个 历史告警信息页面,即在发送通知的pendingIntent中要传递 前端告警页面的url信息。问题出现为每次点击跳转后,intent中的参数url传递过去始终为空:
服务中发送通知: Intent intent1 = new Intent(mContext, WebViewActivity.class); Bundle bundle = new Bundle(); bundle.putString("url","http://www.baidu.com"); intent1.putExtras(bundle); AFLog.d(TAG,"#####notification intent1=" + intent1.toString()); PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent1, 0); AFLog.d(TAG,"#####notification pi=" + pi.toString());
webview界面中响应通知接收参数的地方:
if (null != intent) { Bundle data = intent.getExtras(); AFLog.d(TAG, "#####data = "+ (null ==data ? null : data.toString())); if (null != data){ String url = data.getString("url"); AFLog.d(TAG, "#####url = "+ url); } }
测试结果总是data为空:
05-16 14:12:25.231 26313 26313 D WebViewActivity: #####data = null
2、问题分析
刚开始分析问题时总以为是自己代码在某个步骤将intent的传递参数漏掉了,后台在每一处传递都增加了日志显示,并没有问题,而且intent指定的跳转Activity 是能正常找到并启动的,也进入该Acitivity的onCreate 的生命周期,但是就是无法获取参数,百思不得其解。甚至开始将跳转的Activity改成单例模式 :
android:launchMode="singleTask"
然后在
@Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); AFLog.d(TAG, "#####onNewIntent intent="+ ((null == intent)? null: intent.toString())); if (null != intent) { Bundle data = intent.getExtras(); AFLog.d(TAG, "#####data = "+ (null ==data ? null : data.toString())); if (null != data){ String url = data.getString("url"); AFLog.d(TAG, "#####url = "+ url); } } }
去获取参数,依然为空。我当然也知道这个问题和Activity的 launch mode 方式没有关系,但是人就是如此,当找不到问题的真正原因时,只能够在已有的观念中去怀疑,去尝试,所以有时候会因为自己的无知而怀疑人生。
最终还是通过网络找到了其他人的分析结果,刚开始其实就在查找是不是Notification 的使用问题,但是没有找到正确的方案,真正原因如下所示:
https://www.cnblogs.com/anrainie/articles/2383941.html
还是要对API接口的使用参数进行真正的深入了解,单纯的粘贴复制都是花架子。遇到问题时就是半吊子,一知半解而导致有时候像无头苍蝇一样乱撞,解决问题的效率就大打折扣了。
public @interface Flags {} /** * Flag indicating that this PendingIntent can be used only once. * For use with {@link #getActivity}, {@link #getBroadcast}, and * {@link #getService}.If set, after * {@link #send()} is called on it, it will be automatically * canceled for you and any future attempt to send through it will fail. */ public static final int FLAG_ONE_SHOT = 1<<30; /** * Flag indicating that if the described PendingIntent does not * already exist, then simply return null instead of creating it. * For use with {@link #getActivity}, {@link #getBroadcast}, and * {@link #getService}. */ public static final int FLAG_NO_CREATE = 1<<29; /** * Flag indicating that if the described PendingIntent already exists, * the current one should be canceled before generating a new one. * For use with {@link #getActivity}, {@link #getBroadcast}, and * {@link #getService}.
You can use * this to retrieve a new PendingIntent when you are only changing the * extra data in the Intent; by canceling the previous pending intent, * this ensures that only entities given the new data will be able to * launch it. If this assurance is not an issue, consider * {@link #FLAG_UPDATE_CURRENT}. */ public static final int FLAG_CANCEL_CURRENT = 1<<28; /** * Flag indicating that if the described PendingIntent already exists, * then keep it but replace its extra data with what is in this new * Intent. For use with {@link #getActivity}, {@link #getBroadcast}, and * {@link #getService}.
This can be used if you are creating intents where only the * extras change, and don't care that any entities that received your * previous PendingIntent will be able to launch it with your new * extras even if they are not explicitly given to it. */ public static final int FLAG_UPDATE_CURRENT = 1<<27; /** * Flag indicating that the created PendingIntent should be immutable. * This means that the additional intent argument passed to the send * methods to fill in unpopulated properties of this intent will be * ignored. */ public static final int FLAG_IMMUTABLE = 1<<26;
问题的关键就是这个flag参数的使用,改成如下就可以:
PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent1, PendingIntent.FLAG_UPDATE_CURRENT);