使用片段清除堆栈

时间:2011-05-31 10:49:01

标签: android android-fragments

我将我的Android应用程序移植到了蜂窝状态,然后为了使用碎片我做了一个大的重构。在我之前的版本中,当我按下Home按钮时,我曾经做过ACTIVITY_CLEAR_TOP以重置后台堆栈。

现在我的应用程序只是一个包含多个片段的Activity,因此当我按下Home按钮时,我只需替换其中的一个片段。如何清除我的后台堆栈而不必使用带有startActivity标志的ACTIVITY_CLEAR_TOP

15 个答案:

答案 0 :(得分:385)

I posted something similar here

来自约阿希姆的回答,来自Dianne Hackborn:

http://groups.google.com/group/android-developers/browse_thread/thread/d2a5c203dad6ec42

我最终只是使用:

FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {    
    fm.popBackStack();
}

但同样可以使用类似的东西:

FragmentManager.popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE)

将弹出所有状态到指定状态。然后,您可以将片段替换为您想要的

答案 1 :(得分:141)

为@Warpzit的评论做出回答,让其他人更容易找到。

使用:

fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

答案 2 :(得分:37)

充分尊重所有相关方;我很惊讶地看到有多少人可以通过简单的

清除整个片段

fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

根据Android documentation(关于name论证 - &#34; null&#34;在声明的工作提案中)。

  

如果为null,则仅弹出顶部状态

现在,我确实意识到我对您的特定实现缺乏了解(比如您在给定时间点在后台堆叠中有多少条目),但我会把所有资金都押在接受的答案上当期望在更广泛的设备和供应商上有明确定义的行为时:

(供参考,与此一致)

FragmentManager fm = getFragmentManager(); // or 'getSupportFragmentManager();'
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {    
    fm.popBackStack();
}

答案 3 :(得分:17)

对我来说,接受的答案是不够的。我不得不使用:

FragmentManager fm = getSupportFragmentManager();
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {
    fm.popBackStackImmediate();
}

答案 4 :(得分:16)

无需使用循环即可轻松实现:

 FragmentManager fragmentManager = getSupportFragmentManager();
 //this will clear the back stack and displays no animation on the screen
 fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

答案 5 :(得分:14)

清除没有循环的backstack

String name = getSupportFragmentManager().getBackStackEntryAt(0).getName();
getSupportFragmentManager().popBackStack(name, FragmentManager.POP_BACK_STACK_INCLUSIVE);

其中 name 是addToBackStack()参数

getSupportFragmentManager().beginTransaction().
                .replace(R.id.container, fragments.get(titleCode))
                .addToBackStack(name)

答案 6 :(得分:8)

我只想补充一点: -

使用以下

从后台弹出
  

fragmentManager.popBackStack()

只是从事务中删除片段,它不会从屏幕上删除片段。 理想情况下,它可能不会被您看到,但可能会有两个或三个碎片堆叠在一起,并且在按键背面按下UI可能看起来混乱,堆叠。

举一个简单的例子: -

假设您有一个fragmentA,它使用 fragmentmanager.replace()加载Fragmnet B,然后我们执行addToBackStack来保存此事务。 所以流程是: -

步骤1 - &gt; FragmentA-&gt; FragmentB(我们移动到FragmentB,但片段A在背景中,不可见)。

现在你在fragmentB中做了一些工作并按下Save按钮 - 保存后应该返回到fragmentA。

步骤2->在保存FragmentB后,我们回到FragmentA。

第3步 - &gt;所以常见的错误是...在片段B中,我们将使用fragmentA片段管理Manager.replace()fragmentB。

但实际上发生了什么,我们再次加载Fragment A,取代FragmentB。所以现在有两个FragmentA(一个来自STEP-1,一个来自这个STEP-3)。

FragmentsA的两个实例相互堆叠,可能看不见,但它就在那里。

因此,即使我们通过上述方法清除了backstack,事务也会被清除,但不会清除实际的片段。 理想情况下,在这种特殊情况下,按下保存按钮,您只需要通过简单地执行 fm.popBackStack() fm.popBackImmediate()返回到fragmentA。

如此正确的Step3-&gt; fm.popBackStack()返回到已经在内存中的fragmentA。

答案 7 :(得分:3)

阅读documentation并研究片段ID是什么,它似乎只是堆栈索引,所以这有效:

0

零(while(fragmentManager.getBackStackEntryCount() > 0) { fragmentManager.popBackStackImmediate(); } )是堆栈的底部,因此弹出它可以清除堆栈。

CAVEAT:虽然以上工作在我的程序中,但我有点犹豫,因为FragmentManager文档实际上从未说明id是堆栈索引。它是有意义的,并且我的所有调试日志都没有,但是在某些特殊情况下它可能不会?任何人都能确认这种方式吗?如果是,则上述是最佳解决方案。如果没有,这是替代方案:

    <?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center_horizontal"
    android:id="@+id/fillable_area">

    <TableLayout
        android:id="@+id/table_header"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"/>
    <ScrollView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">

        <LinearLayout android:orientation="horizontal"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:gravity="center_horizontal"
            >


             <HorizontalScrollView
               android:id="@+id/scroller"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content">

                <TableLayout
                    android:id="@+id/scrollable_part"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"/>

            </HorizontalScrollView>


        </LinearLayout>
    </ScrollView>

</LinearLayout>



    package com.example.freez_t00;

import java.util.ArrayList;

import android.R.layout;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.HorizontalScrollView;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Gravity;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TableRow.LayoutParams;
import android.widget.TextView;

public class MainActivity extends Activity {
    private boolean showSummaries;

    private TableLayout summaryTable;
    private TableLayout frozenTable;
    private TableLayout contentTable;
    private Button backButton ;
    private HorizontalScrollView hor;
    private TextView recyclableTextView;




    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

           setContentView(R.layout.activity_main);






           TableRow.LayoutParams wrapWrapTableRowParams = new TableRow.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            int[] fixedColumnWidths = new int[]{20, 20,20, 20, 20};
            int[] scrollableColumnWidths = new int[]{20, 20, 20, 30, 30};
            int fixedRowHeight = 50;
            int fixedHeaderHeight = 60;
            TableRow row = new TableRow(this);
            //header (fixed vertically)
            TableLayout header=(TableLayout)findViewById(R.id.table_header);

            row.setLayoutParams(wrapWrapTableRowParams);
            row.setGravity(Gravity.CENTER);
            row.setBackgroundColor(Color.YELLOW);
            row.addView(makeTableRowWithText("col1", fixedColumnWidths[0],fixedHeaderHeight));
            row.addView(makeTableRowWithText("col2", fixedColumnWidths[1],fixedHeaderHeight));
            row.addView(makeTableRowWithText("col3", fixedColumnWidths[2],fixedHeaderHeight));
            row.addView(makeTableRowWithText("col4", fixedColumnWidths[3],fixedHeaderHeight));
            row.addView(makeTableRowWithText("col5", fixedColumnWidths[4],fixedHeaderHeight));

            header.addView(row);


            hor = (HorizontalScrollView)findViewById(R.id.scroller);
            hor.postDelayed(new Runnable(){
                public void run() {
                    hor.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
                }
            }, 1L);

          //  TableLayout fixedColumn = (TableLayout) findViewById(R.id.fixed_column);
            //rest of the table (within a scroll view)
            TableLayout scrollablePart = (TableLayout)findViewById(R.id.scrollable_part);
            for(int i = 0; i < 10; i++) {
                   row = new TableRow(this);
                   row.setLayoutParams(wrapWrapTableRowParams);
                   row.setGravity(Gravity.CENTER);
                   row.setBackgroundColor(Color.WHITE);
                   row.addView(makeTableRowWithText("value 1", scrollableColumnWidths[1], fixedRowHeight));
                   row.addView(makeTableRowWithText("value 2", scrollableColumnWidths[1], fixedRowHeight));
                   row.addView(makeTableRowWithText("value 3", scrollableColumnWidths[2], fixedRowHeight));
                   row.addView(makeTableRowWithText("value 4", scrollableColumnWidths[3], fixedRowHeight));
                   row.addView(makeTableRowWithText("value 5", scrollableColumnWidths[4], fixedRowHeight));
                   scrollablePart.addView(row);
            }








    }




     public TextView makeTableRowWithText(String text, int widthInPercentOfScreenWidth, int fixedHeightInPixels) {
            int screenWidth = getResources().getDisplayMetrics().widthPixels;
            recyclableTextView = new TextView(this);
            recyclableTextView.setText(text);
            recyclableTextView.setTextColor(Color.BLACK);
            recyclableTextView.setTextSize(20);
            recyclableTextView.setWidth(widthInPercentOfScreenWidth * screenWidth / 100);
            recyclableTextView.setHeight(fixedHeightInPixels);
            return recyclableTextView;
        }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

答案 8 :(得分:2)

  

只需使用此方法并传递Context&amp;片段标记我们需要删除后退片段。

<强>用法

clearFragmentByTag(context, FragmentName.class.getName());



public static void clearFragmentByTag(Context context, String tag) {
    try {
        FragmentManager fm = ((AppCompatActivity) context).getSupportFragmentManager();

        for (int i = fm.getBackStackEntryCount() - 1; i >= 0; i--) {
            String backEntry = fm.getBackStackEntryAt(i).getName();
            if (backEntry.equals(tag)) {
                break;
            } else {
                 fm.popBackStack();
            }
        }
    } catch (Exception e) {
        System.out.print("!====Popbackstack error : " + e);
        e.printStackTrace();
    }
}

答案 9 :(得分:1)

我这样做了:

public void showHome() {
    getHandler().post(new Runnable() {
        @Override
        public void run() {
            final FragmentManager fm = getSupportFragmentManager();
            while (fm.getBackStackEntryCount() > 0) {
                fm.popBackStackImmediate();
            }
        }
    });
}

答案 10 :(得分:1)

它对我有用,请尝试以下操作:

public void clearFragmentBackStack() {
        FragmentManager fm = getSupportFragmentManager();
        for (int i = 0; i < fm.getBackStackEntryCount() - 1; i++) {
            fm.popBackStack();
        }
    }

答案 11 :(得分:0)

    private void clearBackStack(){
        SupportFragmentManaer fm = getSupportFragmentManager();
        fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

调用此方法会非常整洁。

  1. 不需要循环。
  2. 如果您在片段中使用动画,则不会显示太多动画。但是使用循环会。

答案 12 :(得分:0)

private boolean removeFragFromBackStack() {
    try {
        FragmentManager manager = getSupportFragmentManager();
        List<Fragment> fragsList = manager.getFragments();
        if (fragsList.size() == 0) {
            return true;
        }
        manager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}

答案 13 :(得分:0)

嗨,我发现了一个更好的解决方案,来自:https://gist.github.com/ikew0ng/8297033

    /**
 * Remove all entries from the backStack of this fragmentManager.
 *
 * @param fragmentManager the fragmentManager to clear.
 */
private void clearBackStack(FragmentManager fragmentManager) {
    if (fragmentManager.getBackStackEntryCount() > 0) {
        FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(0);
        fragmentManager.popBackStack(entry.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }
}

答案 14 :(得分:0)

对于这里的 kotlin 人:

repeat(supportFragmentManager.backStackEntryCount) {
    supportFragmentManager.popBackStack()
}