【问题标题】:Fragment is in backstack片段在后台
【发布时间】:2016-05-13 12:56:46
【问题描述】:

在我的应用程序中,我的第一个 Fragment 在 BackStack 中,并且在交易时该片段未添加到 backstack。

编辑。

我在第一次横断后多次使用相同的片段,但 横切后跟第一个被添加到backstack addToBackStack(TAG); 但我从未将第一个片段添加到后台堆栈 但我仍然不明白为什么我必须点击两次才能发送应用程序 到背景。

这是它的代码

FragmentManager fm = getSupportFragmentManager();
Bundle args = new Bundle();
args.putString("url", Constants.URL_BASE);
feedFragment.setArguments(args);
fm.beginTransaction().replace(R.id.content_frame, feedFragment).commit();

现在,当我按下返回按钮时,它会删除片段,但应用程序不会进入后台。当我第二次按下返回按钮时它会进入后台。

replace() 本身是否将片段添加到后台堆栈?如果是,那么我怎样才能删除片段并使我的应用程序转到后台onBackPressed? 如果它没有将片段添加到后台堆栈,那么为什么会发生这种情况?我应该如何使它正常工作?

谢谢!

编辑:

这里是完整的活动代码。

public class MainActivity extends AppCompatActivity {
    private final String TAG = getClass().getName();
    private DrawerLayout drawerLayout;
    private FeedFragment feedFragment = new FeedFragment();
    private ListView listView;
    private LinearLayout searchLayout;
    private RelativeLayout logolayout;
    private Toolbar toolbar;
    private Button settingBtn;
    private Button bookmarkBtn;
    private Button searchBtn;
    private Tracker mTracker;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ApplicationController applicationController = (ApplicationController) getApplication();
        mTracker = applicationController.getDefault();
        initToolbar();
        initUi();
        loadCategorgies();
        initFeed();
    }

    public void initUi() {
        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        listView = (ListView) findViewById(R.id.lv_categories);
        settingBtn = (Button) findViewById(R.id.btn_settings);
        bookmarkBtn = (Button) findViewById(R.id.btn_bookmarks);
        searchBtn = (Button) findViewById(R.id.btn_search);


        settingBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                FragmentManager fragmentManager = getSupportFragmentManager();
                fragmentManager.beginTransaction().replace(R.id.content_frame, new SettingFragment()).addToBackStack("setting").commit();
                drawerLayout.closeDrawers();
            }
        });

        bookmarkBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                FragmentManager fragmentManager = getSupportFragmentManager();
                fragmentManager.beginTransaction().replace(R.id.content_frame, new BookmarkFragment()).addToBackStack("bookmark").commit();
                drawerLayout.closeDrawers();
            }
        });

        searchBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                FragmentManager fragmentManager = getSupportFragmentManager();
                fragmentManager.beginTransaction().replace(R.id.content_frame, new SearchFragment()).addToBackStack("search").commit();
                drawerLayout.closeDrawers();
            }
        });
    }

    public void initToolbar() {
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_action_menu_inactive);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }

    public void hideLogo() {
        ImageView imageView = (ImageView) toolbar.findViewById(R.id.logo);
        imageView.setVisibility(View.GONE);
    }

    public void showLogo() {
        ImageView imageView = (ImageView) toolbar.findViewById(R.id.logo);
        imageView.setVisibility(View.VISIBLE);
    }

    public void loadCategorgies() {
        StringRequest stringRequest = new StringRequest(Constants.URL_GET_CATEGORIES, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                if (Constants.isDev)
                    Log.d(TAG, response);
                final CategoriesDTO categoriesDTO = Constants.gson.fromJson(response, CategoriesDTO.class);
                CatgoriesAdapter catgoriesAdapter = new CatgoriesAdapter(categoriesDTO, MainActivity.this);
                listView.setAdapter(catgoriesAdapter);
                listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                        if (Constants.isDev)
                            Log.d(TAG, "clicked" + categoriesDTO.getCategories().get(position).getTitle());
                        FeedFragment feedFragment = new FeedFragment();
                        FragmentManager fm = getSupportFragmentManager();
                        Bundle args = new Bundle();
                        args.putString("url", Constants.URL_BASE_CATEGORY + categoriesDTO.getCategories().get(position).getSlug());
                        feedFragment.setArguments(args);
                        fm.beginTransaction().replace(R.id.content_frame, feedFragment).addToBackStack(categoriesDTO.getCategories().get(position).getSlug()).commit();
                        drawerLayout.closeDrawers();
                    }
                });
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {

            }
        });
        ApplicationController.getmInstance().addToRequestQueue(stringRequest);
    }

    public void initFeed() {
        FragmentManager fm = getSupportFragmentManager();
        Bundle args = new Bundle();
        args.putString("url", Constants.URL_BASE);
        feedFragment.setArguments(args);
        fm.beginTransaction().replace(R.id.content_frame, feedFragment).commit();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        switch (id) {
            case android.R.id.home:
                drawerLayout.openDrawer(GravityCompat.START);
                return true;
        }
        return super.onOptionsItemSelected(item);

    }

    @Override
    protected void onResume() {
        super.onResume();
        if (Constants.isDev)
            Log.i(TAG, "Setting screen name: " + TAG);
        mTracker.setScreenName("Image~" + TAG);
        mTracker.send(new HitBuilders.ScreenViewBuilder().build());
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        //moveTaskToBack(true);
    }
}

