【问题标题】:best way to use context in fragment在片段中使用上下文的最佳方法
【发布时间】:2016-12-12 13:18:07
【问题描述】:

我在我的应用程序中使用片段。我创建了一个名为 BaseFragment 的父类,所有其他片段都扩展了这个 Basefrgment 下面是这个 Basefragment 的 sn-p

BaseFragment.java

public class BaseFragment extends Fragment {
    public MainActivity activity;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (activity == null && context instanceof  MainActivity) {
            activity = (MainActivity) context;
        }
    }
}


public void replaceFragment(Fragment fragment, FragmentDetail last) {

    fragmentManager = getSupportFragmentManager();
    FragmentTransaction transaction = fragmentManager.beginTransaction();
    boolean push = true;
    if (Validator.isNotNull(last)) {
        push = false;
    }
    /*if(Validator.isNull(last)){
        transaction.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right);
    }else{
        transaction.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left);
    }*/
    transaction.add(R.id.frame_container, fragment, fragment.getClass().getName());
    if (Validator.isNull(last) && preferences.getFragmentStack().size() > 0) {
        last = preferences.getFragmentStack().lastElement();
    }
    if (Validator.isNotNull(last)) {
        Fragment f = fragmentManager.findFragmentByTag(last.className);
        if (Validator.isNotNull(f)) {
            f.onPause();
            transaction.remove(f);
        }
    }
    last = new FragmentDetail(fragment.getClass().getName(), getTitle().toString(), preferences.isBack());
    if (preferences.isBack() || preferences.getFragmentStack().size() == 0) {
        if (push) {
            preferences.getFragmentStack().push(last);
        }
    } else {
        while (preferences.getFragmentStack().size() > 1) {
            preferences.getFragmentStack().pop();
        }
        if (!preferences.getFragmentStack().lastElement().className.equals(last.className)) {
            preferences.getFragmentStack().push(last);
        }
    }
    transaction.commitAllowingStateLoss();
    changeNavigationIcon();

// HWUtil.showToast(this, fragmentManager.getBackStackEntryCount() + ""); }

在我使用活动作为上下文的所有其他片段中,我的问题是,以这种方式访问​​上下文是否是不好的方式,或者它是否会造成内存泄漏。或任何其他访问上下文的方法。任何帮助都已得到应用。

【问题讨论】:

    标签: android fragment android-context


    【解决方案1】:

    我认为您存储context 的方式确实是最佳的,因为您可以在每个子片段实例中使用它。因为MainActivity 是片段中的实例变量,所以当片段被销毁时,它将被垃圾回收。如果我没有弄错 Activity-Fragment 生命周期,当您的活动旋转时,将创建新的片段,而旧的片段实例将被销毁。所以,我们在那里也很好。但是,你需要小心你的上下文变量声明:

    public MainActivity activity;
    

    这使得它可以从任何地方访问。任何类都可以调用context = fragIns.activity 之类的东西并将其保存在那里。这对您来说真的很糟糕,因为现在它包含对该上下文变量的引用。现在,当不再需要您的片段时,它不会被垃圾收集,因为其他一些类正在持有对其变量之一的引用。你会发现自己身处“内存泄漏小镇”。

    确保你非常重视这个变量,并且它的引用没有传递给其他类。由于它在一个超类中,您可以将其定义为:

    protected MainActivity activity;
    

    这应该可以完成工作。

    【讨论】:

    • @Shaishav 你是绝对正确的..你能不能再提供一个关于如何在适配器类中访问这个上下文的解决方案
    • 您可以将引用传递给您的适配器实例,只需将其传递给activity 变量即可。只需确保 adapter 实例本身仅在您的片段中声明即可。我们不希望将activity 实例提供给任何可能不会被我们的片段破坏的类:)
    【解决方案2】:

    最好的方法是在片段中使用 getActivity() 函数来访问上下文, 因为它将返回附加了片段的活动的实例。

    【讨论】:

    • 但我多次遇到空指针异常,因为片段与活动分离
    • 使用 getActivity().getApplicationContext() 函数并将其实例保存为静态,以便在片段与活动分离时它不能为空,并且首先检查实例是否为空只执行您的操作
    • 如果由于不推荐静态变量而意外变为 null 怎么办
    • @GokulKumar 不要在静态字段中保存任何 context 内容,因为这会使您的应用容易受到内存泄漏的影响。
    • @Shaishav 所以最好的方法是什么,请建议
    【解决方案3】:

    使用getActivity() 是获取父 Activity 上下文的简单快捷方式,但分离该片段时会出现问题。

    因此,像这样在 fragment 内使用它,imo 就足以满足以更好的方式进行操作的需要......

    @Override
    public void onAttach(Activity activity) {        
        super.onAttach(activity);
        mContext=activity;
    }
    

    【讨论】:

      【解决方案4】:

      为避免内存问题,建议您在使用onAttach(Context context) 时也应使用onDetach()

      @Override
      public void onAttach(Context context) {
          super.onAttach(context);
          if (activity == null && context instanceof  MainActivity) {
              activity = (MainActivity) context;
          }
      }
      
      @Override
      public void onDetach() {
          this.activity = null;
          super.onDetach();
      }
      

      【讨论】:

        【解决方案5】:

        我的方式:

        public class AppManager extends Application {
        
        
            private static AppManager mApp;
        
            @Override
            public void onCreate() {
                super.onCreate();
                mApp = this;
            }
        
            public static Context getContext() {
                return mApp.getApplicationContext();
            }
        }
        

        所以,任何人都想获得Context,只需使用AppManager.getContext(),除了开始Activity。很简单。

        以您的方式,如果活动重新启动,片段将自动再次创建。在你不处理 Activty 重启的动作时,可能 Activity 有两个相同的 Fragment,而一个自动创建的 Fragment 没有调用OnAttch(),会导致NullPointerException

        我的解决方案:

        public abstract class BaseTabActivity extends BaseActivity {
        
            @CallSuper
            protected void initTabs(boolean isRestarted) {
                if (isRestarted) {
                    FragmentManager manager = getSupportFragmentManager();
                    FragmentTransaction transaction = manager.beginTransaction();
                    if (manager.getFragments() == null)
                        return;
                    Stream.of(manager.getFragments())
                            .forEach((fragment) -> {
                                if (fragment != null)
                                    transaction.remove(fragment);
                            });
                    transaction.commit();
                    manager.executePendingTransactions();
                }
            }
        
            public FragmentTransaction getSlideAnimTransaction() {
                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                transaction.setCustomAnimations(R.anim.slide_from_right, R.anim.slide_out_left);
                return transaction;
            }
        
        }
        

        【讨论】:

        • @IntelliJ Amiya 但由于这是静态变量,它可能会变为空
        • @Yakami 我无法理解你在说什么
        • @HardikMehta 对不起.....我的英语不好......我只想以你的方式说,在某些情况下,变量MainActivity 在 Activtiy 重启中将为空。希望你能明白我说的话....._(:3」∠)_很抱歉我的英语不好。(´;ω;`)
        • @Yakmi 实际上我无法理解你想说的情况
        • @HardikMehta 如果一个片段以编程方式替换一个视图以显示在屏幕上,当 Activity 重新启动时(旋转屏幕.etc),片段将在我们的代码之前自动重新创建自己。因此,如果我们不处理action,在activity重启后我们会得到两个相同的fragment。
        猜你喜欢
        • 2016-01-25
        • 1970-01-01
        • 1970-01-01
        • 2012-01-03
        • 1970-01-01
        相关资源
        最近更新 更多