继承AsyncTask的类中For循环重复执行问题排查
问题根源与解决方案
核心问题
你的代码出现重复插入的原因有两个:
onBindViewHolder被多次触发:RecyclerView的每个列表项绑定都会调用这个方法,你在里面每次都启动一个doIT异步任务,相当于多个爬取任务同时执行,每个任务都遍历链接列表(写死循环2次),导致同一条数据被多次插入。- 列表元素重复添加:
list.add(data.get(position))在onBindViewHolder中执行,而RecyclerView会复用ViewHolder,这个方法可能被重复调用同一个position,导致list中出现重复链接。
修复方案
应该把爬取逻辑从Adapter中剥离,Adapter只负责数据展示,爬取任务在Activity中只执行一次,遍历完整的链接列表。
1. 简化Adapter,只做展示
修改MySqliteAdapter.java,移除所有爬取相关代码:
public class MySqliteAdapter extends RecyclerView.Adapter<MySqliteAdapter.ViewHolder> { private final Activity activity; private final List<String> data; public MySqliteAdapter(Activity activity, List<String> data) { this.data = data; this.activity = activity; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { LayoutInflater inflater = activity.getLayoutInflater(); // 传入parent参数,保证布局参数生效 View view = inflater.inflate(R.layout.custom_layout, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { // 仅负责设置文本展示,移除所有爬取逻辑 holder.linksURL.setText(data.get(position)); } @Override public int getItemCount() { return data.size(); } static class ViewHolder extends RecyclerView.ViewHolder { TextView linksURL; public ViewHolder(View itemView) { super(itemView); linksURL = itemView.findViewById(R.id.textView); } } }
2. 在Activity中执行单次爬取任务
把爬取逻辑移到MainActivity,确保只启动一次任务,遍历所有链接:
public class MainActivity extends AppCompatActivity { private List<String> linkList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 从SQLite获取完整的链接列表 linkList = fetchLinksFromSQLite(); // 初始化RecyclerView RecyclerView recyclerView = findViewById(R.id.recyclerView); recyclerView.setLayoutManager(new LinearLayoutManager(this)); MySqliteAdapter adapter = new MySqliteAdapter(this, linkList); recyclerView.setAdapter(adapter); // 启动一次爬取任务 new ScrapeTask().execute(); } // 实现从SQLite获取链接的逻辑 private List<String> fetchLinksFromSQLite() { List<String> links = new ArrayList<>(); // 这里写你的SQLite查询代码,填充links列表 return links; } private class ScrapeTask extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... params) { // 遍历完整的链接列表,每个链接只爬取一次 for (String url : linkList) { try { Document document = Jsoup.connect(url).get(); Elements titleElements = document.getElementsByClass("wp-block-post-title"); Elements contentElements = document.getElementsByClass("has-global-padding is-layout-constrained entry-content wp-block-post-content"); String title = titleElements.html(); String content = contentElements.html(); insertToFirebase(title, content); } catch (IOException e) { e.printStackTrace(); } } return null; } } private void insertToFirebase(String title, String content) { Map<String, Object> dataMap = new HashMap<>(); dataMap.put("title", title); dataMap.put("lyrics", content); FirebaseDatabase.getInstance().getReference() .child("worshipintercessor") .push() .setValue(dataMap) .addOnSuccessListener(unused -> { // 可选:添加成功后的回调 }) .addOnFailureListener(e -> { // 可选:失败处理 }); } }
额外优化点
- 移除了原代码中
new MainActivity()的错误写法:手动创建Activity实例会导致上下文混乱,绝对禁止。 - 布局填充时传入
parent参数,保证RecyclerView的Item布局参数正常生效。 - 原代码中
doIT的循环写死为i<2,改为动态遍历完整列表,适配任意数量的链接。 - 注意:
AsyncTask在Android API 30已被废弃,建议后续改用Kotlin协程或Java ExecutorService实现异步任务。
内容的提问来源于stack exchange,提问作者Isaac Darlong
相关产品推荐
相关产品推荐

