微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

片段未附加到主机

如何解决片段未附加到主机

为了防万一,让我解释一下整个事情。我正在将BottomNavigationView与Jetpack的Mobile Navigation图形一起使用。我重新实现了该方法

NavigationUI.setupWithNavController(...)

在导航设置过程中,我没有使用这种方法,而是做了一个非常相似的事情:

customSetupWithNavController(...)

我所做的唯一更改是更改片段之间的认淡入淡出过渡,并开始使用更自然的(在我看来)侧滑动画,就像onNavDestinationSelected中一样:

if(origin == 0){
        builder.setEnteranim(R.anim.slide_in_from_right)
                .setExitAnim(R.anim.slide_out_to_left)
                .setPopEnteranim(R.anim.slide_in_from_left)
                .setPopExitAnim(R.anim.slide_out_to_right);
    }else if(origin == 1){
        builder.setEnteranim(R.anim.slide_in_from_left)
                .setExitAnim(R.anim.slide_out_to_right)
                .setPopEnteranim(R.anim.slide_in_from_right)
                .setPopExitAnim(R.anim.slide_out_to_left);
    }

原点代表传入片段的来源方向。

它带来一个问题:我的两个碎片需要一个FAB才能将元素添加到回收站中,并且侧滑片的过渡突然变得丑陋。因此,我在MainActivity的Layout中添加一个FAB,并且只有在调用这两个片段时,逻辑才会显示FAB。

我找不到一种将click事件从Activity传递给Fragments的好方法,因为导航无法处理整个过程,所以我无法实例化Fragments。

因此,我所做的就是创建一个ViewHolder,因为我知道它可以在生命周期变化中生存下来。这个ViewHolder拥有一个 int 一个 mutablelivedata ,在MainActivity逻辑中,我将BottomNavigationView选择的元素的当前选定ID传递给 int >,并且只有在单击MainActivity的FAB时,实时的 Boolean 才设置为true。因此,在片段 onViewCreated()中,当该值设置为true且传递给ViewHolder的ID与该ID匹配时,我向此 Boolean 添加了观察者。当前片段中,布尔值设置回false,可以完成某些操作,如下所示:

eventsNotificationHandler.getClickEvent().observe(requireActivity(),new Observer<Boolean>() {
        @Override
        public void onChanged(Boolean aBoolean) {
            if(aBoolean && eventsNotificationHandler.getPositionId() == R.id.nav_contacts){
                eventsNotificationHandler.setClickEvent(false);
                //do something here
            }
        }
    });

此notificationHandler是ViewHolder。

到目前为止,到目前为止,我可以做到

1-在BottomNavigationView的片段之间自由导航,FAB仅显示所需的片段。

2-随时可以在观察者内部使用Log.d(...),并看到调试消息就可以了。

3-随时随地敬酒一条消息,,如果上下文参数是在Observer外部初始化的,则如下所示:

Toast.makeText(以前为DefinedContext,“ SOME TEXT”,Toast.LENGTH_SHORT).show();

我不能做什么:

1-只要有需要,就可以在观察者内部使用与以前相同的想法启动一个活动,在观察者之前和之后初始化上下文,就像我能够启动意图一样,这个:

eventsNotificationHandler.getClickEvent().observe(requireActivity(),new Observer<Boolean>() {
        @Override
        public void onChanged(Boolean aBoolean) {
            if(aBoolean && eventsNotificationHandler.getPositionId() == R.id.nav_contacts){
                eventsNotificationHandler.setClickEvent(false);
                Intent newContact = new Intent(prevIoUslyDefinedContext,NewContactActivity.class);
                startActivity(newContact);
                requireActivity().overridePendingTransition(R.anim.slide_in_from_right,R.anim.slide_out_to_left);
            }
        }
    });

但是在这种情况下,如果我直接导​​航到这个特定的片段(在打开应用程序后定义了观察者的位置),我可以随意启动新的Activity 但仅限决定先浏览其他片段,然后再转到该片段尝试启动“活动”,应用程序崩溃

我注意到,当我从Observer内部调用requireContext()时,会发生这种确切的行为,但是它可以工作,但是随后停止工作。

该应用崩溃的原因:

E / Android运行时:致命异常:主要 流程:cu.arrowtech.bpawreckproject,PID:18019 java.lang.IllegalStateException:片段FragmentContacts {883259b}(9f127bdb-127d-4366-b90b-c8900a5a771e)}未附加到活动

我想要的:

1-如果可能的话,通过在MainActivity中按FAB从片段内部启动新Activity的正确方法

2-如果可能的解决方案意味着改变我已经拥有的逻辑,那么切换片段的一种好方法

3-继续使用Jetpack和导航图。

我可以通过在每个Fragment中使用2个独立的FAB来做我想做的事,但是过渡并不美观。

我愿意提出建议,即使这暗示着改变逻辑。我几乎可以肯定,这一定是一种更好的方法,而不是为此目的使用ViewHolder。

我想得到类似于Google Pay的东西,似乎是用于添加付款方式,通过和转账的按钮是相同的按钮,但是它可以适应每种情况。

解决方法

经过一些研究,我确实找到了一种方法来保持碎片之间的流畅过渡 AND 移动导航组件 AND MainMainity布局中的单个FAB。

我所做的是使用接口而不是ViewModels(我一直知道这种方法是错误的):

public interface SharedViewsInterface {
    void onFabClicked();
}

因此,在MainActivity中,我将该接口定义为null,并根据情况创建了一种定义该接口的方法。我的MainActivity看起来像:

public class MainActivity extends AppCompatActivity {
    
    //UI elements
    private FloatingActionButton main_fab;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

        //Same dode to get the custom animations
        //.......
    
        //Main and only Fab configuration
        main_fab = findViewById(R.id.main_fab);
        main_fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(sharedViewsInterface !=null){
                    sharedViewsInterface.onFabClicked();
                }
            }
        });    
    }


    //Other auxiliary methods
    public void setInterface(SharedViewsInterface sharedViewsInterface){
        this.sharedViewsInterface = sharedViewsInterface;
    }
}

这样做,我可以从每个片段中通过执行以下操作在onCreate中实现接口:

((MainActivity) requireActivity()).setInterface(new SharedViewsInterface() {
        @Override
        public void onFabClicked() {
            Intent newContact = new Intent(requireContext(),NewContactActivity.class);
            startActivity(newContact);
            requireActivity().overridePendingTransition(R.anim.slide_in_from_right_short,R.anim.slide_out_to_left_medium);
        }
});

这很好用,因为仅当可见带有接口实现的片段时才显示FAB,请参见我的示例gif

example app

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。