Tab+ViewPager 未更新而是显示奇怪的警告 expected state 3 found 2
Tab+ViewPager not updating instead shows weird warning expected state 3 found 2
我有一个主要活动,其中包括一个带 ViewPager 的 TabLayout
我添加了 3 个选项卡,每个选项卡都有单独的片段,其中包含一个 recyclerview,并且这些 recyclerviews 有一个复选框,每当我滑动 viewpager(我保存选中共享偏好中的位置并通过共享偏好更新)。
我的问题是每当我选中 tab1 中的复选框时,tab2 都不是 updating/refreshing,直到我向下滚动 Recyclerview。 tab3 工作正常。
我也在 logcat 中收到一个奇怪的警告。
03-05 09:35:53.345 4317-4327/com.example.rubin W/art: Suspending all threads took: 6.805ms
03-05 09:35:58.310 4317-4317/com.example.rubin W/FragmentManager: moveToState: Fragment state for Tab3{10a5f1f0 #2 id=0x7f0d00b6} not updated inline; expected state 3 found 2
03-05 09:36:01.363 4317-4317/com.example.rubin W/FragmentManager: moveToState: Fragment state for Tab1{2d9aa887 #1 id=0x7f0d00b6} not updated inline; expected state 3 found 2
我的 PagerAdapter
public class PagerAdapter1 extends FragmentStatePagerAdapter {
int mNumOfTabs;
public PagerAdapter1(FragmentManager fm, int NumOfTabs) {
super(fm);
this.mNumOfTabs = NumOfTabs;
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new Tab1();
case 1:
return new Tab2();
case 2:
return new Tab3();
default:
return null;
}
}
@Override
public int getCount() {
return mNumOfTabs;
}
}
Tablayout OnPageChangelistener
final PagerAdapter1 adapter = new PagerAdapter1
(getSupportFragmentManager(), tabLayout1.getTabCount(), getApplicationContext());
viewPager1.setAdapter(adapter);
viewPager1.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout1));
tabLayout1.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager1.setCurrentItem(tab.getPosition());
adapter.notifyDataSetChanged();
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
每个片段的代码。
public class Tab1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.home_tab1_recycler, container, false);
RecyclerView rv = (RecyclerView) v.findViewById(R.id.home_recyclerview);
LinearLayoutManager llm = new LinearLayoutManager(getContext());
rv.setLayoutManager(llm);
rv.setHasFixedSize(true); // to improve performance
rv.setAdapter(new HomeManager()); // the projectdatabase manager is assigner to the RV
return v;
}
public class HomeManager extends RecyclerView.Adapter<HomeManager.RecyclerViewHolder> {
int Length,h;
View v1;
ArrayList<String> PROJECT_ID = new ArrayList<String>();
Set<String> set;
List<String> selected;
public class RecyclerViewHolder extends RecyclerView.ViewHolder {
CheckBox mCheck;
RecyclerViewHolder(final View itemView) {
super(itemView);
mCheck = (CheckBox) itemView.findViewById(R.id.PROJECT_fav);
SharedPreferences pref = getContext().getSharedPreferences("MirSP", Context.MODE_PRIVATE);
set = pref.getStringSet("FAV", null);
if (set != null) {
selected = new ArrayList<String>(set);
} else {
selected = new ArrayList<String>();
}
mCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
h = getAdapterPosition();
check = PROJECT_ID.get(h); // for saving the project id from json.
if (selected.contains(check)) {
selected.remove(check);
mCheck.setBackgroundResource(R.drawable.ic_favorite_white1_24dp);
Snackbar snackbar = Snackbar.make(v, "Property Unfavorited", Snackbar.LENGTH_SHORT);
snackbar.show();
} else {
selected.add(check);
mCheck.setBackgroundResource(R.drawable.ic_favorite_white_24dp);
Snackbar snackbar = Snackbar.make(v, "Property Favorited", Snackbar.LENGTH_SHORT);
snackbar.show();
}
Log.e("HF update checked", String.valueOf(selected));
Set<String> set = new HashSet<String>();
set.addAll(selected);
SharedPreferences pref = getContext().getSharedPreferences("MirSP", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
editor.putStringSet("FAV", set);
editor.commit();
}
}
});
@Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
v1 = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recyclerview_item, viewGroup, false);
return new RecyclerViewHolder(v1);
}
@Override
public void onBindViewHolder(final RecyclerViewHolder viewHolder, int i) {
SharedPreferences pref = getContext().getSharedPreferences("MirSP", Context.MODE_PRIVATE);
set = pref.getStringSet("FAV", null);
if (set != null) {
selected = new ArrayList<String>(set);
} else {
selected = new ArrayList<String>();
}
Log.e("HF update UI", String.valueOf(selected));
if (String.valueOf(selected).contains(String.valueOf(PROJECT_ID.get(i)))) {
viewHolder.mCheck.setBackgroundResource(R.drawable.ic_favorite_white_24dp);
} else {
viewHolder.mCheck.setBackgroundResource(R.drawable.ic_favorite_white1_24dp);
}
}
@Override
public int getItemCount() {
//Code for Total length of json
return Length;
}
FragmentPagerAdapter
调用 setUserVisibleHint(true|false)
在活动片段的邻域上,这会改变该片段的状态。
这至少是 "weird warning messages" 的答案,但它可能无法解决您的问题。
关于您关于如何解决该警告消息的评论,我创建了自己的 FragmentPagerAdapter,如下所示:
public abstract class AbstractTabPagerAdapter extends PagerAdapter {
private static final String TAG = AbstractTabPagerAdapter.class.getCanonicalName();
private final FragmentManager mFragmentManager;
private FragmentTransaction mCurTransaction;
private Fragment mCurrentPrimaryItem = null;
public AbstractTabPagerAdapter(FragmentManager fragmentManager) {
mFragmentManager = fragmentManager;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
if (mCurTransaction == null) {
throw new IllegalArgumentException("current transaction must not be null");
}
String fragmentTag = makeFragmentName(container.getId(), position);
Fragment fragment = (Fragment) mFragmentManager.findFragmentByTag(fragmentTag);
if (fragment != null) {
mCurTransaction.attach(fragment);
Log.d(TAG, "Attaching existing fragment " + fragment + " at position " + position);
//mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), position));
} else {
fragment = getItem(position);
mCurTransaction.add(container.getId(), fragment, fragmentTag);
Log.d(TAG, "Attaching new fragment " + fragment + " at position " + position);
}
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
//fragment.setUserVisibleHint(false);
}
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (mCurTransaction == null) {
throw new IllegalArgumentException("current transaction must not be null");
}
mCurTransaction.detach((Fragment) object);
//mCurTransaction.remove((Fragment)object);
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
//super.setPrimaryItem(container, position, object);
Fragment fragment = (Fragment) object;
if (fragment != mCurrentPrimaryItem) {
Log.d(TAG, "set Primary item " + position + " to " + fragment);
if (mCurrentPrimaryItem != null) {
mCurrentPrimaryItem.setMenuVisibility(false);
// this command unexpectedly changes the state of the fragment which leads to a warning message and possible some strange behaviour
//mCurrentPrimaryItem.setUserVisibleHint(false);
}
if (fragment != null) {
fragment.setMenuVisibility(true);
//fragment.setUserVisibleHint(true);
}
mCurrentPrimaryItem = fragment;
}
}
@Override
public boolean isViewFromObject(View view, Object fragment) {
return ((Fragment) fragment).getView() == view;
}
public abstract Fragment getItem(int position);
@Override
public void startUpdate(ViewGroup container) {
super.startUpdate(container);
if (mCurTransaction != null) {
throw new IllegalArgumentException("current transaction must not be null");
}
mCurTransaction = mFragmentManager.beginTransaction();
Log.d(TAG, "FragmentTransaction started");
}
@Override
public void finishUpdate(ViewGroup container) {
if (mCurTransaction != null) {
mCurTransaction.commit();
mCurTransaction = null;
//mFragmentManager.executePendingTransactions();
Log.d(TAG, "FragmentTransaction committed");
} else {
throw new IllegalArgumentException("current transaction must not be null");
}
}
private String makeFragmentName(int viewId, int position) {
if (viewId <= 0)
throw new IllegalArgumentException("viewId " + viewId);
return "tabpageradptr:" + getPageTitle(position) + ":" + viewId + ":" + position;
}
}
警告消息现在消失了,目前我没有遇到任何缺陷 - 但我仍在研究中。
不重要。这只是一个警告。
请尝试将 ViewPager
布局的背景更改为空(不设置背景)。
这个问题我花了很多时间。问题是您尝试在 OnPageChangeListener 侦听器中更新 viewpager,它会抛出警告
not update in line
解决方案:
所有数据更改和更新视图都应调用 OnPageChangeListener,
例如:片段的 onCreateView
我的警告消失了! viewpager 更新完全
已经晚了,但我想出了使用 FragmentPagerAdapter 的最佳方法,虽然它没有消除警告,但它解决了目的,如果有人能告诉我该警告的实际含义以及实际导致警告的原因,它会符合我的最大利益。
首先在viewpager创建方法中使用的所有片段如下。
public void updateView() {
//Update whatever views or data you want to update
}
同时覆盖 FragmentPagerAdapter 中使用的方法 setUserVisibleHint 以通知用户片段是否可见。
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
this.isVisibleToUser = isVisibleToUser;
super.setUserVisibleHint(isVisibleToUser);
}
最后在您的片段中添加以下代码以在片段可见时更新 view/date。
@Override
public void onStart() {
if (isVisibleToUser)
updateView();
}
然后在您的 TabFragment 或 Activity
中实现它
viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
switch (position) {
case 0: {
((Fragment) mFragmentList.get(0)).updateView();
break;
}
case 1: {
((Fragment) mFragmentList.get(1)).updateView();
break;
}
}
}
这将负责持续更新数据,无论是滑动还是单击选项卡,如果有人发现任何问题或错误,请发表评论并让我知道或随时编辑解决方案
并且我投票赞成上面的解决方案,它为我提供了应用此解决方案的方法。谢谢@mikes
"W/FragmentManager: moveToState: … expected state 3 found 2"
警告可以忽略并已在支持库 v24.0.0 中删除。
引用官方开发者answer:
You don't need to do anything additional; this is an informational log message only.
[…]
The log itself as described here does not affect behavior. Please open
a new bug if you are having other issues; conflating different issues
in the same bug makes those separate issues more difficult to track.
Closing comments as the log issue has been resolved for a future
release.
在视图寻呼机中同时加载相邻的标签。因此,您在选项卡 1 中的操作不会反映在选项卡 2 中,因为它已经加载。您应该使用广播接收器来解决这个问题。在选项卡 1 中广播事件并在选项卡 2 中接收事件
我有一个主要活动,其中包括一个带 ViewPager 的 TabLayout
我添加了 3 个选项卡,每个选项卡都有单独的片段,其中包含一个 recyclerview,并且这些 recyclerviews 有一个复选框,每当我滑动 viewpager(我保存选中共享偏好中的位置并通过共享偏好更新)。
我的问题是每当我选中 tab1 中的复选框时,tab2 都不是 updating/refreshing,直到我向下滚动 Recyclerview。 tab3 工作正常。 我也在 logcat 中收到一个奇怪的警告。
03-05 09:35:53.345 4317-4327/com.example.rubin W/art: Suspending all threads took: 6.805ms
03-05 09:35:58.310 4317-4317/com.example.rubin W/FragmentManager: moveToState: Fragment state for Tab3{10a5f1f0 #2 id=0x7f0d00b6} not updated inline; expected state 3 found 2
03-05 09:36:01.363 4317-4317/com.example.rubin W/FragmentManager: moveToState: Fragment state for Tab1{2d9aa887 #1 id=0x7f0d00b6} not updated inline; expected state 3 found 2
我的 PagerAdapter
public class PagerAdapter1 extends FragmentStatePagerAdapter {
int mNumOfTabs;
public PagerAdapter1(FragmentManager fm, int NumOfTabs) {
super(fm);
this.mNumOfTabs = NumOfTabs;
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new Tab1();
case 1:
return new Tab2();
case 2:
return new Tab3();
default:
return null;
}
}
@Override
public int getCount() {
return mNumOfTabs;
}
}
Tablayout OnPageChangelistener
final PagerAdapter1 adapter = new PagerAdapter1
(getSupportFragmentManager(), tabLayout1.getTabCount(), getApplicationContext());
viewPager1.setAdapter(adapter);
viewPager1.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout1));
tabLayout1.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager1.setCurrentItem(tab.getPosition());
adapter.notifyDataSetChanged();
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
每个片段的代码。
public class Tab1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.home_tab1_recycler, container, false);
RecyclerView rv = (RecyclerView) v.findViewById(R.id.home_recyclerview);
LinearLayoutManager llm = new LinearLayoutManager(getContext());
rv.setLayoutManager(llm);
rv.setHasFixedSize(true); // to improve performance
rv.setAdapter(new HomeManager()); // the projectdatabase manager is assigner to the RV
return v;
}
public class HomeManager extends RecyclerView.Adapter<HomeManager.RecyclerViewHolder> {
int Length,h;
View v1;
ArrayList<String> PROJECT_ID = new ArrayList<String>();
Set<String> set;
List<String> selected;
public class RecyclerViewHolder extends RecyclerView.ViewHolder {
CheckBox mCheck;
RecyclerViewHolder(final View itemView) {
super(itemView);
mCheck = (CheckBox) itemView.findViewById(R.id.PROJECT_fav);
SharedPreferences pref = getContext().getSharedPreferences("MirSP", Context.MODE_PRIVATE);
set = pref.getStringSet("FAV", null);
if (set != null) {
selected = new ArrayList<String>(set);
} else {
selected = new ArrayList<String>();
}
mCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
h = getAdapterPosition();
check = PROJECT_ID.get(h); // for saving the project id from json.
if (selected.contains(check)) {
selected.remove(check);
mCheck.setBackgroundResource(R.drawable.ic_favorite_white1_24dp);
Snackbar snackbar = Snackbar.make(v, "Property Unfavorited", Snackbar.LENGTH_SHORT);
snackbar.show();
} else {
selected.add(check);
mCheck.setBackgroundResource(R.drawable.ic_favorite_white_24dp);
Snackbar snackbar = Snackbar.make(v, "Property Favorited", Snackbar.LENGTH_SHORT);
snackbar.show();
}
Log.e("HF update checked", String.valueOf(selected));
Set<String> set = new HashSet<String>();
set.addAll(selected);
SharedPreferences pref = getContext().getSharedPreferences("MirSP", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
editor.putStringSet("FAV", set);
editor.commit();
}
}
});
@Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
v1 = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recyclerview_item, viewGroup, false);
return new RecyclerViewHolder(v1);
}
@Override
public void onBindViewHolder(final RecyclerViewHolder viewHolder, int i) {
SharedPreferences pref = getContext().getSharedPreferences("MirSP", Context.MODE_PRIVATE);
set = pref.getStringSet("FAV", null);
if (set != null) {
selected = new ArrayList<String>(set);
} else {
selected = new ArrayList<String>();
}
Log.e("HF update UI", String.valueOf(selected));
if (String.valueOf(selected).contains(String.valueOf(PROJECT_ID.get(i)))) {
viewHolder.mCheck.setBackgroundResource(R.drawable.ic_favorite_white_24dp);
} else {
viewHolder.mCheck.setBackgroundResource(R.drawable.ic_favorite_white1_24dp);
}
}
@Override
public int getItemCount() {
//Code for Total length of json
return Length;
}
FragmentPagerAdapter
调用 setUserVisibleHint(true|false)
在活动片段的邻域上,这会改变该片段的状态。
这至少是 "weird warning messages" 的答案,但它可能无法解决您的问题。
关于您关于如何解决该警告消息的评论,我创建了自己的 FragmentPagerAdapter,如下所示:
public abstract class AbstractTabPagerAdapter extends PagerAdapter {
private static final String TAG = AbstractTabPagerAdapter.class.getCanonicalName();
private final FragmentManager mFragmentManager;
private FragmentTransaction mCurTransaction;
private Fragment mCurrentPrimaryItem = null;
public AbstractTabPagerAdapter(FragmentManager fragmentManager) {
mFragmentManager = fragmentManager;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
if (mCurTransaction == null) {
throw new IllegalArgumentException("current transaction must not be null");
}
String fragmentTag = makeFragmentName(container.getId(), position);
Fragment fragment = (Fragment) mFragmentManager.findFragmentByTag(fragmentTag);
if (fragment != null) {
mCurTransaction.attach(fragment);
Log.d(TAG, "Attaching existing fragment " + fragment + " at position " + position);
//mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), position));
} else {
fragment = getItem(position);
mCurTransaction.add(container.getId(), fragment, fragmentTag);
Log.d(TAG, "Attaching new fragment " + fragment + " at position " + position);
}
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
//fragment.setUserVisibleHint(false);
}
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (mCurTransaction == null) {
throw new IllegalArgumentException("current transaction must not be null");
}
mCurTransaction.detach((Fragment) object);
//mCurTransaction.remove((Fragment)object);
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
//super.setPrimaryItem(container, position, object);
Fragment fragment = (Fragment) object;
if (fragment != mCurrentPrimaryItem) {
Log.d(TAG, "set Primary item " + position + " to " + fragment);
if (mCurrentPrimaryItem != null) {
mCurrentPrimaryItem.setMenuVisibility(false);
// this command unexpectedly changes the state of the fragment which leads to a warning message and possible some strange behaviour
//mCurrentPrimaryItem.setUserVisibleHint(false);
}
if (fragment != null) {
fragment.setMenuVisibility(true);
//fragment.setUserVisibleHint(true);
}
mCurrentPrimaryItem = fragment;
}
}
@Override
public boolean isViewFromObject(View view, Object fragment) {
return ((Fragment) fragment).getView() == view;
}
public abstract Fragment getItem(int position);
@Override
public void startUpdate(ViewGroup container) {
super.startUpdate(container);
if (mCurTransaction != null) {
throw new IllegalArgumentException("current transaction must not be null");
}
mCurTransaction = mFragmentManager.beginTransaction();
Log.d(TAG, "FragmentTransaction started");
}
@Override
public void finishUpdate(ViewGroup container) {
if (mCurTransaction != null) {
mCurTransaction.commit();
mCurTransaction = null;
//mFragmentManager.executePendingTransactions();
Log.d(TAG, "FragmentTransaction committed");
} else {
throw new IllegalArgumentException("current transaction must not be null");
}
}
private String makeFragmentName(int viewId, int position) {
if (viewId <= 0)
throw new IllegalArgumentException("viewId " + viewId);
return "tabpageradptr:" + getPageTitle(position) + ":" + viewId + ":" + position;
}
}
警告消息现在消失了,目前我没有遇到任何缺陷 - 但我仍在研究中。
不重要。这只是一个警告。
请尝试将 ViewPager
布局的背景更改为空(不设置背景)。
这个问题我花了很多时间。问题是您尝试在 OnPageChangeListener 侦听器中更新 viewpager,它会抛出警告
not update in line
解决方案:
所有数据更改和更新视图都应调用 OnPageChangeListener, 例如:片段的 onCreateView
我的警告消失了! viewpager 更新完全
已经晚了,但我想出了使用 FragmentPagerAdapter 的最佳方法,虽然它没有消除警告,但它解决了目的,如果有人能告诉我该警告的实际含义以及实际导致警告的原因,它会符合我的最大利益。
首先在viewpager创建方法中使用的所有片段如下。
public void updateView() { //Update whatever views or data you want to update }
同时覆盖 FragmentPagerAdapter 中使用的方法 setUserVisibleHint 以通知用户片段是否可见。
@Override public void setUserVisibleHint(boolean isVisibleToUser) { this.isVisibleToUser = isVisibleToUser; super.setUserVisibleHint(isVisibleToUser); }
最后在您的片段中添加以下代码以在片段可见时更新 view/date。
@Override public void onStart() { if (isVisibleToUser) updateView(); }
然后在您的 TabFragment 或 Activity
中实现它viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { switch (position) { case 0: { ((Fragment) mFragmentList.get(0)).updateView(); break; } case 1: { ((Fragment) mFragmentList.get(1)).updateView(); break; } } }
这将负责持续更新数据,无论是滑动还是单击选项卡,如果有人发现任何问题或错误,请发表评论并让我知道或随时编辑解决方案
并且我投票赞成上面的解决方案,它为我提供了应用此解决方案的方法。谢谢@mikes
"W/FragmentManager: moveToState: … expected state 3 found 2"
警告可以忽略并已在支持库 v24.0.0 中删除。
引用官方开发者answer:
You don't need to do anything additional; this is an informational log message only. […]
The log itself as described here does not affect behavior. Please open a new bug if you are having other issues; conflating different issues in the same bug makes those separate issues more difficult to track.
Closing comments as the log issue has been resolved for a future release.
在视图寻呼机中同时加载相邻的标签。因此,您在选项卡 1 中的操作不会反映在选项卡 2 中,因为它已经加载。您应该使用广播接收器来解决这个问题。在选项卡 1 中广播事件并在选项卡 2 中接收事件