RecyclerView在Fragment上不可见。

huangapple go评论81阅读模式
英文:

RecyclerView isn't visible on Fragment

问题

你的RecyclerView在Fragment中无法正常显示卡片,即使你已经尝试过在Activity中也不起作用。这里有一些可能的问题和建议:

  1. 确保你在Fragment的布局文件(frag_cart.xml)中的RecyclerView配置正确。检查layout_widthlayout_height是否设置为适当的值,以及RecyclerView是否位于正确的位置。

  2. 确保你的ViewModel(CartItemViewModel)在Fragment中正确初始化,而且LiveData被观察。检查ViewModel的初始化是否没有问题,而且观察者(Observer)被正确设置。

  3. 确保你的数据在ViewModel中被正确加载并传递给Adapter。在观察LiveData的onChanged回调中,确保adapter.setCartItems(cartItems)被调用。

  4. 检查RecyclerView的布局文件(sample_product_item.xml)是否正确,包括内部视图的ID是否匹配适配器中的代码。

  5. onCreateView方法中,你可以添加一些日志输出来检查是否正确调用了onCreateView以及LiveData的观察是否有数据返回。

如果你检查了上述几个方面,但问题仍然存在,可以提供更多关于你的布局和代码的信息,以便更具体地帮助你解决问题。

英文:

I'm following this tutorial to implement a Room database. Everything is the same except mine is on a Fragment. There are no errors and the RecyclerView cards aren't visible at all. (I'm still able to add cards dynamically when not using a RecyclerView)

I've already tried this on an Activity and it still doesn't work so I must have missed something as I'm not copying the entire code from the tutorial. Maybe it's something simple because I'm new to Android.

Adapter:

public class CartItemAdapter extends RecyclerView.Adapter<CartItemAdapter.CartItemHolder> {
    private List<CartItem> cartItems = new ArrayList<>();

    @NonNull
    @Override
    public CartItemHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.sample_product_item, parent, false);
        return new CartItemHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull CartItemHolder holder, int position) {
        CartItem currentCartItem = cartItems.get(position);
        holder.tvItemName.setText(currentCartItem.getItemName());
        holder.tvItemPrice.setText(currentCartItem.getItemPrice());
        holder.tvQuantity.setText(String.valueOf(currentCartItem.getQuantity()));
    }

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

    public void setCartItems(List<CartItem> cartItems) {
        this.cartItems = cartItems;
        notifyDataSetChanged();
    }

    class CartItemHolder extends RecyclerView.ViewHolder {
        private TextView tvItemName;
        private TextView tvItemPrice;
        private TextView tvQuantity;

        public CartItemHolder(@NonNull View itemView) {
            super(itemView);
            tvItemName = itemView.findViewById(R.id.itemName);
            tvItemPrice = itemView.findViewById(R.id.itemPrice);
            tvQuantity = itemView.findViewById(R.id.quantity);
        }
    }

}

ViewModel:

public class CartItemViewModel extends AndroidViewModel {
    private CartItemRepository repository;
    private LiveData<List<CartItem>> allCartItems;

    public CartItemViewModel(@NonNull Application application) {
        super(application);
        repository = new CartItemRepository(application);
        allCartItems = repository.getAllCartItems();
    }

    public void insert(CartItem cartItem) {
        repository.insert(cartItem);
    }

    public void update(CartItem cartItem) {
        repository.update(cartItem);
    }

    public void delete(CartItem cartItem) {
        repository.delete(cartItem);
    }

    public void deleteAllCartItems() {
        repository.deleteAll();
    }

    public LiveData<List<CartItem>> getAllCartItems() {
        return allCartItems;
    }
}

Fragment layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:animateLayoutChanges="true"
    android:orientation="vertical">

    <!--Views...-->

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/cart_recyclerview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@id/totalCard"
        android:layout_below="@id/titleCard"
        android:padding="8dp"
        tools:listitem="@layout/sample_product_item">

        <!-- cart items dynamically added here -->

    </androidx.recyclerview.widget.RecyclerView>

    <!--Views...-->

</RelativeLayout>

Fragment class:

    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    view = inflater.inflate(R.layout.frag_cart, container, false);
    RecyclerView recyclerView = view.findViewById(R.id.cart_recyclerview);
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        recyclerView.setHasFixedSize(true);
        final CartItemAdapter adapter = new CartItemAdapter();
        recyclerView.setAdapter(adapter);

        cartItemViewModel = new ViewModelProvider(getActivity(),
                ViewModelProvider.AndroidViewModelFactory.getInstance(getActivity().getApplication())).get(CartItemViewModel.class);
        cartItemViewModel.getAllCartItems().observe(getActivity(), new Observer<List<CartItem>>() {
            @Override
            public void onChanged(List<CartItem> cartItems) {
                adapter.setCartItems(cartItems);
                Log.i(TAG, "items set!");
            }
        });
    return view;
}

