我的ViewPager2中管理着3个Fragment,其中两个Fragment都有RecyclerView,这两个RecyclerView都管理着同样的实时更新的item数据,但是我发现在ViewPager2中当RecyclerView有item数据实时更新出来时所有的item都会闪烁或者发生奇怪的偏移。但是这一系列的现象在ViewPager中都没有出现到,我对这个现象进行了一系列的追溯,有了一点眉目,但不知道该如何解决这个问题,下面展示3种我调试的现象,欢迎大家来参观讨论,我挺期待用上ViewPager2的:
现象1(ViewPager2的问题现象):
Clipchamp.mp4
<com .google.android.material.appbar.AppBarLayout
android : id =" @+id/app_bar_layout"
android : layout_width =" match_parent"
android : layout_height =" wrap_content"
android : theme =" @style/Theme.AppCompat.DayNight"
app : layout_constraintTop_toTopOf =" parent"
app : layout_constraintLeft_toLeftOf =" parent"
app : layout_constraintRight_toRightOf =" parent"
app : layout_constraintBottom_toTopOf =" @+id/view_pager2" >
<com .google.android.material.tabs.TabLayout
android : id =" @+id/tab_layout"
android : layout_width =" match_parent"
android : layout_height =" 20dp" />
</com .google.android.material.appbar.AppBarLayout>
<androidx .viewpager2.widget.ViewPager2
android : id =" @+id/view_pager2"
android : layout_width =" match_parent"
android : layout_height =" 0dp"
android : orientation =" horizontal"
app : layout_constraintTop_toBottomOf =" @+id/app_bar_layout"
app : layout_constraintBottom_toTopOf =" @+id/sendMsgEt"
app : layout_constraintLeft_toLeftOf =" parent"
app : layout_constraintRight_toRightOf =" parent" />
viewPager2 = findViewById (R .id .view_pager2 );
tabLayout = findViewById (R .id .tab_layout );
//禁止ViewPager的左右滑动
viewPager2 .setUserInputEnabled (false );
viewPager2 .setOffscreenPageLimit (3 );
viewPager2 .setAdapter (new FragmentStateAdapter (supportFragmentManager , getLifecycle ()) {
@ NonNull
@ Override
public Fragment createFragment (int position ) {
switch (position ){
case 0 :
chatFragment = new mChatFragment ();
return chatFragment ;
case 1 :
terminalFragment = new mTerminalFragment ();
return terminalFragment ;
case 2 :
controlFragment = new mControlFragment ();
return controlFragment ;
default :
return null ;
}
}
@ Override
public int getItemCount () {
return 3 ;
}
});
tabLayoutMediator = new TabLayoutMediator (tabLayout , viewPager2 , new TabLayoutMediator .TabConfigurationStrategy () {
@ Override
public void onConfigureTab (@ NonNull TabLayout .Tab tab , int position ) {
//ViewPager选中时对Tab执行的代码
switch (position ){
case 0 :
tab .setText ("对话模式" );
break ;
case 1 :
tab .setText ("终端模式" );
break ;
case 2 :
tab .setText ("控件模式" );
break ;
default : break ;
}
}
});
tabLayoutMediator .attach ();
messageRecyclerView .addOnLayoutChangeListener (new View .OnLayoutChangeListener () {
@ Override
public void onLayoutChange (View v , int left , int top , int right , int bottom , int oldLeft , int oldTop , int oldRight , int oldBottom ) {
Log .e ("RecyclerViewLayout" ,"newTop:" +top +"\t newBottom:" +bottom );
}
});
OnLayoutChangeListener中捕获的日志如下(RecyclerView每新增一个item其中的newBottom都会发生两次改变先是0后面变成1953,我认为导致这个问题的原因就在于newBottom改变成了0):
于是我对令newBottom变成0的代码经行了追溯,发现下面两处有可能是导致newBottom变成0的代码(我能力有限,只能debug后建立断点后一点点往回看,希望理解),令我好奇的是下面两处代码在newBottom变成1953时并没有被执行,这也让我更加肯定下面两处代码把newBottom变成了0:
现象2(把xml布局文件中ViewPager2的layout_height="0dp"修改成固定的"350dp",其它部分代码同上)
Clipchamp.mp4
修改后的xml代码如下
<androidx .viewpager2.widget.ViewPager2
android : id =" @+id/view_pager2"
android : layout_width =" match_parent"
android : layout_height =" 350dp"
android : orientation =" horizontal"
app : layout_constraintTop_toBottomOf =" @+id/app_bar_layout"
app : layout_constraintBottom_toTopOf =" @+id/sendMsgEt"
app : layout_constraintLeft_toLeftOf =" parent"
app : layout_constraintRight_toRightOf =" parent" />
捕获日志如下(可见RecyclerView每新增一个item其中的newBottom只更新了一次,且都为963,可以说没有改变,一切正常,但这样的固定值的布局显然不是我想要的):
现象3(把ViewPager2改回用ViewPager)
Clipchamp.mp4
<com .google.android.material.appbar.AppBarLayout
android : id =" @+id/app_bar_layout"
android : layout_width =" match_parent"
android : layout_height =" wrap_content"
android : theme =" @style/Theme.AppCompat.DayNight"
app : layout_constraintTop_toTopOf =" parent"
app : layout_constraintLeft_toLeftOf =" parent"
app : layout_constraintRight_toRightOf =" parent"
app : layout_constraintBottom_toTopOf =" @+id/view_pager" >
<com .google.android.material.tabs.TabLayout
android : id =" @+id/tab_layout"
android : layout_width =" match_parent"
android : layout_height =" 20dp" />
</com .google.android.material.appbar.AppBarLayout>
<androidx .viewpager.widget.ViewPager
android : id =" @+id/view_pager"
android : layout_width =" match_parent"
android : layout_height =" 0dp"
android : orientation =" horizontal"
app : layout_constraintTop_toBottomOf =" @+id/app_bar_layout"
app : layout_constraintBottom_toTopOf =" @+id/sendMsgEt"
app : layout_constraintLeft_toLeftOf =" parent"
app : layout_constraintRight_toRightOf =" parent" />
ViewPager viewPager = findViewById (R .id .view_pager );
viewPager .setOffscreenPageLimit (3 );
viewPager .setAdapter (new FragmentPagerAdapter (supportFragmentManager ) {
@ NonNull
@ Override
public Fragment getItem (int position ) {
switch (position ){
case 0 :
chatFragment = new mChatFragment ();
return chatFragment ;
case 1 :
terminalFragment = new mTerminalFragment ();
return terminalFragment ;
case 2 :
controlFragment = new mControlFragment ();
return controlFragment ;
default :
return null ;
}
}
@ Override
public int getCount () {
return 3 ;
}
@ Override
public CharSequence getPageTitle (int position ){
switch (position ){
case 0 :
return "对话模式" ;
case 1 :
return "终端模式" ;
case 2 :
return "控件模式" ;
default :
return null ;
}
}
});
TabLayout tabLayout = findViewById (R .id .tab_layout );
tabLayout .setupWithViewPager (viewPager );
捕获日志如下(一切正常):
最后贴上RecyclerView的item更新代码
private void refreshMsgUI (){
((AppCompatActivity )context ).runOnUiThread (()->{
terminalFragment .recyclerViewAdapter .notifyItemInserted (terminalFragment .recyclerViewAdapter .getItemCount ()-1 );
if (isTerScrollToBottom ) {
terminalFragment .messageRecyclerView .scrollToPosition (terminalFragment .recyclerViewAdapter .getItemCount ()-1 );
}
chatFragment .recyclerViewAdapter .notifyItemInserted (chatFragment .recyclerViewAdapter .getItemCount ()-1 );
if (isChatScrollToBottom ) {
chatFragment .messageRecyclerView .scrollToPosition (chatFragment .recyclerViewAdapter .getItemCount ()-1 );
}
});
}
我的ViewPager2中管理着3个Fragment,其中两个Fragment都有RecyclerView,这两个RecyclerView都管理着同样的实时更新的item数据,但是我发现在ViewPager2中当RecyclerView有item数据实时更新出来时所有的item都会闪烁或者发生奇怪的偏移。但是这一系列的现象在ViewPager中都没有出现到,我对这个现象进行了一系列的追溯,有了一点眉目,但不知道该如何解决这个问题,下面展示3种我调试的现象,欢迎大家来参观讨论,我挺期待用上ViewPager2的:
现象1(ViewPager2的问题现象):
Clipchamp.mp4
OnLayoutChangeListener中捕获的日志如下(RecyclerView每新增一个item其中的newBottom都会发生两次改变先是0后面变成1953,我认为导致这个问题的原因就在于newBottom改变成了0):



于是我对令newBottom变成0的代码经行了追溯,发现下面两处有可能是导致newBottom变成0的代码(我能力有限,只能debug后建立断点后一点点往回看,希望理解),令我好奇的是下面两处代码在newBottom变成1953时并没有被执行,这也让我更加肯定下面两处代码把newBottom变成了0:
现象2(把xml布局文件中ViewPager2的layout_height="0dp"修改成固定的"350dp",其它部分代码同上)
Clipchamp.mp4
修改后的xml代码如下
捕获日志如下(可见RecyclerView每新增一个item其中的newBottom只更新了一次,且都为963,可以说没有改变,一切正常,但这样的固定值的布局显然不是我想要的):

现象3(把ViewPager2改回用ViewPager)
Clipchamp.mp4
捕获日志如下(一切正常):

最后贴上RecyclerView的item更新代码