Фрагмент из ViewPager возвращает нулевой контекст, если система убивает приложение в стеке - PullRequest
0 голосов
/ 29 августа 2018

У меня проблемы, и я не знаю, как это исправить. Все работает хорошо и должным образом, но если приложение было в стеке, а ОС требовались ресурсы, это убивает приложение, и я получаю проблему.

У меня есть одно действие с FAB, Tabs и ViewPager, которое содержит 2 фрагмента. FAB зависит от того, какие текущие Tab вызывает методы Fragments, я использую интерфейс для него, а мои методы используют context во Fragments.

Схема активности

public class MyActivity extends AppCompatActivity {

private MyInterface mMyInterface;
private FloatingActionButton mFab;
private Toolbar mToolbar;
private DrawerLayout mDrawerLayout;
private NavigationView mNavigationView;
private ViewPager mViewPager;
private TabLayout mTabLayout;
private PagerAdapter mAdapter;
private FirstFragment mFirstFrg;
private SecondFragment mSecondFrg;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initToolbar();
    initComponent();
}

private void initToolbar() {
    mToolbar = (Toolbar) findViewById(R.id.toolbar);
    mToolbar.setNavigationIcon(R.drawable.ic_menu);
    setSupportActionBar(mToolbar);
    getSupportActionBar().setTitle("My App");
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}

private void initComponent() {

    mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer);
    mNavigationView = (NavigationView) findViewById(R.id.navigation);
    mViewPager = (ViewPager) findViewById(R.id.view_pager);
    setupViewPager(mViewPager);

    mTabLayout = (TabLayout) findViewById(R.id.tab_layout);
    mTabLayout.setupWithViewPager(mViewPager);

    mFirstFrg = (FirstFragment) mAdapter.getItem(0);
    mSecondFrg = (SecondFragment) mAdapter.getItem(1);

    mFab = (FloatingActionButton)findViewById(R.id.fab);

    mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
        @Override
        public boolean onNavigationItemSelected(MenuItem item) {

            if(item.getItemId() == R.id.drawer_one) {
                showToast("Menu one");
            }else{
                showToast("Menu two");
            }
            item.setChecked(true);
            mDrawerLayout.closeDrawers();
            return true;
        }
    });

    mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
        @Override
        public void onPageSelected(int position) {
            changeFabIcon(position);
            super.onPageSelected(position);
        }
    });

    mFab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (mViewPager.getCurrentItem()) {
                case 0: {       
                        showToast("Test!!!");
                    }
                    break;
                }
                case 1: {
                        if(mSecondFrg.getContext() == null){                
                            showToast("context is Null!");
                        }
                        mMyInterface.doSomething();
                    break;
                }
            }
        }
    });
}

private void setupViewPager(ViewPager viewPager) {
    FirstFragment firstFragment = new FirstFragment();
    SecondFragment secondFragment = new SecondFragment();
    this.mMyInterface = secondFragment;
    mAdapter = new PagerAdapter(getSupportFragmentManager());
    mAdapter.addFragment(firstFragment, "One");
    mAdapter.addFragment(secondFragment, "Two");
    viewPager.setAdapter(mAdapter);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if(item.getItemId() == android.R.id.home)
    {
        mDrawerLayout.openDrawer(GravityCompat.START);
        return true;
    }
    return super.onOptionsItemSelected(item);
}

private void changeFabIcon(final int index) {
    mFab.hide();
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            switch (index) {
                case 0: {
                    mFab.setImageResource(R.drawable.ic_plus);
                    break;
                }
                case 1: {
                    mFab.setImageResource(R.drawable.ic_text);
                    break;
                }
            }
            mFab.show();
        }
    }, 300);
}

private void showToast(String message){
    Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}}

Фрагмент второй схемы

public class SecondFragment extends Fragment implements MyInterface {

private RecyclerView mRecycler;
private Context mContext;

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View fragmentView = inflater.inflate(R.layout.fragment_second, container, false);
    mRecycler = (RecyclerView) placeView.findViewById(R.id.recycler);
    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mContext);
    linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
    mRecycler.setLayoutManager(linearLayoutManager);

    return fragmentView;
}

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    mContext = context;
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setRetainInstance(true);
}

private void getData(){// Some action and Update the UI
}
@Override
public void doSomething(){ 
    getData();
}}

Проблема в том, что каждый раз, когда Система удаляет приложение в стеке, я получаю нулевые методы Context, а Fragment не работает :( Я проверяю это там

if(mSecondFrg.getContext() == null){                
                            showToast("context is Null!");
                        }
                        mMyInterface.doSomething();

Также мой код адаптера

public class PagerAdapter extends FragmentPagerAdapter {

private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();

public PagerAdapter(FragmentManager manager) {
    super(manager);
}

@Override
public Fragment getItem(int position) {
    return mFragmentList.get(position);
}

@Override
public int getCount() {
    return mFragmentList.size();
}

public void addFragment(Fragment fragment, String title) {
    mFragmentList.add(fragment);
    mFragmentTitleList.add(title);
}

@Override
public CharSequence getPageTitle(int position) {
    return mFragmentTitleList.get(position);
}}

Спасибо за любые подсказки или помощь

Обновление и исправление Я это исправил, проблема была в адаптере Пожалуйста, прочитайте это из документации

Вызов метода startUpdate (ViewGroup) в PagerAdapter указывает, что содержимое ViewPager собирается измениться. Последуют один или несколько обращений к instantiateItem (ViewGroup, int) и / или destroyItem (ViewGroup, int, Object), и об окончании обновления будет сигнализироваться вызовом finishUpdate (ViewGroup).

я удалил весь код создания фрагмента в Activity и добавил это

mAdapter.startUpdate(mViewPager);
mFirstFrg = (FirstFragment) mAdapter.instantiateItem(mViewPager,0);
mSecondFrg = (SecondFragment) mAdapter.instantiateItem(mViewPager,1);
mAdapter.finishUpdate(mViewPager);

Обновление класса адаптера

public class PagerAdapter extends FragmentPagerAdapter {
public PagerAdapter(FragmentManager manager) {
    super(manager);
}
@Override
public Fragment getItem(int position) {
    if (position == 0) {
        return new FirstFragment();
    }else {
        return new SecondFragment();
    }
}

@Override
public int getCount() {
    return 2;
}

@Override
public CharSequence getPageTitle(int position) {
    if (position == 0){
        return "One";
    }else {
        return "Two";
    }
}

Также вы можете использовать FragmentStatePagerAdapter, вы можете прочитать об этом там Разница между FragmentPagerAdapter и FragmentStatePagerAdapter

...