I've populated the database in CartItemDatabase

@Database(entities = {CartItem.class}, version = 1)
public abstract class CartItemDatabase extends RoomDatabase {

    private static CartItemDatabase instance;

    public abstract CartItemDao cartItemDao();

    public static synchronized CartItemDatabase getInstance(Context context) {
        if (instance == null) {
            instance = Room.databaseBuilder(context.getApplicationContext(),
                    CartItemDatabase.class, "cart_item_database")
                    .fallbackToDestructiveMigration()
                    .addCallback(roomCallback)
                    .build();
        }
        return instance;
    }

    private static RoomDatabase.Callback roomCallback = new RoomDatabase.Callback() {
        @Override
        public void onCreate(@NonNull SupportSQLiteDatabase db) {
            super.onCreate(db);
            new PopulateDbAsyncTask(instance).execute();
        }
    };

    private static class PopulateDbAsyncTask extends AsyncTask<Void, Void, Void> {
        private CartItemDao cartItemDao;

        private PopulateDbAsyncTask(CartItemDatabase db) {
            cartItemDao = db.cartItemDao();
        }

        @Override
        protected Void doInBackground(Void... voids) {
            cartItemDao.insert(new CartItem("Bread", "60", 2));
            cartItemDao.insert(new CartItem("Butter", "70", 1));
            return null;
        }
    }

}

What am I doing wrong?
Please ask me if more info is needed. Thanks in advance.

答案1

得分: 1

学会调试你的代码并准确定位错误。我解决了大多数错误都是通过调试。如果你不知道什么是调试或如何进行调试,你可以搜索一下。这非常简单,可以节省你解决问题的时间,也可以避免你提出问题。

我建议这样做是因为根据你描述的情况,我首先要检查的是我的RecyclerView是否有接收到任何数据。我会在RecyclerView的getItemCount方法内设置一个调试断点来进行检查。如果返回的值大于0,那就没问题。

然后,我会继续检查代码的其他步骤,这样你实际上可以看到问题出在哪里,这对于更好地理解问题的根本和事物的运作方式非常有用。

这样你就可以准确定位错误并提出更具体的问题。而不是引用整个代码,你可以引用一个方法或者只引用一行代码。

编辑

很高兴听到问题出在列表上。现在我看到你在适配器的第一行代码中遇到了问题。你在这里创建了一个新的空列表:

private List<CartItem> cartItems = new ArrayList<>();

也许你可以考虑给适配器添加一个参数,比如:

public class CartItemAdapter(List<CartItem> cartItems) extends RecyclerView.Adapter<CartItemAdapter.CartItemHolder>

然后你可以在适配器内部使用该列表。它应该已经被填充了。在你的onCreateView方法中,你可以这样做:

// 创建列表
private List<CartItem> cartItems = new ArrayList<>();

// 使用一些元素填充列表
CartItem item = new CartItem(构造函数参数);
cartItems.add(item);

// 创建适配器并将列表作为参数传递
final CartItemAdapter adapter = new CartItemAdapter(cartItems);
recyclerView.setAdapter(adapter);

然后在你的适配器中,你可以随心所欲地使用cartItems

英文:

Suggestion

Learn to debug your code and pinpoint your error. Most of the errors I get I solve them by debugging. If you don't know what debugging is or how to do it you can google it. It's really simple and it can save you hours of problem solving and it saves you the question altogether.

I'm suggesting this because from what you've described, the first thing I'd check is that if my RecyclerView is receiving anything at all. I would do this by setting a debug breakpoint inside the getItemCount method of my RecyclerView. If the value returned is bigger than 0 it means that's OK.

Then I'd proceed to check other steps of my code and this way you can actually see what's wrong and it's very useful to get a better understanding of what's going and how things work.

This way you can pinpoint your error and ask a more specific question. Instead of quoting your entire code, you could quote just a method or just one line.

EDIT

Great to hear that the problem is within the list. Now I see that you're having a problem with it in the first lines of your adapter. You're creating a new empty list when you do

private List<CartItem> cartItems = new ArrayList<>();

Maybe you can consider adding a parameter to the adapter such as

public class CartItemAdapter(List<CartItem> cartItems) extends RecyclerView.Adapter<CartItemAdapter.CartItemHolder>

And the you can use that list inside the adapter. It should be already populated. And in your onCreateView method you could do something like

// create the list
private List<CartItem> cartItems = new ArrayList<>();

// populate the list with some element or elements
CartItem item = new CartItem(constructor parameters);
cartItems.add(item);

// create the adapter and send the list as a parameter
final CartItemAdapter adapter = new CartItemAdapter(cartItems)
recyclerView.setAdapter(adapter)

And then in your adapter you can use cartItems as you wish

huangapple
  • 本文由 发表于 2020年7月23日 01:10:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/63039660.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定