在通知单击时启动片段而不会丢失状态

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在通知单击时启动片段而不会丢失状态相关的知识,希望对你有一定的参考价值。

我有聊天应用程序,也通过通知点击直接启动。聊天片段也可以通过在应用内部单击手动启动。

我希望如果用户在聊天片段上点击主页按钮,然后点击通知,它应该在最后一个状态启动,不要调用活动的onDestroy然后onCreate

像这样在Fragment通知启动Activity

((AppCompatActivity)context).getFragmentManager().beginTransaction().replace(R.id.Navigation_Main_Layout, screenFragment,"Chat").commit();

我正在处理来自FirebaseMessagingService的通知

public class FireBase_Messaging_Service extends FirebaseMessagingService {

    public static final String TAG="###FireBase MSG###";
    public static final int NOTIFICATION=5;
    String UserName;
    String ID;
    String Msg;

    Map<String,String> data;
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
        Log.d(TAG,"From "+remoteMessage.getFrom());
        if (remoteMessage.getData().size()>0){
            data = remoteMessage.getData();
            Log.d(TAG,"Message Data "+remoteMessage.getData());
            data = remoteMessage.getData();

            UserName = data.get("name");
            ID = data.get("ID");
            Msg = data.get("Message");

            showNotification(Msg,ID,UserName);
        }

        if (remoteMessage.getNotification()!=null){
            Log.d(TAG,"Message Notification Body "+remoteMessage.getNotification().getBody());
           // Toast.makeText(this, "Notification "+remoteMessage.getNotification().getBody(), Toast.LENGTH_LONG).show();
        }
    }

    private void showNotification(String Message,String ID,String UserName) {
        Log.d(TAG,"Show Notification "+Message+" "+ID);
        Intent intent=new Intent(this, Navigation_Drawer.class);
        intent.putExtra("Type","Text");
        //intent.putExtra("Type",MsgType);
        intent.putExtra("ID",ID);
        intent.putExtra("uname",UserName);
        intent.putExtra("Message",Msg);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent pendingIntent=PendingIntent.getActivity(this,NOTIFICATION,intent,PendingIntent.FLAG_UPDATE_CURRENT);
        int color = getResources().getColor(R.color.black);
        String ChannelID = "Message";
        notificationChannel(ChannelID,"Chat");
        NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(),ChannelID)
                .setSmallIcon(R.drawable.default_x)
                .setColor(color)
                .setContentTitle(UserName)
                .setContentText(Message)
                .setChannelId(ChannelID)
                .setTicker("My App")
                .setDefaults(Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND | Notification.FLAG_SHOW_LIGHTS)
                .setLights(0xff00ff00, 1000, 500) // To change Light Colors
                .setStyle(new NotificationCompat.BigTextStyle().bigText(Message))//For Expandable View
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .setContentIntent(pendingIntent)
                .setAutoCancel(true);

        NotificationManagerCompat managerCompat = NotificationManagerCompat.from(this);
        managerCompat.notify(NOTIFICATION,builder.build());
    }

    @Override
    public void onDeletedMessages() {
        super.onDeletedMessages();
    }

    private void notificationChannel (String ChannelID, String channelName) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel  channel = new NotificationChannel(ChannelID,channelName, NotificationManager.IMPORTANCE_DEFAULT);
            channel.setLightColor(Color.GREEN);
            NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            notificationManager.createNotificationChannel(channel);
        }
    }
}

在上面的代码中,我尝试了Intent与不同的标志,如Intent.FLAG_ACTIVITY_NEW_TASK,IntentFLAG_ACTIVITY_SINGLE_TOPFLAG_ACTIVITY_BROUGHT_TO_FRONTFLAG_ACTIVITY_CLEAR_TOP等。但是,它总是首先调用活动的(导航抽屉)onDestroy然后onCreate。然后它从开始启动片段。

如何避免app创建qazxsw poi和qazxsw poi?

答案

据我所知,Android活动中所需的行为与活动和片段的Android生命周期相冲突。当用户按下后退或主页按钮时,活动或片段将在该活动或片段实例的生命周期之后通过ActivityFragment。你无法避免它,除非你在你的活动中调用onPause,这避免了活动中的onDestroy函数调用。但是,您不希望完成活动,您希望使用相同的活动并希望不重新创建该活动。

所以我在考虑一种解决问题的不同方法。大多数情况下,重新创建活动或片段的问题直接指示要获取的资源以及在初始化活动或片段时要获取大量资源是一种开销。因此,当资源在已保存的实例状态中已可用时,我们可能会避免获取要在活动或片段中使用的资源。

例如,当您在活动的finish函数中获取保存在SQLite数据库中的某些数据时,您可能不希望在活动的方向更改时再次获取它,这会强制重新创建活动。在这种情况下,你可能需要选择一个加载器(我说的是onDestroyonCreate的实现),它在Activity娱乐中幸存下来。如果已经获取,则使用加载器的实现将不会再从SQLite数据库获取数据,并将在重新创建活动时提供数据。

我想推荐的另一件好事是使用CursorLoader。你可能会发现LoaderCallbacks解释了实现。 ViewModel幸存于Activity,您可以使用documentation here保存实例状态,这将减少加载时间。

重点是,您可能无法欺骗生命周期功能,但您可能会选择使用数据模型,这些数据模型将在您重新创建活动和片段后继续存在。

另一答案

我在没有任何标志的情况下首次启动时加载活动和片段。当我收到通知时,我正在添加一个标志,该活动首先调用ViewModel然后ViewModel

我会在活动首次创建时在活动标记下的清单文件中添加onDestroy。它可以帮助我避免在Activity中重新创建Fragment。

onCreate

以上是关于在通知单击时启动片段而不会丢失状态的主要内容,如果未能解决你的问题,请参考以下文章

来自相机的 Android 丢失片段视图

在通知单击时将项目添加到片段内的 recyclerview

对“xxx”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们。 错误解决一例。(代码片段

Android:单击片段中的按钮时如何通知活动? [复制]

从第二个片段访问时 ViewModel 数据丢失状态

按下锁定/主页按钮时的通知,单击返回选项卡片段时的通知