如何在fragment中添加onBackPressedCallback?

问题描述 投票:0回答:7

我在几个地方看到了这一点,但无法完全弄清楚如何实现它,因为网上没有示例,我想知道我是否误解了它的含义。

addOnBackPressedCallback 的 Android 开发者链接

我想知道这是否意味着我可以在片段中添加一个回调,以在

onBackPressed()
到达活动之前拾取它。

在我的片段中我已经实现了

implements OnBackPressedCallBack

然后实现方法

@Override
public boolean handleOnBackPressed() {
    Log.d(TAG, "handleOnBackPressed: hello");
    return true;
}

但它没有拿起它并直接进入主要活动

onBackPressed()

我继续阅读,发现我的片段需要从 FragmentActivity 扩展

public class MainExampleFragment extends FragmentActivity implements View.OnClickListener, OnBackPressedCallback {

而不是

appCompatActivity.getSuppportFragmentManager

打电话

FragmentActivity.getSupportFragmentManager 

相反,但是当尝试设置捆绑包时,这会在 Fragment.newInstance 方法中抛出错误。

有没有人知道这样做的信息,谢谢

android
7个回答
20
投票

正如@Derek Zhu 指出的那样,如果您在 Activity 中重写 onBackPressed,则 Fragment 的 onBackPressedCallback 似乎不起作用。我发现如果我也想在活动中使用它,那么我也需要在那里使用

onBackPressedDispatcher.addCallback

活动:

onBackPressedDispatcher.addCallback(
        this,
        object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                Log.d(TAG, "Activity back pressed invoked")
                // Do custom work here    

                // if you want onBackPressed() to be called as normal afterwards
                if (isEnabled) {
                    isEnabled = false
                    requireActivity().onBackPressed()
                }
            }
        }
)

片段:

requireActivity().onBackPressedDispatcher.addCallback(
        this,
        object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                Log.d(TAG, "Fragment back pressed invoked")
                // Do custom work here    

                // if you want onBackPressed() to be called as normal afterwards
                if (isEnabled) {
                    isEnabled = false
                    requireActivity().onBackPressed()
                }
            }
        }
)

上面的结果是会调用Fragment backpressed,然后调用Activitybackpressed。


4
投票

这就是我所做的

public class MyFragment extends Fragment {

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

        requireActivity().getOnBackPressedDispatcher().addCallback(this, onBackPressedCallback);
    }

    private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(true /* Enabled by default */) {
        @Override
        public void handleOnBackPressed() {
            // Handle the back button event

            if (fieldsModified()) {
                // User made changes on EditText on the Fragment. Confirm exit to avoid loss of data

                AlertDialog.Builder builder= new AlertDialog.Builder(getContext());
                builder.setMessage(msg_confirm_close_form);
                builder.setPositiveButton(R.string.btn_yes, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        closeFragment();
                    }
                });
                builder.setNegativeButton(R.string.btn_no, null);
                builder.show();
            }
            else {
                closeFragment();
            }
        }

        private void closeFragment() {
            // Disable to close fragment
            this.setEnabled(false);
            requireActivity().getOnBackPressedDispatcher().onBackPressed();
        }
    };  
}

您必须在 Fragment 中实现回调,以通过活动的调度程序拦截 onBackPressed 事件。


2
投票

如果有人不知道,我会更新 Fragment 和 AppCompacTActivity 的 OnBackPressedCallBack,并且我在这里有嵌套 Fragment

在片段中

public class MessageFragment extends Fragment  {

public MessageFragment() {
    // Required empty public constructor
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    // This callback will only be called when MyFragment is at least Started.
    OnBackPressedCallback callback = new OnBackPressedCallback(true ) {
        @Override
        public void handleOnBackPressed() {
            // Handle the back button event
            FragmentManager fm= getFragmentManager();
            if (fm != null) {
                if (fm.getBackStackEntryCount() > 0) {
                    fm.popBackStack();
                    Log.e( "backpress Frag","back" );

                }

                List<Fragment> fragList = fm.getFragments();
                if (fragList != null && fragList.size() > 0) {
                    for (Fragment frag : fragList) {
                        if (frag == null) {
                            continue;
                        }
                        if (frag.isVisible()) {
                          Log.e( "backpress Frag","Visible" );
                        }
                    }
                }
            }


        }
    };
    requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
    super.onCreate( savedInstanceState );
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View root=inflater.inflate( R.layout.fragment_listning, container, false );

    return root;
}

并且您在 MainActivity 中删除 OnBackpressed() 方法并添加这个新方法

OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback( true ) {
    boolean doubleBackToExitPressedOnce=false;
    @Override
    public void handleOnBackPressed() {

        if (doubleBackToExitPressedOnce) {
            ActivityCompat.finishAffinity( FirstActivity.this );
            Log.e( "Click", "double back" );
            return;
        }

        this.doubleBackToExitPressedOnce = true;
        Toast.makeText(FirstActivity.this,getStrin(R.string.exitapp),Toast.LENGTH_SHORT).show();

        new Handler().postDelayed( new Runnable() {

            @Override
            public void run() {
                doubleBackToExitPressedOnce=false;
            }
        }, 2000);


    }
};

 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate( savedInstanceState );
    setContentView( R.layout.activity_first );
    //getting bottom navigation view and attaching the listener


