【问题标题】:Prevent navigation drawer Fragment from being recreated防止重新创建导航抽屉片段
【发布时间】:2016-09-06 09:12:57
【问题描述】:

最近我正在开发我的应用程序,以使其加载更快并更好地工作,我在我的 MainActivity 中使用导航抽屉:

    @Override
public boolean onNavigationItemSelected(MenuItem item) {

    // Handle navigation view item clicks here.
    int id = item.getItemId();

    if (id == R.id.nav_camara) {
        LoadJson asyncTask = (LoadJson) new LoadJson(new LoadJson.AsyncResponse() {
            @Override
            public void processFinish(JSONArray output) {
                //Here you will receive the result fired from async class
                //of onPostExecute(result) method.
                //Set the fragment initially
                MainFragment fragment = new MainFragment(output);
                FragmentTransaction fragmentTransaction =
                        getSupportFragmentManager().beginTransaction();
                fragmentTransaction.add(R.id.fragment_container, fragment);
                fragmentTransaction.commit();
                // Handle the camera action
            }
        }).execute();


    } else if (id == R.id.nav_gallery) {
        //Set the fragment initially
        GalleryFragment fragment = new GalleryFragment();
        FragmentTransaction fragmentTransaction =
                getSupportFragmentManager().beginTransaction();
        fragmentTransaction.replace(R.id.fragment_container, fragment);
        fragmentTransaction.commit();


    } else if (id == R.id.nav_search) {
        //Set the fragment initially
        FetchResualt fragment = new FetchResualt();
        FragmentTransaction fragmentTransaction =
                getSupportFragmentManager().beginTransaction();
        fragmentTransaction.replace(R.id.fragment_container, fragment);
        fragmentTransaction.commit();
        // Handle the camera action

    } else if (id == R.id.nav_manage) {//
         Bundle bundle = new Bundle();//
        bundle.putInt("someStr",ID_OF_BEACH);//
        //Set the fragment initially//
        FragmentBeach fragment = new FragmentBeach();//
        fragment.setArguments(bundle);//
        FragmentTransaction fragmentTransaction =//
                getSupportFragmentManager().beginTransaction();//
        fragmentTransaction.replace(R.id.fragment_container, fragment);//
        fragmentTransaction.commit();//
        // Handle the camera action

    } else if (id == R.id.nav_share) {

    } else if (id == R.id.nav_send) {

    }

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    drawer.closeDrawer(GravityCompat.START);
    return true;
}

如您所见,如果我们按下第一个菜单 if (id == R.id.nav_camara),它会将 JSONArray 传递给 Fragment 类,并且加载大约需要 4-5 秒。因此,如果用户每次转到 nav_camara 时都在菜单之间导航,它会使应用程序冻结 4 秒才能加载,并且正如您所看到的,每次我们选择一个菜单项时,它都会重新创建一个片段的新副本,所以即使我让:setRetainInstance(true); 在我的片段类中它不起作用。

您建议什么解决方案来防止应用在每次选择菜单项时重新创建新片段?

【问题讨论】:

  • 也许是加载问题?而不是片段本身?尝试实现一些预取并提前执行您的 LoadJson 任务。
  • 嘿,请访问this link。希望在这里你能找到有用的东西。
  • 我认为这没有任何区别,因为有一些计算可以制作 culester 标记并迭代 json 文件并将其放在地图上,这需要很长时间,并且每次应用程序制作新副本片段这些计算会发生它认为解决方案不能重新生成片段
  • 这不是导航抽屉。这是另外一回事。导航抽屉可以通过从屏幕开始处(通常是左侧)做出滑动/滑动手势或按下汉堡按钮(在 ActionBar 中)来调出。它仅在 Activity 的 onCreate() 生命周期方法期间创建/恢复。你所做的显然是另一回事。
  • @Sufian 它的作用完全相同,但我为每个菜单项定义了一个 ID,因此我在选择其中一个时实现我的片段

标签: android android-fragments navigation-drawer


【解决方案1】:

您需要保留 SparseArray<Fragment> 以将实例保存在内存中。

按照以下步骤操作:

  1. 在您的活动中创建一个字段:

    SparseArray<Fragment> myFragments;
    
  2. onCreate() 中初始化它:

    myFragments = new SparseArray<Fragment>();
    
  3. 更新您的onNavigationItemSelected()

    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        int id = item.getItemId();
    
        if (id == R.id.nav_camara) {
            // get cached instance of the fragment
            fragment = myFragments.get(INT_CONSTANT_FOR_CAM_FRAGMENT);
    
            // if fragment doesn't exist in myFragments, create one and add to it
            if (fragment == null) {
                fragment = new MainFragment();
                myFragments.put(INT_CONSTANT_FOR_CAM_FRAGMENT, fragment);
            }
    
            // now load the fragment
            FragmentTransaction fragmentTransaction =
                        getSupportFragmentManager().beginTransaction();
            fragmentTransaction.replace(R.id.fragment_container, fragment);
            fragmentTransaction.commit();
    
        }
        // do the rest with others as well.
    }
    
  4. AsyncTask 移动到您的MainFragmentonActivityCreated() 或类似的生命周期方法中。

以上方式可以让您重用片段并将逻辑移动到正确的位置(您的 Activity 不应该知道 MainFragment 如何加载数据以启动自身,但当然您仍然可以将其保留在那里,尽管不推荐) .

【讨论】:

  • 这里:fragmentTransaction.add(R.id.fragment_container, fragment); “片段”的价值是什么?我想你忘了实例化它
  • @AryaR。解决了这个问题。
  • 我试试这样的代码: int id = item.getItemId(); if (id == R.id.nav_camara) { //初始设置片段 Fragment fragment = myFragments.get(id, new MainFragment()); // 现在加载片段 FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); fragmentTransaction.add(R.id.fragment_container, fragment);片段交易.commit();它不起作用:(
  • @AryaR。用“它不起作用”解释你的意思。它什么都不做,或者它崩溃或其他什么?
  • 这意味着它没有解决它再次重新加载之前工作的问题
【解决方案2】:

您可以在将新片段推送到容器时添加TAG。然后使用FragmentManager#findFragmentByTag 查找之前添加了相同标签的任何片段。

        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        Fragment oldFragment = manager.findFragmentByTag(tag);
        if (oldFragment != null)
            transaction.replace(R.id.fragment_container, oldFragment, tag);
        else
            transaction.replace(R.id.fragment_container, newInstanceOfFragment, tag);
        transaction.commit();

【讨论】:

    【解决方案3】:

    全局声明它们

    GalleryFragment galleryFrag = new GalleryFragment();
    FragmentTransaction ft;
    FragmentManager fm;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
    
        fm = getSupportFragmentManager();
    
        ...
    }
    

    然后在您的导航选择上

    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
    
    // Handle navigation view item clicks here.
    int id = item.getItemId();
    
    if (id == R.id.nav_search) {
        ft = fm.beginTransaction();
        ft.replace(R.id.fragment_container, galleryFrag).commit();
    } 
    
    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    drawer.closeDrawer(GravityCompat.START);
    return true;
    }
    

    【讨论】:

    • 没有任何区别
    • 它有所作为。它不会创建片段的另一个实例。至于 jsonobject,请尝试将其作为参数传递,而不是传递给构造函数。不要在片段上创建构造函数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-16
    • 2016-01-03
    • 1970-01-01
    相关资源
    最近更新 更多