Android短信应用ANR问题及RecyclerView不更新求助
嘿,我来帮你拆解下你遇到的问题——RecyclerView只显示dummy数据还触发ANR,其实核心根源你自己已经发现了,咱们再把细节和优化点理清楚:
你在onPostExecute()里错误地调用了db1.startTransaction();,但数据库事务启动后如果不调用endTransaction()(或者先标记事务成功),会一直持有数据库锁,直接阻塞主线程,最终触发ANR。你替换成db1.endTransaction()后恢复正常,这正是最关键的修复点。
这里给你补一个标准的数据库事务写法,避免以后再踩坑:
db1.startTransaction(); try { // 执行你的数据库写入/修改操作 db1.setTransactionSuccessful(); // 标记事务执行成功 } finally { db1.endTransaction(); // 无论成功失败,必须结束事务释放锁 }
你这次是在读取数据完成后错误启动了事务却不结束,直接把数据库资源占死,导致主线程卡死。
你的SmsAdapter.insert()方法每次添加一条短信就调用notifyDataSetChanged(),这会让RecyclerView整个列表重新刷新一遍,当短信数量多的时候,不仅会让UI卡顿,还会加重主线程的负担,间接加剧ANR的风险。
给你两个优化方案:
方案一:批量插入(推荐)
给Adapter加一个批量添加数据的方法,一次性刷新新增的条目范围:
public class SmsAdapter extends RecyclerView.Adapter<SmsAdapter.SmsViewHolder>{ // ... 原有代码 ... public void addAll(ArrayList<String> newMessages) { int startPos = sms_messages_list.size(); sms_messages_list.addAll(newMessages); notifyItemRangeInserted(startPos, newMessages.size()); } }
然后在onPostExecute()里直接调用这个方法,代替循环插入:
@Override protected void onPostExecute(ArrayList<String> msg_list) { super.onPostExecute(msg_list); MainActivity activity = activityWeakReference.get(); if (activity == null || activity.isFinishing()) { return; } try { activity.sms_adapter.addAll(msg_list); } catch (Exception e){ Log.d(TAG, "onPostExecute: exception : " + e); } db1.endTransaction(); // 这里用正确的结束事务方法 db1.close(); }
方案二:逐条插入但精准刷新
如果一定要保持逐条插入的逻辑,把notifyDataSetChanged()替换成notifyItemInserted(position),这样只会刷新新增的那一条,而不是整个列表:
public void insert(int position, String new_sms) { Log.d(TAG, "SmsAdapter: insert(): adding a new message at position + " + position); sms_messages_list.add(position, new_sms); notifyItemInserted(position); // 替换notifyDataSetChanged() }
初始化RecyclerView的时候,建议先设置LayoutManager再设置Adapter,这是更规范的写法,避免潜在的布局异常:
messages.setLayoutManager(new LinearLayoutManager(this)); sms_adapter = new SmsAdapter(this, sms_messages_list); messages.setAdapter(sms_adapter);
内容的提问来源于stack exchange,提问作者sweetpoision

