Android 如何在选项卡更改时停止刷新片段
Android how to stop refreshing Fragments on tab change
我有以下代码:
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;
}
}
我正在制作一个图书馆应用程序,其中导航是通过选项卡进行的,问题是每次我从第三个选项卡转到第一个或从第一个转到第三个选项卡时,选项卡内容都在刷新,我想阻止刷新,有什么帮助吗?
默认情况下,ViewPager
会在您滑动页面时重新创建片段。为防止这种情况,您可以尝试以下三种方法之一:
1. 在片段的 onCreate()
中,调用 setRetainInstance(true)
.
2.如果分片数量固定且比较少,那么在你的onCreate()
中添加如下代码:
mViewPager = (ViewPager)findViewById(R.id.pager);
mViewPager.setOffscreenPageLimit(limit); /* limit is a fixed integer*/
3. 使用 FragmentPagerAdapter
作为 ViewPager
.
的一部分
如果我没记错的话,第二种方案更有希望。但我强烈建议您尝试所有这三个,看看哪个有效。
由于 activity 实现了 ActionBar.TabListener,activity 的 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) {
}
});
必须首先实例化 FragmentPagerAdapter
,然后 .getCount()
将 return 一个值 -
而 .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);
您可以通过检查视图是否为空来处理视图重建
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;
}
}
这个问题有点晚了,但感谢 Y.S,了解了 ViewPager 的工作原理。我正在构建一个带有 4 个选项卡的应用程序,并且在任何时候都注意到只有两个选项卡被刷新,我认为这是默认行为。经过几个小时的调查,我了解到 Android 会刷新多个选项卡,以便为用户带来流畅的滑动性能 - 您可能会注意到您会点击 tab2,但 android 会为 tab3 和准备好。
这种行为虽然好,但也有利有弊。优点 - 您可以获得流畅的滑动体验,当您进入该选项卡时,无需从外部服务器加载数据。缺点-您在选项卡中的 backstack 实现可能会被折腾。当您单击一个选项卡时,视图寻呼机实际上会调用更平滑的选项卡,如果您的方法根据单击选项卡中的后退堆栈中的内容在左上角设置后退箭头(主页),那么您最终会遇到大麻烦。
setOffscreenPageLimit 就是解决这个问题的方法。如果您希望您的自定义后台堆栈框架起作用,并且不希望在单击 tab2 时调用 tab3,您只需将值设置为选项卡的数量。例如,如果您有 4 个选项卡,请设置 setOffScreePageLimit(4)。这意味着 Android 最初会刷新所有 4 个片段,这会带来一些性能开销(您应该妥善管理)。但是,您的后台堆栈和选项卡切换保持不变。希望这有帮助。
在片段的 onCreate() 中,调用 setRetainInstance(true)
在我的情况下,上述建议不起作用。
为了限制片段的重新创建,我做了什么:
在 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
如果您成功解析数据,请将其设置为真。
在 apiCalls 放置这样的条件之前:
if (!apiDataReceived) {
apiCalls()
}
因此,如果仅在未解析数据时才调用 apiCalls()。
在 onCreateView
之后调用的方法中执行您的 http 调用和解析或任何其他操作,例如 onStart
以上代码是在kotlin中,如果您遇到任何问题,请在评论中告诉我。
我有以下代码:
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;
}
}
我正在制作一个图书馆应用程序,其中导航是通过选项卡进行的,问题是每次我从第三个选项卡转到第一个或从第一个转到第三个选项卡时,选项卡内容都在刷新,我想阻止刷新,有什么帮助吗?
默认情况下,ViewPager
会在您滑动页面时重新创建片段。为防止这种情况,您可以尝试以下三种方法之一:
1. 在片段的 onCreate()
中,调用 setRetainInstance(true)
.
2.如果分片数量固定且比较少,那么在你的onCreate()
中添加如下代码:
mViewPager = (ViewPager)findViewById(R.id.pager);
mViewPager.setOffscreenPageLimit(limit); /* limit is a fixed integer*/
3. 使用 FragmentPagerAdapter
作为 ViewPager
.
如果我没记错的话,第二种方案更有希望。但我强烈建议您尝试所有这三个,看看哪个有效。
由于 activity 实现了 ActionBar.TabListener,activity 的 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) {
}
});
必须首先实例化 FragmentPagerAdapter
,然后 .getCount()
将 return 一个值 -
而 .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);
您可以通过检查视图是否为空来处理视图重建
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;
}
}
这个问题有点晚了,但感谢 Y.S,了解了 ViewPager 的工作原理。我正在构建一个带有 4 个选项卡的应用程序,并且在任何时候都注意到只有两个选项卡被刷新,我认为这是默认行为。经过几个小时的调查,我了解到 Android 会刷新多个选项卡,以便为用户带来流畅的滑动性能 - 您可能会注意到您会点击 tab2,但 android 会为 tab3 和准备好。
这种行为虽然好,但也有利有弊。优点 - 您可以获得流畅的滑动体验,当您进入该选项卡时,无需从外部服务器加载数据。缺点-您在选项卡中的 backstack 实现可能会被折腾。当您单击一个选项卡时,视图寻呼机实际上会调用更平滑的选项卡,如果您的方法根据单击选项卡中的后退堆栈中的内容在左上角设置后退箭头(主页),那么您最终会遇到大麻烦。
setOffscreenPageLimit 就是解决这个问题的方法。如果您希望您的自定义后台堆栈框架起作用,并且不希望在单击 tab2 时调用 tab3,您只需将值设置为选项卡的数量。例如,如果您有 4 个选项卡,请设置 setOffScreePageLimit(4)。这意味着 Android 最初会刷新所有 4 个片段,这会带来一些性能开销(您应该妥善管理)。但是,您的后台堆栈和选项卡切换保持不变。希望这有帮助。
在片段的 onCreate() 中,调用 setRetainInstance(true)
在我的情况下,上述建议不起作用。
为了限制片段的重新创建,我做了什么:
在 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
如果您成功解析数据,请将其设置为真。
在 apiCalls 放置这样的条件之前:
if (!apiDataReceived) { apiCalls() }
因此,如果仅在未解析数据时才调用 apiCalls()。
在 onCreateView
之后调用的方法中执行您的 http 调用和解析或任何其他操作,例如 onStart
以上代码是在kotlin中,如果您遇到任何问题,请在评论中告诉我。