【问题标题】:RecylerView won't populateRecyclerView 不会填充
【发布时间】:2015-11-30 21:36:04
【问题描述】:

调试后更新

事实证明,convertCursorToTransactionInfoListtransactionLoadComplete 从未真正运行过。我在它们上设置了断点,它们从未出现在调试器中。此外,adapterData: size = 0 会在运行调试器时显示。

我能够使用onCreateViewTransactionInfo returnListValue = new TransactionInfo(); 下的代码正确填充回收站视图的一项

谁能提供一些关于为什么这不起作用的见解?我这样做的次数越来越多,我认为这与ArrayList<>List<> 的差异有关,因为ArrayList<> 用于TransactionsTab.java,而AdapterTransactions.java 使用List<> TransactionInfo.java 在某些方面。我已经在下面发布了所有这些类。

SQLite 接口不是问题(我很确定),因为我在应用程序的其他地方使用它来使用SimpleCursorAdapter 填充Spinners

TransactionsTab.java:

public class TransactionsTab extends Fragment
    implements TransactionLoad.LoadComplete {

RecyclerView transactionsRecycler;
AdapterTransactions adapter;
TransactionLoad load = null;
Cursor cursor;
ArrayList<TransactionInfo> adapterData = new ArrayList<>();

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    load = new TransactionLoad(getActivity());
    load.execute();
}

@Override
public View onCreateView(LayoutInflater inflater,
                         @Nullable ViewGroup container,
                         @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.tab_transactions,container,false);
    transactionsRecycler = (RecyclerView) view.findViewById(R.id.transactionRecycler);
    adapter = new AdapterTransactions(getActivity(), adapterData);
    transactionsRecycler.setAdapter(adapter);
    transactionsRecycler.setLayoutManager(new LinearLayoutManager(getActivity()));

    TransactionInfo returnListValue = new TransactionInfo();
    returnListValue.itemName = "lunch";
    returnListValue.itemCat = "Food";
    returnListValue.itemCurrency = "KRW";
    returnListValue.itemPrice = "125";
    returnListValue.date = "2015/08/25; 17:25:32";
    adapterData.add(returnListValue);

    return view;
}

private void convertCursorToTransactionInfoList(Cursor cursor) {
    if (cursor != null) {
        while (cursor.moveToNext()) {
            TransactionInfo returnListValue = new TransactionInfo();
            returnListValue.itemName = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_NAME));
            returnListValue.itemCat = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_CATEGORY));
            returnListValue.itemCurrency = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_CURRENCY));
            returnListValue.itemPrice = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_PRICE));
            returnListValue.date = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_DATE));
            adapterData.add(returnListValue);
        }
    }
}

@Override
public void transactionLoadComplete(Cursor cursor) {
    convertCursorToTransactionInfoList(cursor);
    adapter.setData(adapterData);
    adapter.notifyDataSetChanged();
    adapter.transactionData.notifyAll();
}
}

AdapterTransactions.java:

public class AdapterTransactions extends RecyclerView.Adapter<AdapterTransactions.MyViewHolder> {

private LayoutInflater inflater;
List<TransactionInfo> transactionData = Collections.emptyList();

public void setData(List<TransactionInfo> newData) {
    transactionData = newData;
}

public AdapterTransactions(Context context, List<TransactionInfo> transactionData) {
    inflater = LayoutInflater.from(context);
    this.transactionData = transactionData;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = inflater.inflate(R.layout.transaction_row, parent, false);
    MyViewHolder holder = new MyViewHolder(view);
    return holder;
}

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
    TransactionInfo current = transactionData.get(position);
    holder.itemName.setText(current.itemName);
    holder.itemCat.setText(current.itemCat);
    holder.itemPrice.setText(current.itemPrice);
    holder.itemDate.setText(current.date);
    holder.itemCurrency.setText(current.itemCurrency);
}

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

class MyViewHolder extends RecyclerView.ViewHolder {
    TextView itemName, itemCat, itemPrice, itemDate, itemCurrency;

