1

我正在试验在React Native应用程序中集成Firebase支持的RecyclerView。对于硬编码数据,它工作得很好,但是在插入动态加载的行并在RecyclerView.Adapter上调用notifyItemInserted()或notifyDataSetChanged()时,RecyclerView本身并不反映更改。直到应用程序的刷新按钮被点击后,它才会以初始空白视图的形式出现,它具有从React Native侧重新呈现RecyclerView,或直到滚动或屏幕方向更改的唯一效果。React Native中的RecyclerView:notifyItemInserted()和notifyDataSetChanged()不起作用

在阅读本网站上关于类似问题(涉及React Native并且尝试了大多数常见解决方案)之后,我猜这个问题与React Native特别相关。

鉴于React Native的列表视图实施中持续存在的性能问题,寻找解决方案可能对许多人有所帮助。

public class PostsAdapter extends RecyclerView.Adapter<PostsAdapter.ViewHolder> { 

    ArrayList<Post> mDataset; 

    public PostsAdapter(ArrayList<Post> list){ 
     mDataset = list; 
    } 

    public static class ViewHolder extends RecyclerView.ViewHolder { 
     public LinearLayout mPostView; 
     public ViewHolder(LinearLayout v) { 
      super(v); 
      mPostView = v; 
     } 
    } 

    @Override 
    public PostsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, 
                int viewType) { 
     LinearLayout v = (LinearLayout) LayoutInflater.from(parent.getContext()) 
       .inflate(R.layout.post, parent, false); 
     ViewHolder vh = new ViewHolder(v); 
     return vh; 
    } 

    @Override 
    public void onBindViewHolder(ViewHolder holder, int position) { 
     TextView tv = (TextView) holder.mPostView.findViewById(R.id.title); 
     tv.setText(mDataset.get(position).title); 
    } 

    @Override 
    public int getItemCount() { 
     return mDataset.size(); 
    } 

} 

public class RNPostsViewManager extends SimpleViewManager{ 
    private ArrayList<Post> mDataset = new ArrayList<>(); 
    public static final String REACT_CLASS = "AndroidPostsView"; 
    private RecyclerView mRecyclerView; 
    private PostsAdapter mAdapter; 
    private RecyclerView.LayoutManager mLayoutManager; 
    private DatabaseReference mDatabase; 
    private Query initialDataQuery; 
    private ChildEventListener initialDataListener; 

    @Override 
    public String getName() { 
     return REACT_CLASS; 
    } 

    @UiThread 
    public void addPost (Post p){ 
     mDataset.add(p); 
     mAdapter.notifyItemInserted(mDataset.size()-1); 
    } 

    @Override 
    public RecyclerView createViewInstance(ThemedReactContext context) { 

     mAdapter = new PostsAdapter(mDataset); 

     mRecyclerView = new RecyclerView(context){ 
      @Override 
      protected void onAttachedToWindow() { 
       super.onAttachedToWindow(); 
       initialDataQuery.addChildEventListener(initialDataListener); 
      } 
     }; 

     mLayoutManager = new LinearLayoutManager(context.getCurrentActivity(), LinearLayoutManager.VERTICAL, false); 
     DividerItemDecoration mDecoration = new DividerItemDecoration(context, 1); 
     mDecoration.setDrawable(ContextCompat.getDrawable(context.getCurrentActivity(), R.drawable.sep)); 
     mRecyclerView.setLayoutManager(mLayoutManager); 
     mRecyclerView.addItemDecoration(mDecoration); 
     mRecyclerView.setItemAnimator(new DefaultItemAnimator()); 
     mRecyclerView.setAdapter(mAdapter); 

     mDatabase = FirebaseDatabase.getInstance().getReference(); 
     initialDataQuery = mDatabase.child("wp-posts").orderByChild("unixPostDate").limitToFirst(100); 
     initialDataListener = new ChildEventListener() { 
      @Override 
      public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) { 
       Post p = dataSnapshot.getValue(Post.class); 
       addPost(p); 
      } 

      @Override 
      public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) { 
      } 
      @Override 
      public void onChildRemoved(DataSnapshot dataSnapshot) { 
      } 
      @Override 
      public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) { 
      } 
      @Override 
      public void onCancelled(DatabaseError databaseError) { 
      } 
     }; 

     return mRecyclerView; 
    } 

} 

// layout file post.xml 
<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 

    android:background="@android:color/background_light" 
    android:clickable="true" 
    android:focusable="true" 
    android:gravity="center_vertical" 
    android:orientation="horizontal" 
    android:padding="10dp" 
    android:weightSum="1"> 

    <Button 
     android:id="@+id/button" 
     style="@style/Widget.AppCompat.Button.Small" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_marginRight="20dp" 
     android:background="@android:drawable/ic_menu_more" 
     android:gravity="center_vertical" /> 

    <LinearLayout 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_gravity="fill_vertical" 
     android:orientation="horizontal" 
     android:weightSum="1"> 

     <TextView 
      android:id="@+id/title" 
      android:layout_width="0dp" 
      android:layout_height="wrap_content" 
      android:layout_gravity="fill_vertical" 
      android:layout_weight="1" 
      android:gravity="top" 
      android:text="TextView" 
      android:textColor="@color/title" 
      android:textStyle="bold" /> 
    </LinearLayout> 

</LinearLayout> 
+0

您可以在'addPost(p)'方法中插入日志吗? –

+0

那里应该记录什么? – Isaac16

+0

刚刚添加了RecyclerView.AdapterDataObserver并从中记录。 onChanged()方法从不调用。 – Isaac16

回答

1

ReactNative中的根视图是ReactRootView,其中onlayout是一个空方法。

当在RecyclerView中调用notifyDatasetChanged时,它实际上是要求layout来重新布局它的孩子。布局方法将调用super.layout首先遍历整个视图树。所以当根视图是ReactRootView时没有问题。

您可以手动呼叫RecyclerView.onlayout(boolean changed, int l, int t, int r, int b)来触发其子节点重新布局,以使notifyDatasetChanged正常工作。

相关问题