Android, как остановить обновление фрагментов при изменении вкладок
У меня есть следующий код:
MainActivity.java
package com.erc.library;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.FragmentTransaction;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Environment;
import android.os.StrictMode;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
import com.erc.sayeghlibrary.adapter.TabsPagerAdapter;
public class MainActivity extends FragmentActivity implements
ActionBar.TabListener {
private ViewPager viewPager;
private TabsPagerAdapter mAdapter;
private ActionBar actionBar;
// Tab titles
private String[] tabs = { "Stories", "Dictionaries", "eBooks"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int actionBarTitleId = Resources.getSystem().getIdentifier("action_bar_title", "id", "android");
if (actionBarTitleId > 0) {
TextView title = (TextView) findViewById(actionBarTitleId);
if (title != null) {
title.setTextColor(Color.WHITE);
}
}
// Initilization
viewPager = (ViewPager) findViewById(R.id.pager);
actionBar = getActionBar();
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Adding Tabs
for (String tab_name : tabs) {
actionBar.addTab(actionBar.newTab().setText(tab_name)
.setTabListener(this));
}
/**
* on swiping the viewpager make respective tab selected
* */
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
// on changing the page
// make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// on tab selected
// show respected fragment view
viewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// action with ID action_refresh was selected
case R.id.Favorites:
Toast.makeText(this, "Favorites selected", Toast.LENGTH_SHORT)
.show();
break;
// action with ID action_settings was selected
default:
break;
}
return true;
}
}
TabsPagerAdapter.java
package com.erc.library.adapter;
import com.erc.library.Dictionaries;
import com.erc.library.Ebooks;
import com.erc.library.Stories;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
public class TabsPagerAdapter extends FragmentPagerAdapter {
public TabsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int index) {
switch (index) {
case 0:
return new Stories();
case 1:
return new Dictionaries();
case 2:
// Movies fragment activity
return new Ebooks();
}
return null;
}
@Override
public int getCount() {
// get item count - equal to number of tabs
return 3;
}
}
Я делаю библиотечное приложение, в котором навигацией по вкладкам, проблема возникает каждый раз, когда я перехожу с третьей вкладки в первую или первую в третью, содержимое вкладки освежает, я хочу, чтобы предотвратить обновить, Любая помощь пожалуйста?
Ответы
Ответ 1
По умолчанию ViewPager
воссоздает фрагменты при прокрутке страницы. Чтобы предотвратить это, вы можете попробовать одну из двух вещей:
1. В onCreate()
ваших фрагментов вызовите setRetainInstance(true)
.
2. Если количество фрагментов фиксировано и относительно невелико, то в onCreate()
добавьте следующий код:
mViewPager = (ViewPager)findViewById(R.id.pager);
mViewPager.setOffscreenPageLimit(limit); /* limit is a fixed integer*/
Если я правильно помню, второй вариант более перспективен. Но я призываю вас попробовать оба и посмотреть, какие из них работают.
Ответ 2
сначала нужно указать FragmentPagerAdapter
, затем .getCount()
вернет значение -
в то время как .getCount() - 1
должен быть установлен как предел по умолчанию за пределами экрана:
TabsPagerAdapter adapter = new TabsPagerAdapter(getSupportFragmentManager());
/* the ViewPager requires a minimum of 1 as OffscreenPageLimit */
int limit = (adapter.getCount() > 1 ? adapter.getCount() - 1 : 1);
ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(limit);
Ответ 3
вы можете обрабатывать просмотр отдыха, проверяя, является ли представление нулевым или нет
public class FragmentExample extends Fragment {
private View rootView;
public FragmentExample() {}
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
if (rootView == null) {
rootView = inflater.inflate(R.layout.fragment_example_layout, container, false);
// Initialise your layout here
} else {
((ViewGroup) rootView.getParent()).removeView(rootView);
}
return rootView;
}
}
Ответ 4
В onCreate() ваших фрагментов вызовите setRetainInstance (true)
Ответ 5
Так как активность реализует ActionBar.TabListener, активность onCreate() вызывается снова и снова. Поэтому поместите следующий код в метод onResume():
// Initilization
viewPager = (ViewPager) findViewById(R.id.pager);
actionBar = getActionBar();
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Adding Tabs
for (String tab_name : tabs) {
actionBar.addTab(actionBar.newTab().setText(tab_name)
.setTabListener(this));
}
/**
* on swiping the viewpager make respective tab selected
* */
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
// on changing the page
// make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageScrollStateChanged(int arg0) {
}
});
Ответ 6
Немного поздно к этому вопросу, но благодаря Y.S., узнал, как работает ViewPager. Я создавал приложение с 4 вкладками и в любой момент времени замечал, что обновляется только две вкладки, что, я полагаю, было поведением по умолчанию. После нескольких часов исследований я понял, что Android обновляет несколько вкладок, чтобы обеспечить плавное отслеживание производительности для пользователя - вы могли заметить, что вы бы нажали на tab2, но андроид вводит данные для tab3 и сохраняет его.
Хотя это поведение хорошо, оно имеет свои плюсы и минусы. Плюсы - вы получаете плавный переход, без загрузки данных с внешнего сервера, когда вы приземляетесь на эту вкладку. Минусы - реализация backstack в вкладках может пойти на бросок. Когда вы нажимаете вкладку, пейджер представления на самом деле вызывает более плавную вкладку, и в итоге вы столкнетесь с большими проблемами, если ваши методы настраивают backarrow (home) в левом верхнем углу в зависимости от того, что находится в backstack на вкладке clicked.
setOffscreenPageLimit - это ответ на этот вопрос. Если вы хотите, чтобы ваша пользовательская структура backstack функционировала, и вы не хотите, чтобы tab3 вызывался при нажатии на tab2, вам просто нужно установить значение в число вкладок. Например, если у вас есть 4 вкладки, установите setOffScreePageLimit (4). Это означало бы, что Android сначала обновит все 4 фрагмента, что немного связано с производительностью (что вы должны правильно управлять). Но, ваши backstack и переключение табуляции остаются нетронутыми. Надеюсь, это поможет.
Ответ 7
В моем случае выше предложение не работает.
Чтобы ограничить воссоздание фрагмента, что я сделал:
В onCreateView
вы можете хранить завышенное представление в глобальной переменной и инициализировать его, только если оно null
, как в этом коде:
var root:View?=null
var apiDataReceived=false
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
if (root==null)
root=inflater!!.inflate(R.layout.fragment_layout, container, false)
return root
}
Теперь, если вы анализируете некоторые данные и заполняете их в RecyclerView
или любом другом View
-
Создайте глобальную переменную, как в приведенном выше коде apiDataReceived
-
Установите значение true, если вы успешно проанализировали данные.
-
Перед apiCalls поместите условие, подобное этому:
if (! apiDataReceived) {apiCalls()}
Так что, если apiCalls() будет вызываться, только если данные не анализируются.
Делайте ваши http-вызовы и синтаксический анализ или любые другие вещи в методе, который onCreateView
после onCreateView
например onStart
Приведенный выше код написан на kotlin. Если вы столкнулись с какой-либо проблемой, сообщите мне об этом в комментариях.