    public MyViewHolder(View itemView) {
        super(itemView);
        itemName = (TextView) itemView.findViewById(R.id.itemName);
        itemCat = (TextView) itemView.findViewById(R.id.itemCat);
        itemPrice = (TextView) itemView.findViewById(R.id.itemPrice);
        itemDate = (TextView) itemView.findViewById(R.id.itemDate);
        itemCurrency = (TextView) itemView.findViewById(R.id.itemCurrency);
    }
}
}

TransactionInfo.java:

public class TransactionInfo {
public String itemName, itemPrice, itemCurrency, itemCat, date;
}

重新回答:

我已尝试对convertCursorToTransactionInfoList 进行以下方法更改:

private void convertCursorToTransactionInfoList(Cursor cursor) {
    if (cursor != null) {
        while (cursor.moveToNext()) {
            TransactionInfo returnListValue = new TransactionInfo();
            returnListValue.itemName = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_NAME));
            returnListValue.itemCat = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_CATEGORY));
            returnListValue.itemCurrency = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_CURRENCY));
            returnListValue.itemPrice = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_PRICE));
            returnListValue.date = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_DATE));
            adapterData.add(returnListValue);
        }
    }
}

private static void convertCursorToTransactionInfoList(Cursor cursor, ArrayList<TransactionInfo> adapterData) {
    if (cursor != null) {
        while (cursor.moveToNext()) {
            TransactionInfo returnListValue = new TransactionInfo();
            returnListValue.itemName = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_NAME));
            returnListValue.itemCat = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_CATEGORY));
            returnListValue.itemCurrency = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_CURRENCY));
            returnListValue.itemPrice = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_PRICE));
            returnListValue.date = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_DATE));
            adapterData.add(returnListValue);
        }
    }
}

像这样通知adatpers:

@Override
public void transactionLoadComplete(Cursor cursor) {
    convertCursorToTransactionInfoList(cursor, adapterData);
    adapter.setData(adapterData);
    adapter.notifyDataSetChanged();
    adapter.transactionData.notifyAll();
}

另外,请注意,我必须将 List&lt;TransactionInfo&gt; adapterData = new ArrayList&lt;&gt;(); 更改为 ArrayList&lt;TransactionInfo&gt; adapterData = new ArrayList&lt;&gt;();

我看的越多,我就越认为它与ArrayList&lt;&gt;List&lt;&gt; 问题有关。

结束编辑

【问题讨论】:

  • 它在哪里停止工作?您是否从数据库中获得结果?是否创建了未显示的视图?
  • 片段只是空白;没有任何显示。如果这就是您获取结果的意思,那么数据库有必要的事务来加载。我不确定如何检查创建的视图。
  • 使用调试或Log 类而不是发布整个应用代码...
  • 哦,我明白你们的意思了。我已将 DDMS LogCat 添加到 OP。

标签: java android sqlite android-recyclerview


【解决方案1】:

问题在于从Cursor 中获取数据,特别是这里:

if (cursor.moveToFirst()) {
    for (int i = 10; i < cursor.getCount(); i++) {
        returnListValue.itemName = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_NAME));
        returnListValue.itemCat = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_CATEGORY));
        returnListValue.itemCurrency = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_CURRENCY));
        returnListValue.itemPrice = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_PRICE));
        returnListValue.date = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_DATE));
        returnList.add(returnListValue);
    }
}

上面的代码将光标移动到第一个位置(cursor.moveToFirst()),但之后Cursor 位置不会改变,因此您的循环执行cursor.getCount() 次,但它只对光标中的第一项进行操作.

相反,我会选择 while 循环而不是 for 循环,如下所示:

// move cursor on to next position if available
while(cursor.moveToNext()) { 
    // More data is available so add it to the list
    // process data as before
}

编辑 1

RE your comment - 这是我建议更改的内容。

代替:

adapterData = convertCursorToBudgetInfoList(cursor);

要么:

选项 1

convertCursorToBudgetInfoList 仍然是 static 方法,但现在在原始 adapterData 引用上运行。

convertCursorToBudgetInfoList(cursor, adapterData);

并将您的方法更改为:

private static void convertCursorToBudgetInfoList(Cursor cursor, ArrayList<TransactionInfo> adapterData) {

    if (cursor != null) {                         

        while (cursor.moveToNext()) { // note: no for loop ;-)
            TransactionInfo returnListValue = new TransactionInfo();
            returnListValue.itemName = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_NAME));
            returnListValue.itemCat = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_CATEGORY));
            returnListValue.itemCurrency = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_CURRENCY));
            returnListValue.itemPrice = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_PRICE));
            returnListValue.date = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_DATE));
            adapterData.add(returnListValue);
        }
    }
}

