มีวิธีที่เราสามารถนำไปใช้onBackPressed()
ใน Android Fragment คล้ายกับวิธีที่เราใช้ใน Android Activity หรือไม่?
onBackPressed()
ในฐานะที่เป็นวงจรชีวิตส่วนไม่ได้ มีวิธีอื่นในการขี่มากกว่าonBackPressed()
ใน Android 3.0 แฟรกเมนต์หรือไม่?
มีวิธีที่เราสามารถนำไปใช้onBackPressed()
ใน Android Fragment คล้ายกับวิธีที่เราใช้ใน Android Activity หรือไม่?
onBackPressed()
ในฐานะที่เป็นวงจรชีวิตส่วนไม่ได้ มีวิธีอื่นในการขี่มากกว่าonBackPressed()
ใน Android 3.0 แฟรกเมนต์หรือไม่?
คำตอบ:
ฉันแก้ไขด้วยวิธีนี้แทนที่onBackPressed
ในกิจกรรม ทั้งหมดFragmentTransaction
เป็นaddToBackStack
ก่อนที่จะกระทำการ:
@Override
public void onBackPressed() {
int count = getSupportFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
//additional code
} else {
getSupportFragmentManager().popBackStack();
}
}
ในความคิดของฉันทางออกที่ดีที่สุดคือ:
สร้างส่วนต่อประสานที่เรียบง่าย:
public interface IOnBackPressed {
/**
* If you return true the back press will not be taken into account, otherwise the activity will act naturally
* @return true if your processing has priority if not false
*/
boolean onBackPressed();
}
และในกิจกรรมของคุณ
public class MyActivity extends Activity {
@Override public void onBackPressed() {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_container);
if (!(fragment instanceof IOnBackPressed) || !((IOnBackPressed) fragment).onBackPressed()) {
super.onBackPressed();
}
} ...
}
ในที่สุดในส่วนของคุณ:
public class MyFragment extends Fragment implements IOnBackPressed{
@Override
public boolean onBackPressed() {
if (myCondition) {
//action not popBackStack
return true;
} else {
return false;
}
}
}
interface IOnBackPressed {
fun onBackPressed(): Boolean
}
class MyActivity : AppCompatActivity() {
override fun onBackPressed() {
val fragment =
this.supportFragmentManager.findFragmentById(R.id.main_container)
(fragment as? IOnBackPressed)?.onBackPressed()?.not()?.let {
super.onBackPressed()
}
}
}
class MyFragment : Fragment(), IOnBackPressed {
override fun onBackPressed(): Boolean {
return if (myCondition) {
//action not popBackStack
true
} else {
false
}
}
}
R.id.main_container
อะไร นั่นคือ ID สำหรับ FragmentPager หรือไม่
.?
) และการบังคับใช้ non-nulls ( !!
) สามารถนำไปสู่ NPEs - นักแสดงไม่ได้ปลอดภัยเสมอไป ฉันอยากเขียนif ((fragment as? IOnBackPressed)?.onBackPressed()?.not() == true) { ... }
kotliney หรือมากกว่านั้น(fragment as? IOnBackPressed)?.onBackPressed()?.not()?.let { ... }
.onBackPressed()?.takeIf { !it }?.let{...}
หรือ .not()
แค่คืนค่าผกผัน
val fragment = this.supportFragmentManager.findFragmentById(R.id.flContainer) as? NavHostFragment val currentFragment = fragment?.childFragmentManager?.fragments?.get(0) as? IOnBackPressed currentFragment?.onBackPressed()?.takeIf { !it }?.let{ super.onBackPressed() }
เหมาะสำหรับผู้ที่ใช้ Kotlin และ NavigationController
ตาม @HaMMeRed คำตอบที่นี่คือ pseudocode วิธีการใช้งาน ให้บอกว่ากิจกรรมหลักของคุณถูกเรียกBaseActivity
ซึ่งมีชิ้นส่วนย่อยของเด็ก (เช่นในตัวอย่างของ SlideMenu lib) นี่คือขั้นตอน:
ก่อนอื่นเราต้องสร้างส่วนต่อประสานและคลาสซึ่งใช้ส่วนต่อประสานเพื่อให้มีวิธีการทั่วไป
สร้างอินเตอร์เฟสคลาส OnBackPressedListener
public interface OnBackPressedListener {
public void doBack();
}
สร้างคลาสที่ใช้ทักษะของ OnBackPressedListener
public class BaseBackPressedListener implements OnBackPressedListener {
private final FragmentActivity activity;
public BaseBackPressedListener(FragmentActivity activity) {
this.activity = activity;
}
@Override
public void doBack() {
activity.getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
ตั้งแต่ตอนนี้เราจะทำงานกับโค้ดBaseActivity
และแฟรกเมนต์ของมัน
สร้างฟังส่วนตัวบนชั้นเรียนของคุณ BaseActivity
protected OnBackPressedListener onBackPressedListener;
สร้างวิธีการตั้งค่าฟัง BaseActivity
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
ในการแทนที่onBackPressed
ใช้สิ่งที่ต้องการ
@Override
public void onBackPressed() {
if (onBackPressedListener != null)
onBackPressedListener.doBack();
else
super.onBackPressed();
ในส่วนของonCreateView
คุณคุณควรเพิ่มผู้ฟังของเรา
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
activity = getActivity();
((BaseActivity)activity).setOnBackPressedListener(new BaseBackPressedListener(activity));
View view = ... ;
//stuff with view
return view;
}
Voila ตอนนี้เมื่อคุณคลิกกลับมาในส่วนที่คุณควรจะจับวิธีการที่กำหนดเองของคุณกลับ
onBackPressed()
ชิ้นส่วนใดถูกแสดงเมื่อกดปุ่มย้อนกลับ
((BaseActivity)activity).setOnBackPressedListener(new OnBackpressedListener(){ public void doBack() { //...your stuff here }});
สิ่งนี้ใช้ได้สำหรับฉัน: https://stackoverflow.com/a/27145007/3934111
@Override
public void onResume() {
super.onResume();
if(getView() == null){
return;
}
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK){
// handle back button's click listener
return true;
}
return false;
}
});
}
หากคุณต้องการฟังก์ชั่นประเภทนั้นคุณจะต้องแทนที่มันในกิจกรรมของคุณแล้วเพิ่ม a YourBackPressed
อินเทอร์เฟซให้กับแฟรกเมนต์ทั้งหมดของคุณซึ่งคุณโทรหาแฟรกเมนต์ที่เกี่ยวข้องทุกครั้งที่กดปุ่มย้อนกลับ
แก้ไข: ฉันต้องการผนวกคำตอบก่อนหน้าของฉัน
ถ้าฉันจะทำวันนี้ฉันจะใช้การออกอากาศหรืออาจจะเป็นการออกอากาศที่สั่งถ้าฉันคาดว่าแผงอื่น ๆ เพื่ออัปเดตพร้อมกันไปยังแผงหลัก / เนื้อหาหลัก
LocalBroadcastManager
ใน Support Library สามารถช่วยคุณได้และคุณเพียงแค่ส่งการออกอากาศonBackPressed
และสมัครสมาชิกในส่วนที่คุณสนใจ ฉันคิดว่าการส่งข้อความเป็นการใช้งานที่แยกกันมากขึ้นและจะขยายขนาดได้ดีขึ้นดังนั้นจึงเป็นคำแนะนำการใช้งานอย่างเป็นทางการของฉันในตอนนี้ เพียงใช้การIntent
กระทำของเป็นตัวกรองสำหรับข้อความของคุณ ส่งสิ่งที่คุณสร้างขึ้นใหม่ACTION_BACK_PRESSED
ส่งจากกิจกรรมของคุณและฟังในส่วนที่เกี่ยวข้อง
LocalBroadcastManager
ไม่สามารถทำการสั่งออกอากาศได้
ไม่มีสิ่งใดที่ใช้งานได้ง่ายและจะไม่ทำงานในวิธีที่เหมาะสมที่สุด
แฟรกเมนต์มีเมธอด call onDetach ที่จะทำงาน
@Override
public void onDetach() {
super.onDetach();
PUT YOUR CODE HERE
}
งานนี้จะทำ
หากคุณกำลังใช้งานandroidx.appcompat:appcompat:1.1.0
หรือสูงกว่าคุณสามารถเพิ่มOnBackPressedCallback
ส่วนย่อยของคุณได้ดังต่อไปนี้
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()
}
}
}
)
ดูhttps://developer.android.com/guide/navigation/navigation-custom-back
androidx-core-ktx
งานคุณสามารถใช้requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) { /* code to be executed when back is pressed */ }
LifecycleOwner
ควรเพิ่มพารามิเตอร์ในตัวอย่างนี้ หากไม่มีก็จะมีชิ้นส่วนใด ๆ ที่เริ่มต้นหลังจากนั้นจะเรียกhandleBackPressed()
ถ้ากดปุ่มย้อนกลับ
เพียงเพิ่มaddToBackStack
ในขณะที่คุณกำลังเปลี่ยนระหว่างชิ้นส่วนของคุณเช่นด้านล่าง:
fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();
ถ้าคุณเขียนaddToBackStack(null)
มันจะจัดการด้วยตัวเอง แต่ถ้าคุณให้แท็กคุณควรจัดการด้วยตนเอง
เนื่องจากคำถามนี้และคำตอบบางอย่างมีอายุเกินห้าปีให้ฉันแบ่งปันคำตอบของฉัน นี่คือการติดตามและการสร้างสรรค์สิ่งใหม่เพื่อคำตอบจาก @oyenigun
UPDATE: ที่ด้านล่างของบทความนี้ฉันได้เพิ่มการใช้งานทางเลือกโดยใช้ส่วนขยายนามธรรมที่ไม่เกี่ยวข้องกับกิจกรรมเลยซึ่งจะเป็นประโยชน์สำหรับทุกคนที่มีลำดับชั้นของส่วนย่อยที่ซับซ้อนมากขึ้นซึ่งเกี่ยวข้องกับพฤติกรรมซ้อนต่าง ๆ
ฉันต้องใช้สิ่งนี้เพราะบางส่วนที่ฉันใช้มีมุมมองที่เล็กกว่าที่ฉันต้องการยกเลิกด้วยปุ่มย้อนกลับเช่นมุมมองข้อมูลขนาดเล็กที่ปรากฏขึ้น ฯลฯ แต่นี่เป็นสิ่งที่ดีสำหรับทุกคนที่ต้องการแทนที่พฤติกรรมของ ปุ่มย้อนกลับภายในชิ้นส่วน
ก่อนกำหนดอินเทอร์เฟซ
public interface Backable {
boolean onBackPressed();
}
อินเทอร์เฟซนี้ซึ่งฉันเรียกว่าBackable
(ฉันเป็นตัวจัดการข้อตกลงการตั้งชื่อ) มีวิธีการเดียวonBackPressed()
ที่ต้องคืนboolean
ค่า เราจำเป็นต้องบังคับใช้ค่าบูลีนเพราะเราจำเป็นต้องทราบว่าการกดปุ่มย้อนกลับมีการ "ดูดซับ" เหตุการณ์ด้านหลังหรือไม่ การส่งคืนtrue
หมายความว่ามีและไม่จำเป็นต้องดำเนินการใด ๆ เพิ่มเติมมิฉะนั้นจะfalse
กล่าวว่าการดำเนินการย้อนกลับเริ่มต้นยังคงเกิดขึ้น อินเทอร์เฟซนี้ควรเป็นไฟล์ของตัวเอง (ควรอยู่ในแพ็คเกจที่แยกต่างหากinterfaces
) จำไว้ว่าการแยกชั้นเรียนของคุณออกเป็นแพ็คเกจเป็นแนวปฏิบัติที่ดี
ประการที่สองพบชิ้นส่วนด้านบน
ฉันสร้างวิธีการที่ส่งคืนFragment
วัตถุสุดท้ายในกองหลัง ฉันใช้แท็ก ... หากคุณใช้ ID ให้ทำการเปลี่ยนแปลงที่จำเป็น ฉันมีวิธีแบบคงที่นี้ในคลาสยูทิลิตี้ที่เกี่ยวข้องกับรัฐนำทาง ฯลฯ ... แต่แน่นอนวางไว้ในตำแหน่งที่เหมาะสมที่สุดสำหรับคุณ NavUtils
สำหรับการสั่งสอนผมได้วางระเบิดในระดับที่เรียกว่า
public static Fragment getCurrentFragment(Activity activity) {
FragmentManager fragmentManager = activity.getFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
String lastFragmentName = fragmentManager.getBackStackEntryAt(
fragmentManager.getBackStackEntryCount() - 1).getName();
return fragmentManager.findFragmentByTag(lastFragmentName);
}
return null;
}
ตรวจสอบให้แน่ใจว่าจำนวนสแต็กหลังมากกว่า 0 มิฉะนั้นArrayOutOfBoundsException
จะถูกส่งออกไปที่รันไทม์ หากไม่ใช่มากกว่า 0 ให้ส่งคืนค่าว่าง เราจะตรวจสอบค่าว่างในภายหลัง ...
ประการที่สามนำไปใช้ในส่วน
ใช้Backable
อินเทอร์เฟซในส่วนใดก็ตามที่คุณต้องการแทนที่ลักษณะการทำงานของปุ่มย้อนกลับ เพิ่มวิธีการใช้งาน
public class SomeFragment extends Fragment implements
FragmentManager.OnBackStackChangedListener, Backable {
...
@Override
public boolean onBackPressed() {
// Logic here...
if (backButtonShouldNotGoBack) {
whateverMethodYouNeed();
return true;
}
return false;
}
}
ในการonBackPressed()
แทนที่ให้ใส่ตรรกะที่คุณต้องการ หากคุณต้องการให้ปุ่มย้อนกลับไม่ปรากฏสแต็กกลับ (พฤติกรรมเริ่มต้น) ให้คืนค่าจริงว่าเหตุการณ์ด้านหลังของคุณถูกดูดซับ มิฉะนั้นส่งคืน false
สุดท้ายในกิจกรรมของคุณ ...
แทนที่onBackPressed()
เมธอดและเพิ่มตรรกะนี้เข้ากับ:
@Override
public void onBackPressed() {
// Get the current fragment using the method from the second step above...
Fragment currentFragment = NavUtils.getCurrentFragment(this);
// Determine whether or not this fragment implements Backable
// Do a null check just to be safe
if (currentFragment != null && currentFragment instanceof Backable) {
if (((Backable) currentFragment).onBackPressed()) {
// If the onBackPressed override in your fragment
// did absorb the back event (returned true), return
return;
} else {
// Otherwise, call the super method for the default behavior
super.onBackPressed();
}
}
// Any other logic needed...
// call super method to be sure the back button does its thing...
super.onBackPressed();
}
เราได้รับส่วนปัจจุบันในกองหลังแล้วเราทำการตรวจสอบเป็นโมฆะและตรวจสอบว่ามันใช้Backable
อินเตอร์เฟซของเรา ถ้าเป็นเช่นนั้นตรวจสอบว่าเหตุการณ์ถูกดูดซับ ถ้าเป็นเช่นนั้นเราจะทำกับonBackPressed()
และสามารถส่งคืนได้ มิฉะนั้นถือว่าเป็นกดย้อนกลับตามปกติและเรียกใช้วิธีการ super
ตัวเลือกที่สองที่ไม่เกี่ยวข้องกับกิจกรรม
บางครั้งคุณไม่ต้องการให้กิจกรรมจัดการกับสิ่งนี้เลยและคุณต้องจัดการกับมันโดยตรงภายในส่วน แต่ใครบอกว่าคุณทำไม่ได้มี Fragments ด้วย back press API ได้ แค่ขยายแฟรกเมนต์ของคุณไปยังคลาสใหม่
สร้างคลาสนามธรรมที่ขยายส่วนและใช้View.OnKeyListner
อินเทอร์เฟซ ...
import android.app.Fragment;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
public abstract class BackableFragment extends Fragment implements View.OnKeyListener {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.setFocusableInTouchMode(true);
view.requestFocus();
view.setOnKeyListener(this);
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
onBackButtonPressed();
return true;
}
}
return false;
}
public abstract void onBackButtonPressed();
}
อย่างที่คุณเห็นส่วนใด ๆ ที่ขยายBackableFragment
จะจับการคลิกกลับโดยอัตโนมัติโดยใช้View.OnKeyListener
อินเทอร์เฟซ เพียงแค่เรียกonBackButtonPressed()
วิธีนามธรรมจากภายในonKey()
วิธีการใช้งานโดยใช้ตรรกะมาตรฐานในการมองเห็นการกดปุ่มย้อนกลับ หากคุณต้องการลงทะเบียนการคลิกที่สำคัญอื่น ๆ นอกเหนือจากปุ่มย้อนกลับเพียงแค่ให้แน่ใจว่าได้เรียกsuper
วิธีการเมื่อเอาชนะonKey()
ในส่วนของคุณมิฉะนั้นคุณจะแทนที่พฤติกรรมในสิ่งที่เป็นนามธรรม
ใช้งานง่ายเพียงขยายและใช้งาน:
public class FragmentChannels extends BackableFragment {
...
@Override
public void onBackButtonPressed() {
if (doTheThingRequiringBackButtonOverride) {
// do the thing
} else {
getActivity().onBackPressed();
}
}
...
}
ตั้งแต่วิธีการในชั้นซุปเปอร์เป็นนามธรรมเมื่อคุณขยายคุณต้องใช้onBackButtonPressed()
onBackButtonPressed()
มันกลับมาvoid
เพราะมันเพียงแค่ต้องดำเนินการภายในชั้นชิ้นส่วนและไม่จำเป็นต้องถ่ายทอดการดูดซึมของสื่อกลับไปที่กิจกรรม ตรวจสอบให้แน่ใจว่าคุณโทรonBackPressed()
วิธีการกิจกรรมหากสิ่งที่คุณทำกับปุ่มย้อนกลับไม่ต้องการการจัดการมิฉะนั้นปุ่มย้อนกลับจะถูกปิดการใช้งาน ... และคุณไม่ต้องการที่!
Caveats อย่างที่คุณเห็นนี่เป็นการกำหนดให้ผู้ฟังหลักเป็นมุมมองรูทของแฟรกเมนต์และเราจะต้องโฟกัสมัน หากมีการแก้ไขข้อความที่เกี่ยวข้อง (หรือมุมมองการขโมยโฟกัสอื่น ๆ ) ในส่วนของคุณที่ขยายคลาสนี้ (หรือชิ้นส่วนภายในหรือมุมมองอื่น ๆ ที่มีเหมือนกัน) คุณจะต้องจัดการแยกต่างหาก มีบทความที่ดีเกี่ยวกับการขยาย EditTextเพื่อไม่ให้ความสำคัญกับ back press
ฉันหวังว่าบางคนพบว่ามีประโยชน์นี้ การเข้ารหัสที่มีความสุข
super.onBackPressed();
สองครั้ง?
currentFragment
มันเรียกว่าเพียงหนึ่งครั้งต่อสถานการณ์ที่เกี่ยวกับสถานะของ null หากแฟรกเมนต์ไม่เป็นโมฆะและแฟรกเมนต์ใช้Backable
อินเตอร์เฟสจะไม่มีการดำเนินการใด ๆ หากแฟรกเมนต์ไม่เป็นโมฆะและไม่ได้ใช้งานBackable
เราจะเรียกเมธอด super หากแฟรกเมนต์เป็นโมฆะมันจะข้ามไปยังการโทรซูเปอร์ครั้งสุดท้าย
currentFragment
ไม่เป็นโมฆะและเป็นอินสแตนซ์ของ Backable และถูกถอดออก (เรากดback
ปุ่มและปิดแฟรกเมนต์) การเกิดขึ้นครั้งแรกของsuper.onBackPressed();
ถูกเรียกแล้วที่สอง
การแก้ปัญหาง่ายมาก:
1) ถ้าคุณมีคลาสแฟรกเมนต์พื้นฐานที่แฟรกเมนต์ทั้งหมดขยายให้เพิ่มโค้ดนี้ในคลาสของมันมิฉะนั้นสร้างคลาสแฟรกเมนต์พื้นฐานดังกล่าว
/*
* called when on back pressed to the current fragment that is returned
*/
public void onBackPressed()
{
// add code in super class when override
}
2) ในคลาสกิจกรรมของคุณให้แทนที่ onBackPressed ดังนี้:
private BaseFragment _currentFragment;
@Override
public void onBackPressed()
{
super.onBackPressed();
_currentFragment.onBackPressed();
}
3) ในชั้น Fragment ของคุณเพิ่มรหัสที่คุณต้องการ:
@Override
public void onBackPressed()
{
setUpTitle();
}
onBackPressed()
ทำให้แฟรกเมนต์แยกออกจากกิจกรรม
@Sterling Diaz ตอบว่าฉันคิดว่าเขาพูดถูก แต่สถานการณ์บางอย่างจะผิด (เช่นหน้าจอหมุน)
ดังนั้นฉันคิดว่าเราสามารถตรวจสอบได้ว่า isRemoving()
จะบรรลุเป้าหมายหรือไม่
คุณสามารถเขียนได้ที่หรือonDetach()
onDestroyView()
มันเป็นงาน
@Override
public void onDetach() {
super.onDetach();
if(isRemoving()){
// onBackPressed()
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if(isRemoving()){
// onBackPressed()
}
}
ฉันทำอย่างนี้แล้วมันก็ใช้ได้ผลสำหรับฉัน
อินเตอร์เฟซที่เรียบง่าย
FragmentOnBackClickInterface.java
public interface FragmentOnBackClickInterface {
void onClick();
}
ตัวอย่างการนำไปใช้
MyFragment.java
public class MyFragment extends Fragment implements FragmentOnBackClickInterface {
// other stuff
public void onClick() {
// what you want to call onBackPressed?
}
จากนั้นเพียงแค่แทนที่ onBackPressed ในกิจกรรม
@Override
public void onBackPressed() {
int count = getSupportFragmentManager().getBackStackEntryCount();
List<Fragment> frags = getSupportFragmentManager().getFragments();
Fragment lastFrag = getLastNotNull(frags);
//nothing else in back stack || nothing in back stack is instance of our interface
if (count == 0 || !(lastFrag instanceof FragmentOnBackClickInterface)) {
super.onBackPressed();
} else {
((FragmentOnBackClickInterface) lastFrag).onClick();
}
}
private Fragment getLastNotNull(List<Fragment> list){
for (int i= list.size()-1;i>=0;i--){
Fragment frag = list.get(i);
if (frag != null){
return frag;
}
}
return null;
}
คุณควรเพิ่มส่วนต่อประสานกับโปรเจคของคุณดังนี้
public interface OnBackPressed {
void onBackPressed();
}
จากนั้นคุณควรใช้อินเทอร์เฟซนี้กับส่วนของคุณ
public class SampleFragment extends Fragment implements OnBackPressed {
@Override
public void onBackPressed() {
//on Back Pressed
}
}
และคุณสามารถทริกเกอร์เหตุการณ์ onBackPressed นี้ภายใต้กิจกรรมของคุณในกิจกรรม BackBackPressed ด้านล่าง;
public class MainActivity extends AppCompatActivity {
@Override
public void onBackPressed() {
Fragment currentFragment = getSupportFragmentManager().getFragments().get(getSupportFragmentManager().getBackStackEntryCount() - 1);
if (currentFragment instanceof OnBackPressed) {
((OnBackPressed) currentFragment).onBackPressed();
}
super.onBackPressed();
}
}
getActivity().onBackPressed();
ตามที่มันจะเรียกใช้ข้อยกเว้น: "java.lang.StackOverflowError: ขนาดสแต็ก 8MB"
นี่เป็นเพียงรหัสเล็ก ๆ ที่จะทำเคล็ดลับ:
getActivity().onBackPressed();
หวังว่าจะช่วยให้ใครบางคน :)
หากคุณใช้ EventBus อาจเป็นวิธีที่ง่ายกว่า:
ในส่วนของคุณ:
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
EventBus.getDefault().register(this);
}
@Override
public void onDetach() {
super.onDetach();
EventBus.getDefault().unregister(this);
}
// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
getSupportFragmentManager().popBackStack();
}
และในชั้นเรียนกิจกรรมของคุณคุณสามารถกำหนด:
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
super.onBackPressed();
}
@Override
public void onBackPressed() {
EventBus.getDefault().post(new BackPressedMessage(true));
}
BackPressedMessage.java เป็นเพียงวัตถุ POJO
นี่สะอาดมากและไม่มีปัญหาเรื่องอินเตอร์เฟส / การติดตั้งใช้งาน
นี่คือทางออกของฉัน:
ในMyActivity.java:
public interface OnBackClickListener {
boolean onBackClick();
}
private OnBackClickListener onBackClickListener;
public void setOnBackClickListener(OnBackClickListener onBackClickListener) {
this.onBackClickListener = onBackClickListener;
}
@Override
public void onBackPressed() {
if (onBackClickListener != null && onBackClickListener.onBackClick()) {
return;
}
super.onBackPressed();
}
และในส่วน:
((MyActivity) getActivity()).setOnBackClickListener(new MyActivity.OnBackClickListener() {
@Override
public boolean onBackClick() {
if (condition) {
return false;
}
// some codes
return true;
}
});
การใช้องค์ประกอบการนำทางคุณสามารถทำสิ่งนี้ได้ :
ชวา
public class MyFragment extends Fragment {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// This callback will only be called when MyFragment is at least Started.
OnBackPressedCallback callback = new OnBackPressedCallback(true /* enabled by default */) {
@Override
public void handleOnBackPressed() {
// Handle the back button event
}
});
requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
// The callback can be enabled or disabled here or in handleOnBackPressed()
}
...
}
Kotlin
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// This callback will only be called when MyFragment is at least Started.
val callback = requireActivity().onBackPressedDispatcher.addCallback(this) {
// Handle the back button event
}
// The callback can be enabled or disabled here or in the lambda
}
...
}
วิธีการเกี่ยวกับการใช้ onDestroyView ()?
@Override
public void onDestroyView() {
super.onDestroyView();
}
i = i
if (1 < 0) {}
@Override
public void onResume() {
super.onResume();
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
// handle back button
replaceFragmentToBackStack(getActivity(), WelcomeFragment.newInstance(bundle), tags);
return true;
}
return false;
}
});
}
public class MyActivity extends Activity {
protected OnBackPressedListener onBackPressedListener;
public interface OnBackPressedListener {
void doBack();
}
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
@Override
public void onBackPressed() {
if (onBackPressedListener != null)
onBackPressedListener.doBack();
else
super.onBackPressed();
}
@Override
protected void onDestroy() {
onBackPressedListener = null;
super.onDestroy();
}
}
ในส่วนของคุณเพิ่มสิ่งต่อไปนี้อย่าลืมใช้อินเทอร์เฟซของ mainactivity
public class MyFragment extends Framgent implements MyActivity.OnBackPressedListener {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
((MyActivity) getActivity()).setOnBackPressedListener(this);
}
@Override
public void doBack() {
//BackPressed in activity will call this;
}
}
ในโซลูชันของฉัน (Kotlin);
ฉันใช้ฟังก์ชั่น onBackAlternative เป็นพารามิเตอร์ในBaseActivity BaseActivity
BaseActivity
abstract class BaseActivity {
var onBackPressAlternative: (() -> Unit)? = null
override fun onBackPressed() {
if (onBackPressAlternative != null) {
onBackPressAlternative!!()
} else {
super.onBackPressed()
}
}
}
ฉันมีฟังก์ชั่นสำหรับชุดonBackPressAlternativeบนBaseFragment BaseFragment
BaseFragment
abstract class BaseFragment {
override fun onStart() {
super.onStart()
...
setOnBackPressed(null) // Add this
}
//Method must be declared as open, for overriding in child class
open fun setOnBackPressed(onBackAlternative: (() -> Unit)?) {
(activity as BaseActivity<*, *>).onBackPressAlternative = onBackAlternative
}
}
จากนั้นในช่องของฉันกดอัลเทอร์เนทีฟพร้อมใช้งานบนแฟรกเมนต์
ชิ้นส่วนย่อย
override fun setOnBackPressed(onBackAlternative: (() -> Unit)?) {
(activity as BaseActivity<*, *>).onBackPressAlternative = {
// TODO Your own custom onback function
}
}
อย่าใช้วิธี ft.addToBackStack () เพื่อที่เมื่อคุณกดปุ่มย้อนกลับกิจกรรมของคุณจะเสร็จสิ้น
proAddAccount = new ProfileAddAccount();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, proAddAccount);
//fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
เพียงทำตามขั้นตอนเหล่านี้:
เสมอในขณะที่เพิ่มส่วน
fragmentTransaction.add(R.id.fragment_container, detail_fragment, "Fragment_tag").addToBackStack(null).commit();
จากนั้นในกิจกรรมหลักให้แทนที่ onBackPressed()
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
} else {
finish();
}
ในการจัดการปุ่มย้อนกลับในแอปของคุณ
Fragment f = getActivity().getSupportFragmentManager().findFragmentByTag("Fragment_tag");
if (f instanceof FragmentName) {
if (f != null)
getActivity().getSupportFragmentManager().beginTransaction().remove(f).commit()
}
แค่นั้นแหละ!
ในวงจรชีวิตของกิจกรรมหุ่นยนต์ปุ่มย้อนกลับเกี่ยวข้องกับธุรกรรม FragmentManager เสมอเมื่อเราใช้ FragmentActivity หรือ AppCompatActivity
เพื่อจัดการ backstack เราไม่จำเป็นต้องจัดการ backstack หรือติดแท็กอะไร แต่เราควรให้ความสำคัญในขณะที่เพิ่มหรือเปลี่ยนชิ้นส่วน โปรดค้นหาตัวอย่างต่อไปนี้เพื่อจัดการกรณีปุ่มย้อนกลับ
public void replaceFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (!(fragment instanceof HomeFragment)) {
transaction.addToBackStack(null);
}
transaction.replace(R.id.activity_menu_fragment_container, fragment).commit();
}
ที่นี่ฉันจะไม่เพิ่มสแต็กกลับสำหรับส่วนย่อยในบ้านของฉันเพราะเป็นหน้าแรกของใบสมัครของฉัน หากเพิ่ม addToBackStack ไปที่ HomeFragment แล้วแอพจะรอลบ frament ทั้งหมดในความเป็นกรดแล้วเราจะได้หน้าจอว่างเปล่าดังนั้นฉันจะรักษาตามเงื่อนไขต่อไปนี้
if (!(fragment instanceof HomeFragment)) {
transaction.addToBackStack(null);
}
ตอนนี้คุณสามารถดูส่วนที่เพิ่มก่อนหน้านี้ใน acitvity และแอพจะออกเมื่อไปถึง HomeFragment คุณยังสามารถดูตัวอย่างต่อไปนี้
@Override
public void onBackPressed() {
if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
closeDrawer();
} else {
super.onBackPressed();
}
}
Fragment: สร้าง BaseFragment โดยวางเมธอด:
public boolean onBackPressed();
กิจกรรม:
@Override
public void onBackPressed() {
List<Fragment> fragments = getSupportFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
if (!fragment.isVisible()) continue;
if (fragment instanceof BaseFragment && ((BaseFragment) fragment).onBackPressed()) {
return;
}
}
}
super.onBackPressed();
}
กิจกรรมของคุณจะดำเนินการผ่านส่วนที่แนบมาและมองเห็นได้และโทรonBackPressed ()ในแต่ละรายการและยกเลิกหากหนึ่งในนั้นส่งคืน 'จริง' (หมายถึงมีการจัดการดังนั้นจึงไม่มีการดำเนินการเพิ่มเติม)
ตามที่บันทึกประจำรุ่น AndroidX , androidx.activity 1.0.0-alpha01
ถูกปล่อยออกมาและเปิดตัวComponentActivity
เป็นชั้นฐานใหม่ของที่มีอยู่และFragmentActivity
AppCompatActivity
และการเปิดตัวครั้งนี้ทำให้เรามีคุณสมบัติใหม่:
ตอนนี้คุณสามารถลงทะเบียนOnBackPressedCallback
ผ่านaddOnBackPressedCallback
เพื่อรับการonBackPressed()
เรียกกลับโดยไม่จำเป็นต้องแทนที่วิธีการในกิจกรรมของคุณ
คุณสามารถลงทะเบียนชิ้นส่วนในกิจกรรมเพื่อจัดการกดกลับ:
interface BackPressRegistrar {
fun registerHandler(handler: BackPressHandler)
fun unregisterHandler(handler: BackPressHandler)
}
interface BackPressHandler {
fun onBackPressed(): Boolean
}
การใช้งาน:
private val backPressHandler = object : BackPressHandler {
override fun onBackPressed(): Boolean {
showClosingWarning()
return false
}
}
override fun onResume() {
super.onResume()
(activity as? BackPressRegistrar)?.registerHandler(backPressHandler)
}
override fun onStop() {
(activity as? BackPressRegistrar)?.unregisterHandler(backPressHandler)
super.onStop()
}
class MainActivity : AppCompatActivity(), BackPressRegistrar {
private var registeredHandler: BackPressHandler? = null
override fun registerHandler(handler: BackPressHandler) { registeredHandler = handler }
override fun unregisterHandler(handler: BackPressHandler) { registeredHandler = null }
override fun onBackPressed() {
if (registeredHandler?.onBackPressed() != false) super.onBackPressed()
}
}
การจัดเตรียมการนำทางด้านหลังที่กำหนดเองโดยการจัดการกับ BackPressed ทำให้ตอนนี้ง่ายขึ้นด้วยการเรียกกลับภายในส่วน
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val onBackPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (true == conditionForCustomAction) {
myCustomActionHere()
} else NavHostFragment.findNavController(this@MyFragment).navigateUp();
}
}
requireActivity().onBackPressedDispatcher.addCallback(
this, onBackPressedCallback
)
...
}
หากคุณต้องการให้การกระทำย้อนกลับเริ่มต้นขึ้นอยู่กับเงื่อนไขบางประการคุณสามารถใช้:
NavHostFragment.findNavController(this@MyFragment).navigateUp();
ภายในเมธอด onCreate ของแฟรกเมนต์เพิ่มสิ่งต่อไปนี้:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OnBackPressedCallback callback = new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
//Handle the back pressed
}
};
requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
}
ทางออกที่ดีที่สุด
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
public class BaseActivity extends AppCompatActivity {
@Override
public void onBackPressed() {
FragmentManager fm = getSupportFragmentManager();
for (Fragment frag : fm.getFragments()) {
if (frag == null) {
super.onBackPressed();
finish();
return;
}
if (frag.isVisible()) {
FragmentManager childFm = frag.getChildFragmentManager();
if (childFm.getFragments() == null) {
super.onBackPressed();
finish();
return;
}
if (childFm.getBackStackEntryCount() > 0) {
childFm.popBackStack();
return;
}
else {
fm.popBackStack();
if (fm.getFragments().size() <= 1) {
finish();
}
return;
}
}
}
}
}