编辑

mcve

这是 HomeActivity。

public class HomeActivity extends AppCompatActivity {
    private final String TAG = getClass().getName();
    private DrawerLayout drawerLayout;
    private FragmentManager fragmentManager;
    private FeedFragment feedFragment = new FeedFragment();
    private Toolbar toolbar;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.home_activity);
        fragmentManager = getSupportFragmentManager();
        initToolbar();
        initFeed();
    }
    public void initToolbar() {
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_action_menu_inactive);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }
public void initUi() {
        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
}
    public void initFeed() {

        Bundle args = new Bundle();
        args.putString("url", Constants.URL_BASE);
        feedFragment.setArguments(args);
        fragmentManager.beginTransaction().replace(R.id.content_frame, feedFragment).commit();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        switch (id) {
            case android.R.id.home:
                drawerLayout.openDrawer(GravityCompat.START);
                return true;
        }
        return super.onOptionsItemSelected(item);

    }

    @Override
    protected void onResume() {
        super.onResume();
        if (Constants.isDev)
            Log.i(TAG, "Setting screen name: " + TAG);
        mTracker.setScreenName("Image~" + TAG);
        mTracker.send(new HitBuilders.ScreenViewBuilder().build());
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
    }
}

这是片段。

public class FeedFragment extends Fragment {
private final String TAG = getClass().getName();
private View view;

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    view = inflater.inflate(R.layout.feed_fragment, container, false);
    return view;
}

【问题讨论】:

  • 请解释一下这会做什么?
  • 你能给我们更多的代码吗?你是怎么做 onBackPressed() 方法的,你有没有在后台共享相同容器视图的任何其他片段?
  • @Seishin 是的,我确实有同一个容器的其他片段。但是此时只有这个片段被横切并且没有添加到你可以在上面的代码中看到的backstack。
  • 您所要求的应该是基于您的描述的默认行为。 replace() 不会将 Fragment 添加到后台堆栈,除非事务包含 addToBackStack()。如果您发布完整的 Activity 代码以查看您在其他地方对片段执行的其他操作或发现可能导致问题的其他代码,这将有所帮助。
  • @GeorgeMulligan 我添加了完整的活动代码。请检查已编辑的问题。

标签: android android-fragments


【解决方案1】:

此代码很好,当您开始活动时,您不会将其放在后台堆栈中。

FragmentManager fm = getSupportFragmentManager();
Bundle args = new Bundle();
args.putString("url", Constants.URL_BASE);
feedFragment.setArguments(args);
fm.beginTransaction().replace(R.id.content_frame, feedFragment).commit();

但是在 initUI() 之后,您调用 loadcategories() 方法,将提要片段放入 backstack。所以这就是你需要点击两次的原因。

FeedFragment feedFragment = new FeedFragment();
                    FragmentManager fm = getSupportFragmentManager();
                    Bundle args = new Bundle();
                    args.putString("url", Constants.URL_BASE_CATEGORY + categoriesDTO.getCategories().get(position).getSlug());
                    feedFragment.setArguments(args);
                    fm.beginTransaction().replace(R.id.content_frame, feedFragment).addToBackStack(categoriesDTO.getCategories().get(position).getSlug()).commit();

做一件事

@Override
public void onBackPressed() {
       FragmentManager fm = getFragmentManager();
       if(fm.getBackStackEntryCount() == 1){
        fm.popBackStack ("YOUR_TAG",FragmentManager.POP_BACK_STACK_INCLUSIVE);
       }
       super.onBackPressed();
       }