选项 2

convertCursorToBudgetInfoList 设为成员方法而不是静态方法,并直接对您的adapterData 进行操作。

convertCursorToBudgetInfoList(cursor);

并将您的方法更改为:

private void convertCursorToBudgetInfoList(Cursor cursor) {

    if (cursor != null) {                         

        while (cursor.moveToNext()) { // note: no for loop ;-)
            TransactionInfo returnListValue = new TransactionInfo();
            returnListValue.itemName = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_NAME));
            returnListValue.itemCat = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_CATEGORY));
            returnListValue.itemCurrency = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_CURRENCY));
            returnListValue.itemPrice = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_PRICE));
            returnListValue.date = cursor.getString(cursor.getColumnIndex(DatabaseHelper.TRANSACTION_DATE));
            adapterData.add(returnListValue); // member variable (same as this.adapterData)
        }
    }
}

当然,使用这些选项中的任何一个,请务必通知您的适配器。

我还要重申,您确实需要摆脱 for 循环 - 使用调试器逐步完成它,一切都会变得清晰。

【讨论】:

  • 所以我按照您的建议将if 更改为while,但它仍然没有显示任何内容。还有其他建议吗?
  • 我一直在研究它,并得出与刚刚回答的@n00bean 相同的认识。 adapterData = convertCursorToBudgetInfoList(cursor); 不会更新适配器对数据的引用。要么按照@n00bean 的建议进行操作,要么通过convertCursorToBudgetInfoList 对原始adapterData 的引用并对其进行List.add() 调用而不是静态调用。
  • 不幸的是,这些选项都不起作用:(哦,伙计,这令人沮丧:\
  • 再次更新了OP,也许你或@n00bean比我更能理解。
【解决方案2】:

尝试在convertCursorToBudgetInfoList 中更改此for 循环:

for (int i = 10; i < cursor.getCount(); i++) 

0开始...如果少于 10 个结果将不会显示任何内容!

【讨论】:

  • 哈哈,我以为是设置最大长度。我把它切换到0,但它仍然不起作用:(
【解决方案3】:

问题出在 TransactionsTab 上。在 transactionLoadComplete(Cursor cursor) 方法中,您更新了 Fragments List transactionData,但您从未将其传递给您的 RecyclerView Adapter。所以在你的适配器上调用 notify 没有任何作用,因为它的数据没有改变。

您的解决方案是在您的适配器中创建一个函数,例如:

public void setData(List<TransactionData> newData){
    transactionData = newData;
}

然后在transactionLoadComplete(Cursor cursor)中调用notifyDataSetChanged之前的新函数:

public void transactionLoadComplete(Cursor cursor) {
    adapterData = convertCursorToBudgetInfoList(cursor);
    adapter.setData(adapterData);
    adapter.notifyDataSetChanged();
    adapter.transactionData.notifyAll();
}

【讨论】:

  • 您能否将答案中的所有代码更新为您现在使用的代码?我刚刚发现您的 for 循环以 int i = 10 开头,但不确定您是否已经按照@aoemerson 在他的回答中的建议更改了该部分。
  • 刚刚更新。我所做的唯一更改是 Buddy 建议的更改。我确实尝试了 aoemerson 的答案,但没有任何效果,所以我恢复到原来的样子。我根据您的建议尝试了两种方法,但都没有成功。
  • 您的for 循环实际上没有做任何事情,只是对Cursor 中的第一项重复相同的逻辑,所以说实话,我肯定会改变它。在调试器中设置断点并逐步执行循环以了解我的意思。
  • aoemerson 是正确的,但是还有其他问题无法正常工作,否则您会在视图中看到第一个元素显示 cursor.getCount() 次。到处都设置断点,尤其是在 RecycleView 适配器中,看看它试图对你提供的数据做什么。它是否获得了正确的项目计数并将它们添加到无法看到的回收站视图中,或者它显示的回收站视图中没有任何内容?
猜你喜欢
  • 2018-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多