Android开发问题:爬取多页网站数据时数组被覆盖而非追加
解决Android Jsoup多页抓取数据覆盖数组的问题
下午好,我是一名Android编程初学者,正在开发一个从网站抓取信息并展示到ListView的界面。仅抓取网站首页时代码可正常运行,但抓取第2页及更多页面时,新数据会覆盖整个数组而非追加到末尾。我已用尽现有知识仍未解决,推测是数组构建的低级错误,但无法独自找到解决方案。若有拼写错误请见谅,我使用了翻译工具。
原代码
package br.com.testejsoup.eu.testejsoup; import android.content.Intent; import android.os.AsyncTask; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.IOException; public class MainActivity extends AppCompatActivity { private ListView conteudo; String[] aniNomes; String[] aniLinks; ArrayAdapter<String> adaptador; Document doc; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); conteudo = findViewById(R.id.html_conteudo); new doit().execute(); conteudo.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { int posicao = position; Intent intent = new Intent(MainActivity.this, Episodio.class); intent.putExtra("aniLinks", aniLinks[posicao]); //Toast.makeText(getApplicationContext(), aniLinks[posicao], Toast.LENGTH_LONG).show(); startActivity(intent); } }); } public class doit extends AsyncTask<Void, Void, Void>{ String URL = "http://www.URL.com/lancamentos?page="; String nomeExp; Elements nome; Elements links; int paginas = 5; @Override protected Void doInBackground(Void... voids) { try { for (int i=1; i<= paginas;i++) { String new_URL = URL + i; doc = Jsoup.connect(new_URL).get(); nome = doc.select("div.nome-thumb a.tt"); links = doc.select("div.nome-thumb a.tt"); aniNomes = new String[nome.size()]; aniLinks = new String[links.size()]; for(Element nomeTemp : nome){ nomeExp = nomeTemp.text(); adaptador.add(nomeExp); } } for (int i = 0; i < nome.size(); i++) { aniNomes[i] = nome.get(i).text(); } for (int i = 0; i < links.size(); i++) { aniLinks[i] = links.get(i).attr("abs:HREF"); } adaptador = new ArrayAdapter<>(getApplicationContext(), android.R.layout.simple_list_item_1, android.R.id.text1, aniNomes); } catch (IOException e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); conteudo.setAdapter(adaptador); } } }
问题根源
你的核心问题在于使用了固定长度的数组String[]存储多页数据,且每次循环页面时都重新初始化数组:
- 在页面循环里,每次执行
aniNomes = new String[nome.size()]和aniLinks = new String[links.size()]都会彻底覆盖之前页面的数据; - 最后仅对最后一页的
nome和links进行赋值,导致ListView只显示最后一页内容; - 提前调用
adaptador.add(nomeExp)时adaptador还未初始化,会触发空指针异常。
修改后的完整代码
package br.com.testejsoup.eu.testejsoup; import android.content.Intent; import android.os.AsyncTask; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.IOException; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { private ListView conteudo; // 改用ArrayList动态存储数据,支持无限制追加元素 ArrayList<String> aniNomes = new ArrayList<>(); ArrayList<String> aniLinks = new ArrayList<>(); ArrayAdapter<String> adaptador; Document doc; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); conteudo = findViewById(R.id.html_conteudo); new doit().execute(); conteudo.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Intent intent = new Intent(MainActivity.this, Episodio.class); // ArrayList用get(position)方法获取对应位置的元素 intent.putExtra("aniLinks", aniLinks.get(position)); startActivity(intent); } }); } public class doit extends AsyncTask<Void, Void, Void>{ String URL = "http://www.URL.com/lancamentos?page="; Elements nome; Elements links; int paginas = 5; @Override protected Void doInBackground(Void... voids) { try { for (int i=1; i<= paginas;i++) { String new_URL = URL + i; doc = Jsoup.connect(new_URL).get(); nome = doc.select("div.nome-thumb a.tt"); links = doc.select("div.nome-thumb a.tt"); // 将当前页的数据直接追加到ArrayList中 for (Element nomeT : nome){ aniNomes.add(nomeT.text()); } for (Element linkT : links){ aniLinks.add(linkT.attr("abs:HREF")); } } } catch (IOException e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); // 所有数据加载完成后,再初始化Adapter并绑定到ListView adaptador = new ArrayAdapter<>(getApplicationContext(), android.R.layout.simple_list_item_1, android.R.id.text1, aniNomes); conteudo.setAdapter(adaptador); } } }
主要修改点
- 替换数组为ArrayList:固定长度数组无法动态追加数据,
ArrayList可以灵活添加元素,完美解决数据覆盖问题; - 移除循环内的数组初始化:删除了页面循环中重新创建数组的代码,避免覆盖之前的抓取结果;
- 调整Adapter初始化时机:将
ArrayAdapter的初始化移到onPostExecute中,确保所有数据加载完成后再绑定到ListView; - 适配ArrayList的元素访问方式:点击事件中用
aniLinks.get(position)代替数组下标访问,符合集合类的使用规范; - 移除无效的
adaptador.add调用:原代码中提前调用该方法会触发空指针,现在直接将数据存入ArrayList,由Adapter自动处理展示。
内容的提问来源于stack exchange,提问作者wshr
相关产品推荐
相关产品推荐

