Java Android 如何在选项卡更改时停止刷新片段
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28494637/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android how to stop refreshing Fragments on tab change
提问by Monzer Yaghi
I have the following code :
我有以下代码:
MainActivity.java
主活动.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
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;
}
}
I'm making a library application in which the navigation is by tabs, the problem is each time I go from the third tab to the first or the first to the third, the tab content is refreshing, I want to prevent the refresh, Any help please ?
我正在制作一个按标签导航的库应用程序,问题是每次我从第三个标签转到第一个或第一个到第三个时,标签内容正在刷新,我想阻止刷新,任何请帮忙 ?
采纳答案by Y.S
By default, ViewPager
recreates the fragments when you swipe the page. To prevent this, you can try one of three things:
默认情况下,ViewPager
在您滑动页面时重新创建片段。为了防止这种情况,您可以尝试以下三种方法之一:
1.In the onCreate()
of your fragments, call setRetainInstance(true)
.
1.在onCreate()
你的片段中,调用setRetainInstance(true)
。
2.If the number of fragments is fixed & relatively small, then in your onCreate()
add the following code:
2.如果片段数量固定且相对较小,则在您onCreate()
的代码中添加以下代码:
mViewPager = (ViewPager)findViewById(R.id.pager);
mViewPager.setOffscreenPageLimit(limit); /* limit is a fixed integer*/
3.Use a FragmentPagerAdapter
as part of your ViewPager
.
3.使用 aFragmentPagerAdapter
作为ViewPager
.
If I remember correctly, the second option is more promising. But I urge you to try all three and see which of them work.
如果我没记错的话,第二种选择更有希望。但我敦促你尝试所有三个,看看它们中的哪一个有效。
回答by Nagabhushan Baddi
Since the activity implements ActionBar.TabListener, the activity's onCreate() is getting called again and again. So place the following code in onResume() method:
由于活动实现了 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) {
}
});
回答by Martin Zeitler
one has to instance the FragmentPagerAdapter
first, then .getCount()
will return a value -
一个人必须实例第FragmentPagerAdapter
一个,然后.getCount()
将返回一个值 -
while .getCount() - 1
should be set as the default off-screen limit:
while.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);
回答by Ahmad Nasser
you can handle view recreation by check if the view is null or not
您可以通过检查视图是否为空来处理视图娱乐
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;
}
}
回答by Sankararaman Santhanaraman
A bit late to this question, but thanks to Y.S., got to know how ViewPager works. I was building an app with 4 tabs and at any point of time, noticed that only two tabs were being refreshed, which I suppose was a default behaviour. After hours of investigation, I understood that Android refreshes multiple tabs to bring in a smooth swiping performance for the user - you might notice that you would have clicked tab2, but android brings in the data for tab3 and keeps it ready.
这个问题有点晚了,但多亏了 YS,才知道 ViewPager 是如何工作的。我正在构建一个带有 4 个选项卡的应用程序,并且在任何时候都注意到只有两个选项卡正在刷新,我认为这是默认行为。经过几个小时的调查,我了解到 Android 会刷新多个选项卡,以便为用户带来流畅的滑动性能——您可能会注意到您会点击 tab2,但 android 会为 tab3 带来数据并保持就绪。
Though this behaviour is good, it has its pros and cons. Pros - you get a smooth swiping experience, without data being loaded from an external server when you land up in that tab. Cons-your backstack implementation in tabs could go for a toss. When you click a tab, the view pager actually calls smoother tab and you'll end up in a big trouble, if your methods are setting up backarrow (home) at the top left based on what is in the backstack in the clicked tab.
虽然这种行为是好的,但它有利有弊。优点 - 当您进入该选项卡时,您可以获得流畅的刷卡体验,无需从外部服务器加载数据。缺点 - 您在选项卡中的 backstack 实现可能会折腾。当您单击一个选项卡时,视图分页器实际上会调用更平滑的选项卡,如果您的方法根据单击的选项卡中 backstack 中的内容在左上角设置 backarrow(主页),您最终会遇到大麻烦。
setOffscreenPageLimit is the answer to this. If you want your custom backstack framework to function, and do not want tab3 to be called when tab2 is clicked, you simply need to set the value to the number of tabs. For instance, if you have 4 tabs, set setOffScreePageLimit(4). This would mean that Android would refresh all the 4 fragments initially, which is a bit of a performance overhead (which you should manage properly). But, your backstack and tab switching remain intact. Hope this helps.
setOffscreenPageLimit 就是这个问题的答案。如果您希望自定义 backstack 框架正常运行,并且不希望在单击 tab2 时调用 tab3,则只需将该值设置为选项卡数即可。例如,如果您有 4 个选项卡,请设置 setOffScreePageLimit(4)。这意味着 Android 最初会刷新所有 4 个片段,这有点性能开销(您应该正确管理)。但是,您的后台堆栈和选项卡切换保持不变。希望这可以帮助。
回答by Mohsen mokhtari
In the onCreate() of your fragments, call setRetainInstance(true)
在片段的 onCreate() 中,调用 setRetainInstance(true)
回答by Suraj Vaishnav
In my case above suggestion does not work.
在我的情况下,上述建议不起作用。
To restrict recreation of fragment, what i did:
为了限制片段的娱乐,我做了什么:
In onCreateView
you can store inflated view in a global variable and initialize it only if it is null
, like in this code:
在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
}
Now if you are parsing some data and fill it into RecyclerView
or any other View
现在,如果您正在解析一些数据并将其填充到RecyclerView
或任何其他View
Make a global variable like in above code
apiDataReceived
Set it to true if you successfully parsed data.
Before apiCalls place a condition like this:
if (!apiDataReceived) { apiCalls() }
像上面的代码一样创建一个全局变量
apiDataReceived
如果您成功解析数据,请将其设置为 true。
在 apiCalls 之前放置这样的条件:
如果 (!apiDataReceived) { apiCalls() }
So if apiCalls() would be called only if data is not parsed.
因此,如果仅在未解析数据时才调用 apiCalls()。
Do your http calls and parsing or any other thing in method which called after onCreateView
like onStart
做你的 http 调用和解析或任何其他onCreateView
类似调用的方法onStart
The above code is in kotlin, If you are facing any issue, let me know in comments.
上面的代码在 kotlin 中,如果您遇到任何问题,请在评论中告诉我。