best way to use context in fragment

2019-06-23 18:15发布

i m using fragments in my application. i created one Parent Class called BaseFragment and all other fragment extends this Basefrgment below is the snippet of this Basefragment

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() + ""); }

and in all other fragment i m using activity as a context,my question is whether it is bad way to access context in this way or whether it creates memory leak.or any other approach for accessing context..any help is appriciated.

5条回答
贼婆χ
2楼-- · 2019-06-23 18:53

I think the way you are storing the context is really optimal as with that you will be able to use it within each of your sub fragment instances. Because MainActivity is an instance variable in your fragment, it will be garbage collected when your fragment gets destroyed. And if I'm not mistaken about Activity-Fragment lifecycle, when your activity gets rotated, new fragments will be created and the older fragment instances will get destroyed. So, we're good there too. However, you need to be careful with your context variable declaration:

public MainActivity activity;

This makes it accessible from anywhere. Any class can call something like context = fragIns.activity and save it there. This will be really bad for you because now it holds a reference to that context variable. Now, when your fragment is no longer needed it will not be garbage collected because some other class is holding a reference to one of its variable. You'd find yourself in "memory leak town".

Make sure you hold this variable dearly and its reference is not passed to other classes. Since, its in a super class, you may define it as:

protected MainActivity activity;

This should do the job.

查看更多
一纸荒年 Trace。
3楼-- · 2019-06-23 18:53

To avoid memory problems it's recommended that whenever you use onAttach(Context context) you should use onDetach() as well:

@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();
}
查看更多
我欲成王,谁敢阻挡
4楼-- · 2019-06-23 19:00

the best way is to use getActivity() function inside fragment to access context, because it will return the instance of the activity on which fragment is attached.

查看更多
迷人小祖宗
5楼-- · 2019-06-23 19:03

using getActivity() is easy and quick way to get parent activity's context but problem comes when that fragment is detached.

So using it like this inside fragment , imo, will suffice the need of doing it better way....

@Override
public void onAttach(Activity activity) {        
    super.onAttach(activity);
    mContext=activity;
}
查看更多
我欲成王,谁敢阻挡
6楼-- · 2019-06-23 19:18

My way:

public class AppManager extends Application {


    private static AppManager mApp;

    @Override
    public void onCreate() {
        super.onCreate();
        mApp = this;
    }

    public static Context getContext() {
        return mApp.getApplicationContext();
    }
}

so, anyone wants to get a Context, just using the AppManager.getContext(), except starting a Activity. It is very simple.

In your way, if the activity restarted, the fragment will automatically create again. In you dont' handle the action of Activty restarted, it is posssible that the Activity have two same Fragment, and one who automatically creating didn't call OnAttch(), will causing NullPointerException.

My solution:

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;
    }

}
查看更多
登录 后发表回答