在android中按下通知时如何打开片段页面
Posted
技术标签:
【中文标题】在android中按下通知时如何打开片段页面【英文标题】:How to open fragment page, when pressed a notification in android 【发布时间】:2014-12-23 21:00:06 【问题描述】:当我按下通知栏中的通知时,我试图打开一个片段。我的应用结构是:
带有导航抽屉菜单的基本活动从菜单打开的一些片段
b.setOnClickListener(new OnClickListener()
@SuppressWarnings( "deprecation", "static-access" )
public void onClick(View v)
w_nm=(NotificationManager) getActivity().getSystemService(getActivity().NOTIFICATION_SERVICE);
Notification notify=new Notification(R.drawable.notnificationlogo,waternoti,System.currentTimeMillis());
Intent notificationIntent = new Intent(getActivity(), Abc.class);
PendingIntent pending=PendingIntent.getActivity(getActivity(), 0,notificationIntent, 0);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_SINGLE_TOP );
notify.flags = Notification.DEFAULT_LIGHTS | Notification.FLAG_AUTO_CANCEL;
notify.setLatestEventInfo(getActivity(),waternoti,waternoti1, pending);
w_nm.notify(0, notify);
谁能告诉我如何链接到下一个片段页面(当前代码在扩展片段的类中)
【问题讨论】:
广播接收器? developer.android.com/reference/android/content/… 能否详细说明一下,我是android新手 【参考方案1】:如果您使用Navigation
组件,您可以使用NavDeepLinkBuilder
打开特定目的地:
val pendingIntent = NavDeepLinkBuilder(context)
.setComponentName(MainActivity::class.java)
.setGraph(R.navigation.nav_graph)
.setDestination(R.id.destination)
.setArguments(bundle)
.createPendingIntent()
...
notificationBuilder.setContentIntent(pendingIntent)
...
请注意,仅当您的目的地不在启动器活动中时才使用setComponentName
很重要。
【讨论】:
我无法用这个灵魂重新创建 backstack。当我使用此解决方案时,我有 Fragment A -> B -> C -> D -> E ,图表只有 A -> E 。有什么想法吗? 请注意,这会打开一个新的活动实例。我花了几个小时调试这个。还有其他方法可以打开现有活动,但我不确定 NavDeepLinkBuilder 是否正确 Android LinkWhen a user opens your app via an explicit deep link, the task back stack is cleared and replaced with the deep link destination. When nesting graphs, the start destination from each level of nesting—that is, the start destination from each <navigation> element in the hierarchy—is also added to the stack.
所以你必须创建嵌套图来使你的导航工作@AndroidRuntimeException【参考方案2】:
您将需要像往常一样开始您的基本活动,但在意图中添加一些关于将打开哪个菜单片段的额外信息。 在这里你可以看到它是如何完成的:https://***.com/a/8610916/1652236
这取决于您在用于启动/加载片段的活动“onCreate()”方法中检索到的额外信息。
查看这里例如如何使用片段:http://www.tutorialspoint.com/android/android_fragments.htm http://developer.android.com/guide/components/fragments.html
启动此程序的意图类似于:
Intent notificationIntent = new Intent(getActivity(), Abc.class);
notificationIntent.putExtra("menuFragment", "favoritesMenuItem");
在你的基础活动中:
@Override
protected void onCreate(final Bundle savedInstanceState)
String menuFragment = getIntent().getStringExtra("menuFragment");
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// If menuFragment is defined, then this activity was launched with a fragment selection
if (menuFragment != null)
// Here we can decide what do to -- perhaps load other parameters from the intent extras such as IDs, etc
if (menuFragment.equals("favoritesMenuItem"))
FavoritesFragment favoritesFragment = new FavoritesFragment();
fragmentTransaction.replace(android.R.id.content, favoritesFragment);
else
// Activity was not launched with a menuFragment selected -- continue as if this activity was opened from a launcher (for example)
StandardFragment standardFragment = new StandardFragment();
fragmentTransaction.replace(android.R.id.content, standardFragment);
【讨论】:
在这个应用程序中,我需要生成自己的消息作为通知,并且我将该按钮保留在操作栏上的菜单选项之一中,我只使用了一个活动,其余都是片段 据我了解,您需要从一些片段开始您的基本活动。并且片段类型必须取决于通知类型。是真的吗? 不是所有的片段,只有少数片段页面应该依赖于通知类型 也许我不完全理解你的问题。您能否发布您的基本活动代码,我可以帮忙吗? 好的,我现在解释一下,我有一个带有网格视图的活动,然后单击网格视图中的任何图标后,下一页是片段。我有 16 个图标及其各自的片段页面。我在操作栏上的菜单选项之一中保留了一个按钮,因此每当我单击它时都会生成自我通知。【参考方案3】:notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_SINGLE_TOP )
由于您的意图设置标志:FLAG_ACTIVITY_SINGLE_TOP,因此在创建活动时不会调用“onCreate()”,您应该在名为“onNewIntent()”的方法中接收参数。
【讨论】:
【参考方案4】:您还应该添加 .commit(); 和 ft1.addToBackStack(null); 这样它就不会与前一个重叠,并且如果您不做广告ft1.addToBackStack(null); 你的应用程序将退出,所以根据你的功能添加它
String menuFragment = getIntent().getStringExtra("menuFragment");
ft1 = getSupportFragmentManager().beginTransaction();
ft1.addToBackStack(null);
ft1.replace(R.id.frame_container, favoritesFragment).commit();
【讨论】:
【参考方案5】:这是一个详细的答案,我相信如果您仔细遵循它。你会解决你的问题。
当您从 Firebase
发送 notification
时,此方法首先运行
public class FirebaseMessageService extends FirebaseMessagingService
private static final String TAG = "MyFirebaseMsgService";
Map<String, String> data;
// [START receive_message]
@Override
public void onMessageReceived(RemoteMessage remoteMessage)
if (remoteMessage.getData().size() > 0)
removeUserInfoByKeyAsStatic(getApplicationContext(), USER_KNOW_CREATED_EVENT_NOTIFICATION_DATA);
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
data = remoteMessage.getData();
HashMap<String, String> copyData = new HashMap<>(data);
//Calling method to generate notification
sendNotification(data.get("body"), data.get("title"), copyData);
然后你运行上面的sendNotification(..)
方法。在这种方法中,我将notification data
设置为SharedPref
。不要冒犯它。我们稍后会在使用时立即删除它。
我使用我的login data
并根据我的roleID
将intent
设置为不同的Activity
private void sendNotification(String messageBody, String messageTitle, HashMap<String, String> data)
// this methods checks my notification data is null ? isNullOrEmptyExt : "simple java is null control method"
if (!isNullOrEmptyExt(data.get("data")))
Intent intent;
final User myInfos = getMyInfos(getApplicationContext()); // this gives me login user data.
boolean isConsumerOrVolunteer = myInfos.getRoleID() == Constants.ROLES.CONSUMER || myInfos.getRoleID() == Constants.ROLES.VOLUNTEER;
// I want to show here. You can select diffrent Activity with your data..
if (isConsumerOrVolunteer)
// this set my notification data to SharedPref
setUserInfoByKeyAsStatic(getApplicationContext(), USER_KNOW_CREATED_EVENT_NOTIFICATION_DATA, data.get("data"));
intent = new Intent(this, EventListActivity.class);
else
intent = new Intent(this, ProducerActivity.class);
// after from here are the generally same. tricks above
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
String channelId = getString(R.string.default_notification_channel_id);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(messageTitle)
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Since android Oreo notification channel is needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
NotificationChannel channel = new NotificationChannel(channelId,
"Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
当您发送notification
时,上述两种方法都会运行。所以之后你会点击手机上的通知..对..这个点击操作会打开你之前在sendNotification(..)
方法中设置的Intent(ActivityName)
。
例如,您点击通知,您的ProducerActivity
或EventListActivity
就会打开..
如果您的角色是消费者或志愿者(根据我的应用角色),您将notification data
设置为SharedPref
boolean isConsumerOrVolunteer = myInfos.getRoleID() == Constants.ROLES.CONSUMER || myInfos.getRoleID() == Constants.ROLES.VOLUNTEER;
// I want to show here. You can select diffrent Activity with your data..
if (isConsumerOrVolunteer)
// this set my notification data to SharedPref
setUserInfoByKeyAsStatic(getApplicationContext(), USER_KNOW_CREATED_EVENT_NOTIFICATION_DATA, data.get("data"));
intent = new Intent(this, EventListActivity.class);
else
intent = new Intent(this, ProducerActivity.class);
所以你打开了EventListActivity
。让我们看看EventListActivity
会做什么
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event_list_main);
GsonBuilder gsonBuilder = new GsonBuilder();
gson = gsonBuilder.create();
// this gives me data from `SharePref`
String notificationEventDataString = getUserInfoByKeyAsStatic(this, USER_KNOW_CREATED_EVENT_NOTIFICATION_DATA);
// then check the datastring that comes from SharedPref - simple java null check method
if(!isNullOrEmptyExt(notificationEventDataString))
Bundle bundle = new Bundle();
bundle.putParcelable(EVENT, gson.fromJson(notificationEventDataString, Event.class));
removeUserInfoByKeyAsStatic(this, USER_KNOW_CREATED_EVENT_NOTIFICATION_DATA);
openFragmentWithoutAnimation(this, R.id.drawer_layout, bundle, EventPreviewFragment.class, EVENT_PREVIEW_FRAGMENT);
您从 SharedPref
获取数据。这不会为空,因为当您收到 notfication 时,我们已经在 sendNotification(..)
方法中设置了它。
所以你把你的data
放到bundle
并用bundle data
打开Fragment
。在您删除包含我的notification data
的SharedPref
数据后立即
我还与您分享我的自定义方法
这是片段打开方法
public static void openFragmentWithoutAnimation(Context context, int replaceLayout, Bundle bundle, Class<?> fragment, String fragmentTag)
Fragment dynamicFragment = null;
try
Class<?> clazz = Class.forName(fragment.getName());
dynamicFragment = (Fragment) clazz.newInstance();
System.out.println(clazz.getSuperclass());
System.out.println(clazz.getName());
catch (ClassNotFoundException e)
e.printStackTrace();
catch (InstantiationException e)
e.printStackTrace();
catch (IllegalAccessException e)
e.printStackTrace();
AppCompatActivity activity = null;
if (context instanceof AppCompatActivity)
activity = ((AppCompatActivity) context);
if (activity.getSupportFragmentManager().findFragmentByTag(fragmentTag) == null)
FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
if (bundle != null)
dynamicFragment.setArguments(bundle);
transaction.add(replaceLayout, dynamicFragment, fragmentTag);
transaction.addToBackStack(fragmentTag);
transaction.commit();
这些是 SharedPref 设置和获取方法
public static void setUserInfoByKeyAsStatic(Context context, String key, String value)
final SharedPreferences prefs = context.getSharedPreferences(
USER_INFO_PREFS_KEY, Context.MODE_PRIVATE);// Saved token can be accessed only from this app or other apps that shared same id with this app.
SharedPreferences.Editor editor = prefs.edit();
editor.putString(key, value);
editor.apply();
public static String getUserInfoByKeyAsStatic(Context context, String key)
final SharedPreferences controlPrefs = context.getSharedPreferences(
USER_INFO_PREFS_KEY, Context.MODE_PRIVATE);
return controlPrefs.getString(key,null);
这些是空检查方法
public static boolean isNullOrEmpty(String value)
if(value == null)
return true;
else return value.isEmpty() || value.equals("null");
public static boolean isNullOrEmptyExt(String value)
if(value == null)
return true;
else return value.isEmpty() || value.equals("null") || value.equals(JSON_ARRAY_EMPTY) || value.equals(JSON_OBJECT_EMPTY);
【讨论】:
以上是关于在android中按下通知时如何打开片段页面的主要内容,如果未能解决你的问题,请参考以下文章
如果在 WebView 片段中按下后退按钮,如何返回上一页?
android 在一个Activity 中按下返回键,不结束这个Activity 而是返回上个页面,如何实现?