Я работаю над программой для чтения новостей, и у меня есть два основных актива: основной и истории. Main вызывает asynctask и получает все rss-каналы, а затем отображает заголовки после его завершения. Истории отображают статьи из определенных каналов. В главном меню есть навигационная панель, которая называет истории.
Мои загруженные и проанализированные статьи находятся в хэш-карте массивов каналов. У меня есть только один класс адаптера, arrayAdapter. Все работает нормально, и я создаю отдельные экземпляры arrayAdapter каждый раз, когда создаю новый просмотр списка, но проблема в том, что я возвращаюсь от историй к основной и щелкаю по чему-либо в списке, особенно когда в историях меньше элементов, чем заголовков в основном это вылетает с:
java.lang.IllegalStateException: содержимое адаптера изменилось, но ListView не получил уведомление. Убедитесь, что содержимое вашего адаптера не изменено из фонового потока, а только из потока пользовательского интерфейса. [в ListView (2131099654, класс android.widget.ListView) с адаптером (класс 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. Это круто.
Edit:
Вот мой 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 до тех пор, пока приложение не будет готово к работе. Насколько я могу судить, похоже, это решило проблему. Спасибо за вашу помощь!