1

ReactネイティブアプリでFirebaseでサポートされているRecyclerViewを統合することを試しています。ハードコードされたデータでは正常に動作しますが、動的にロードされた行を挿入し、RecyclerView.AdapterでnotifyItemInserted()またはnotifyDataSetChanged()を呼び出すと、RecyclerView自体に変更が反映されません。これは、アプリケーションのリフレッシュボタンがタップされるまで、最初のブランクビューとして現れます。これは、RecyclerViewをReact Nativeサイドから再描画する唯一の効果、またはスクロールや画面の向きの変更までです。Reactネイティブの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のルートビューはonlayoutが空方法であるReactRootViewあります。

RecyclerViewでnotifyDatasetChangedを呼び出すと、実際にはその子を再レイアウトするように要求するのはlayoutです。そして、レイアウトメソッドはsuper.layoutを呼び出し、最初に全体のビューツリーを移動します。そのため、ルートビューがReactRootViewの場合は問題ありません。

手動でRecyclerView.onlayout(boolean changed, int l, int t, int r, int b)を呼び出して、子の再レイアウトをトリガーしてnotifyDatasetChangedの作業を行うことができます。

関連する問題