0

我正在开发新闻阅读器,我有两个主要活动,主要活动和故事。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 中的代码运行,直到应用程序准备好运行。据我所知,这似乎已经解决了问题。感谢你的帮助!

4

1 回答 1

1

在异步任务中使用:

@Override
    protected Void doInBackground(String... arg0) {
        // TODO Auto-generated method stub

    }

因为这有 Ui 的访问权限。对于 ListView 使用 listview.notifyDataSetChanged();

希望这可以帮助

于 2012-03-26T13:53:52.607 回答