    getOnBackPressedDispatcher().addCallback( this, onBackPressedCallback );

}

0
投票

AppCompatActivity 扩展 FragmentActivity 扩展 ComponentActivity(androidx.fragment.app.ComponentActivity) 扩展 (androidx.core.app.ComponentActivity)

所以 addOnBackPressedCallback 也应该适用于 AppCompatActivity


0
投票

更新方法

现在可以很容易地将 backpress 处理程序添加到任何片段 https://developer.android.com/reference/androidx/activity/OnBackPressedDispatcher


已弃用的方法:请勿使用

您无法直接处理片段内的

onBackpressed

你可以做的就是通过某种方式将

onBackPressed
事件传递给当前显示的片段。

一种基本方法是创建一个像这样的界面:

interface BackHandler {
    handleBackPressed(): Boolean
}

然后在你的片段上实现它,如下所示:

class YourFragment : Fragment(), BackHandler {
    ...
    override handleBackPressed(): Boolean {
        // do Your thing here
    }
    ...
}

在您的活动中执行以下操作:

onBackPressed

class YourActivity: Activity() {
    ...
    override onBackPressed() {
        val currentFragment = supportFragmentManager.findFragmentById(yourviewid)
        if (currentFragment is BackHandler) {
            (currentFragment as BackHandler).handleBackPressed()
        } else {
            super.onBackPressed()
        }
    }
    ...
}

这只是一种方法。您还可以使用类似

EventBus
或其他一些实现。关键是 Android 并没有为 Fragment 提供开箱即用的功能。


0
投票

我试图实现以下逻辑:

该活动跟踪当前打开的片段并在

currentState
(枚举变量)中记录数字。 对于授权片段,BackStack 应照常工作,授权片段是应用程序的入口点。 但是
USER_FRAGMENT
,当按后退按钮时,应该退出应用程序,绕过注册页面。

LOGIN_FRAGMENT ->X USER_FRAGMENT
or 
LOGIN_FRAGMENT -> REGISTER_FRAGMENT ->X USER_FRAGMENT

并且在重新定义

OnBackPressedCallback
时,出现了如何调用原来的
OnBackPressedCallback
的问题。

new OnBackPressedCallback(true) {
    @Override
    public void handleOnBackPressed() {
        // Depending on which fragment we're on right now
        switch (currentState) {
            case LOGIN_FRAGMENT:
            case REGISTER_FRAGMENT:
                // In other cases, the usual Callback works, and we disable this Callback
                setEnabled(false);
                getOnBackPressedDispatcher().onBackPressed();
                setEnabled(true);
                break;
            case USER_FRAGMENT:
                // Description of exit points from the application
                // exiting the main interface is just exiting the application
                finish();
        }
    }
};

我是通过以下方式做到的:

setEnabled(false);
getOnBackPressedDispatcher().onBackPressed();
setEnabled(true);

这是有效的,因为

OnBackPressedCallback
调用最近添加的回调,不包括禁用的回调。 如果我们只调用
getOnBackPressedDispatcher().onBackPressed()
,我们将得到循环调用。 因此,我禁用当前回调来触发原始回调。


-1
投票

科特林:

     val mOnBackPressedCallback= object : OnBackPressedCallback(active) {
        override fun handleOnBackPressed() {
            if (active) {
                // Do something
            } else {
                // call onBackPressed() as normal afterwards
                remove()
                requireActivity().onBackPressed()
            }
        }
    }

向调度程序添加回调:

requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, mOnBackPressedCallback)

© www.soinside.com 2019 - 2024. All rights reserved.