我在几个地方看到了这一点,但无法完全弄清楚如何实现它,因为网上没有示例,我想知道我是否误解了它的含义。
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 方法中抛出错误。
有没有人知道这样做的信息,谢谢
正如@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。
这就是我所做的
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 事件。
如果有人不知道,我会更新 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 );
}
AppCompatActivity 扩展 FragmentActivity 扩展 ComponentActivity(androidx.fragment.app.ComponentActivity) 扩展 (androidx.core.app.ComponentActivity)
所以 addOnBackPressedCallback 也应该适用于 AppCompatActivity
更新方法
现在可以很容易地将 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 提供开箱即用的功能。
我试图实现以下逻辑:
该活动跟踪当前打开的片段并在
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()
,我们将得到循环调用。
因此,我禁用当前回调来触发原始回调。
科特林:
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)