我正在做一个新闻阅读器,我有两个主要的活动,主要和故事。主调用asynctask并获取所有rss feed,然后在完成时显示标题。故事显示来自特定Feed的文章。在main中有一个调用故事的导航栏。
我下载和解析的文章都在Feed的arraylists的hashmap中。我只有一个适配器类,arrayAdapter。一切正常,我每次创建一个新的listview时都会创建arrayAdapter的单独实例,但问题是当我从故事回到main并点击列表中的任何内容时,特别是当故事中的项目较少时,头条新闻在主要,它崩溃:
java.lang.IllegalStateException:适配器的内容已更改,但ListView未收到通知。确保不从后台线程修改适配器的内容,而只是从UI线程修改。 [在ListView(2131099654,类android.widget.ListView)中使用Adapter(类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;
}
}
谢谢你的帮助,我真的被困住了。
此外,非常感谢koush和Jwsonic在Github上为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中的代码运行,直到应用程序准备就绪。据我所知,这似乎解决了这个问题。谢谢你的帮助!
答案 0 :(得分:1)
在asynctask中使用:
@Override
protected Void doInBackground(String... arg0) {
// TODO Auto-generated method stub
}
因为这有Ui的访问权限。 对于ListView,使用listview.notifyDataSetChanged();
希望这会有所帮助