【讨论】:

  • 只有当用户点击列表项时,loadcategories 中的片段才会被放入 backstack
  • 但您是从 oncreate() 调用它。这意味着当活动开始时,它会添加到后台堆栈。然后尝试在 listItem click event 上调用 loadcategories() 。不在 onCreate 中。谢谢它会帮助你:)
【解决方案2】:
Try to make own switch like:
import android.support.v4.app.Fragment;
and make switch case and use it like this: 

 case 44: {

                page = 44;

                fragment = new FragmentOne();
                getSupportActionBar().setTitle(R.string.page_44);

                action = true;

                break;
            }
 if (action) {
            FragmentManager fragmentManager = getSupportFragmentManager();
            fragmentManager.beginTransaction()
                    .replace(R.id.container_body, fragment)
                    .commit();
        }


and finally in
 backpress(){

displayView(44);}

【讨论】:

    【解决方案3】:

    如果您的意思是您的应用程序显示不应该存在的空白片段,那么您需要编辑片段事务,从容器中获取片段并添加一些条件以在第一个片段不为空时将其添加到后台堆栈。见下面的例子

    Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.content_frame);
    FragmentManager fm = getSupportFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    ft.replace(R.id.content_frame, feedFragment)
    if(fragment != null){
        ft.addToBackStack(categoriesDTO.getCategories().get(position).getSlug());
    }
    ft.commit();
    

    希望对你有帮助:)

    【讨论】:

      【解决方案4】:

      我添加这样的片段:

      private void addTransaction(Fragment fragment) {
          FragmentTransaction ft = getFragmentManager().beginTransaction();
          ft.replace(R.id.content_frame, fragment, "visible_fragment");
          ft.addToBackStack(null);
          ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
          ft.commit();
      }
      

      我用它来管理按下后退按钮时的片段事务:

      public boolean onKeyDown(int keyCode, KeyEvent event) {
          if (keyCode == KeyEvent.KEYCODE_BACK) {
              if (drawer.isDrawerOpen(GravityCompat.START)) {
                  drawer.closeDrawer(Gravity.LEFT); //CLOSE Nav Drawer!
              } else {
                  if (getFragmentManager().getBackStackEntryCount() == 0) {
                      this.finish();
                      return false;
                  }
      
                  if (getFragmentManager().getBackStackEntryCount() > 1) {
                      getFragmentManager().popBackStack();
                      removeCurrentFragment();
                      return false;
                  }
              }
          }
          return super.onKeyDown(keyCode, event);
      }
      

      从后台删除当前片段

      public void removeCurrentFragment() {
          FragmentTransaction transaction = getFragmentManager().beginTransaction();
          Fragment currentFrag = getFragmentManager().findFragmentByTag("visible_fragment");
          String fragName = "NONE";
      
          if (currentFrag != null) {
              fragName = currentFrag.getClass().getSimpleName();
              transaction.remove(currentFrag);
          }
      
          transaction.commit();
      }
      

      要处理 backstack 上的更改,您必须在您的活动上实现 FragmentManager.OnBackStackChangedListener@Override onBackStackChanged() 方法,例如:

      @Override
      public void onBackStackChanged() {
          // Get your current fragment
          Fragment fragment = getFragment();
      
          // Update your UI such as title, drawer selected options, etc
      }
      
      private Fragment getFragment() {
          return getFragmentManager().findFragmentByTag("visible_fragment");
      }
      

      希望对你有帮助。

      【讨论】:

        【解决方案5】:

        在你的 onBackPressed 中,在 super.onBackPressed() 之前添加:

        moveTaskToBack(true);
        

        编辑

        要实现您所需的功能,请尝试以下操作:

         @Override
        public void onBackPressed() {
        
            int count = getFragmentManager().getBackStackEntryCount();
            //pop all fragments till it remains the first fragment then move to background
            if (count == 1) {
                super.onBackPressed();
                //additional code
            } else {
                getFragmentManager().popBackStack();
            }
        
        }
        

        【讨论】:

        • 你的解决方案搞砸了整个应用流程
        • 对不起。你能解释一下当你应用我的解决方案时发生了什么吗?
        • 这会将应用程序带到后台,即使它不应该进入后台。对于在 backstack 中的片段。
        • 你到底想做什么?在移动到后台之前清除后台堆栈?
        • 不。仔细阅读我的问题。我有很多碎片。第一个片段不添加到后台堆栈,而其他片段则添加到后台堆栈。当我单击第一个片段上的后退按钮时,我希望我的应用程序返回原点。它应该进入后台而不是删除第一个片段并显示空白屏幕
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-02
        • 2021-04-09
        • 2013-02-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多