在多个活动中使用单个阵列适配器的多个实例

时间:2012-03-26 13:14:28

标签: android android-activity android-adapter

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

1 个答案:

答案 0 :(得分:1)

在asynctask中使用:

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

    }

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

希望这会有所帮助