我正在开发新闻阅读器,我有两个主要活动,主要活动和故事。Main 调用 asynctask 并获取所有 rss 提要,然后在完成时显示标题。故事显示来自特定提要的文章。main中有一个导航栏,可以调用故事。
我下载和解析的文章位于提要数组列表的哈希图中。我只有一个适配器类,arrayAdapter。一切正常,每次创建新列表视图时,我都会创建单独的 arrayAdapter 实例,但问题是当我从故事返回主并单击列表中的任何内容时,特别是当故事中的项目少于标题时主要是,它崩溃了:
java.lang.IllegalStateException:适配器的内容已更改,但 ListView 没有收到通知。确保适配器的内容不是从后台线程修改的,而只是从 UI 线程修改的。[在 ListView(2131099654, class android.widget.ListView) 和 Adapter(class package.package.ArticleListAdapter)]
我认为我的错误来自适配器不像单独的实例,尽管我认为我已经将它们作为单独的实例。我环顾四周寻求帮助,但我看到的大部分内容都是关于人们从后台线程更改数据,而不是在单独的活动中。
不幸的是,这段代码被改写了,部分是为了可读性,部分是因为我是为其他人写的,封闭源代码 yadda yadda ...
class main{
public HashMap<Integer, ArrayList<ArticleHolder>> allArticles;
public ArticleListAdapter ArtListAdapter;
public void onCreate(Bundle savedInstanceState) {
allArticles = new HashMap<Integer, ArrayList<ArticleHolder>>();
myApp appstate = (myApp)getApplicationContext();
appState.setParsedArticles(allArticles); //Added this for universal availability of the articles
//download things
//background.execute();
//...
}
private class downloader extends Asynctask ...{
...
onPostExecute(){
ArticleListAdapter = new ArticleListAdapter(context c, list_item L, allArticles.get(1));
listView1 = (ListView)findViewById(R.id.listView1);
listView1.setAdapter(ArtListAdapter);
}
}
class stories{
public HashMap<Integer, ArrayList<ArticleHolder>> allArticles;
public ArticleListAdapter ArtListAdapter;
public void onCreate(Bundle savedInstanceState) {
myApp appstate = (myApp)getApplicationContext();
allArticles = appState.getParsedArticles();
//set layout
//get article to display from Bundle extras
ListView LV = (ListView) findViewById(R.id.listView1);
ArtListAdapter = new ArticleListAdapter(StoriesScreenActivity.this, R.layout.article_list_item, allCleanArticles.get(buttonFeedNum));
LV = (ListView)findViewById(R.id.listView1);
LV.setAdapter(ArtListAdapter);
}
}
适配器的代码如下并且是准确的:
public class ArticleListAdapter extends ArrayAdapter<ArticleHolder>{
private static ArrayList<ArticleHolder> ArticleList;
private Context context;
private LayoutInflater mInflater;
public ArticleListAdapter(Context pcontext, int layoutResourceId, ArrayList<ArticleHolder> results) {
super(pcontext, layoutResourceId, results);
context = pcontext;
ArticleList = results;
mInflater = LayoutInflater.from(context);
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.article_list_item, null);
holder = new ViewHolder();
holder.txtMain = (TextView) convertView.findViewById(R.id.textView1);
holder.txtblurb = (TextView) convertView.findViewById(R.id.textView2);
holder.pic_view = (ImageView) convertView.findViewById(R.id.imageView1);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.txtMain.setText(ArticleList.get(position).getTitle());
holder.txtblurb.setText(ArticleList.get(position).getMainText());
holder.pic_view.setContentDescription(context.getString(R.string.GenImgDesc));
UrlImageViewHelper.setUrlDrawable(holder.pic_view, ArticleList.get(position).getPicName(),R.drawable.ic_placeholder);
return convertView;
}
public int getCount() {
return ArticleList.size();
}
public ArticleHolder getItem(int position) {
return ArticleList.get(position);
}
public long getItemId(int position) {
return position;
}
static class ViewHolder {
TextView txtMain;
TextView txtblurb;
ImageView pic_view;
}
}
谢谢你的帮助,我真的卡住了。
此外,非常感谢和支持 Github 上的 koush 和 Jwsonic 在 UrlImageViewer 上的工作。这很棒。
编辑:这是我的 AsyncTask.doInBackground()。对不起,我花了这么长时间,我在没有电脑的情况下出城了一段时间。再次感谢你的帮助。
protected Boolean doInBackground(String... params) {
boolean succeeded = false;
String downloadPath = null;
for(Integer num: feedArray){
downloadPath = "example.com/rss/"+Integer.toString(num);
doSax(downloadPath, num);
}
for(Integer num: feedArray){
currentDirtyFeedArticles = allDirtyArticles.get(num);
for(ArticleHolder dirtyArticle: currentDirtyFeedArticles){
dirtyArticle.setTitle(textCleaner(dirtyArticle.getTitle()));
//some text cleaning to make it look pretty
}
}
succeeded = true;
return succeeded;
}
好的,所以我接受了 Jedi_warriors 的建议并尝试添加 notifyDataSetChanged(),但我不知道如何让它与我的自定义适配器啮合。不过,它让我走上了正确的道路,因为我意识到当我返回主屏幕上的列表视图时,它并没有得到更新。这导致我考虑使用 onResume 方法,经过反复试验,我最终调用代码将视图与 onResume 中的适配器相关联。这里的诀窍是应用程序在打开时崩溃了,因为代码还没有准备好,所以我阻止了 onResume 中的代码运行,直到应用程序准备好运行。据我所知,这似乎已经解决了问题。感谢你的帮助!