2015-05-11 2 views
1

Я пытаюсь заставить свой бесконечный список работать, но все время я получаю IllegalStateException об изменении содержимого адаптера. Я не знаю, почему это происходит.Android - содержимое адаптера изменилось?

Ошибка довольно

IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(2131493058, class android.widget.ListView) with Adapter(class ListNewsAdapter)] 

Вот мой AsyncTask:

public class ListDownloadNewAsyncTask extends AsyncTask<Void, Void, NewsArrayList> { 
    private String mLastId = null; 

    @Override 
    protected void onPreExecute() { 
     ListNewsAdapter adapter = (ListNewsAdapter) listView.getAdapter(); 
     if (adapter != null && adapter.getCount() > 0) { 
      mLastId = adapter.getItem(adapter.getCount() - 1).getId(); 
     } 
     super.onPreExecute(); 
    } 

    @Override 
    protected NewsArrayList doInBackground(Void... params) { 
     NewsArrayList downloadedNews = null; 
     try { 
      downloadedNews = JSONLoader.loadNews(getActivity(), mLastId); 
     } catch (Exception ex) { } 
     return downloadedNews; 
    } 

    @Override 
    protected void onPostExecute(NewsArrayList result) { 
     mLeftToDownload = result.getLeft(); 
     ListNewsAdapter adapter = (ListNewsAdapter) listView.getAdapter(); 
     if (adapter == null) { 
      adapter = new ListNewsAdapter(getActivity(), R.layout.news_list_row, result.getNewsArray(), NewsListFragment.this); 
      listView.setAdapter(adapter); 
     } else { 
      adapter.addAll(result.getNewsArray()); 
      adapter.notifyDataSetChanged(); 
      isLoading = false; 
     } 
     super.onPostExecute(result); 
    } 
} 

Я искал любой фрагмент кода о бесконечных ListView, но большинство вещей, которые я нашел, были со статическими или динамически создаваемых - Не скачано.

Так что мой вопрос ... Что я пропустил здесь? Или что я делаю неправильно?

EDIT: Вот мой класс адаптер

public class ListNewsAdapter extends ArrayAdapter<News> { 
private final ArrayList<News> news; 
private final int newsRowResourceId; 
private View progressView; 
NewsListFragment fragment; 

public ListNewsAdapter(Context context, int newsRowResourceId, ArrayList<News> news, NewsListFragment fragment) { 
    super(context, newsRowResourceId, news); 
    this.news = news; 
    this.newsRowResourceId = newsRowResourceId; 
    this.fragment = fragment; 
} 

@Override 
public int getCount() { 
    return NewsListFragment.isLoading() ? news.size() + 1 : news.size(); 
} 

@Override 
public View getView(final int position, View convertView, ViewGroup parent) { 
    LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    ViewHolder holder; 

    try { 
     if (convertView == null || convertView.findViewById(R.id.title) != null || convertView == progressView) { 

      convertView = inflater.inflate(newsRowResourceId, null); 
      holder = new ViewHolder(); 
      holder.title = (TextView) convertView.findViewById(R.id.title); 
      holder.description = (TextView) convertView.findViewById(R.id.description); 
      holder.image = (ImageView) convertView.findViewById(R.id.news_list_item_image); 

      convertView.setTag(holder); 
     } else { 
      holder = (ViewHolder) convertView.getTag(); 
     } 

     if (position < getCount()) { 
      News newsRow = news.get(position); 

      if (newsRow != null) { 
       holder.title.setText(newsRow.getTitle().trim().replaceAll("[\n\r]", " ")); 
       holder.description.setText(newsRow.getDescription().trim().replaceAll("[\n\r]", " ")); 

       if (newsRow.getPhotoUrl() != null && !newsRow.getPhotoUrl().equalsIgnoreCase("null")) { 
        Ion.with(holder.image).placeholder(R.drawable.icon).load(newsRow.getPhotoUrl()); 
       } else { 
        holder.image.setImageResource(R.drawable.icon); 
       } 
      } 
     } 
     convertView.setClickable(true); 
     convertView.setFocusable(true); 
     convertView.setOnClickListener(new OnClickListener() { 

      @Override 
      public void onClick(View v) { 
       Main.instance.changeNewsFragment(news.get(position).getNewsUrl()); 
      } 
     }); 

     return convertView; 

    } catch (IndexOutOfBoundsException e) { 
     progressView = inflater.inflate(R.layout.progress_list_item, null); 
     return progressView; 
    } 
} 

static class ViewHolder { 
    TextView title; 
    TextView description; 
    ImageView image; 
} 
} 

EDIT: Я думал о еще одну вещь. Я запускать эту AsyncTask из OnScrollListener:

public abstract class InfiniteScrollListener implements AbsListView.OnScrollListener { 
    private int bufferItemCount = 10; 

    public InfiniteScrollListener(int bufferItemCount) { 
     this.bufferItemCount = bufferItemCount; 
    } 

    public abstract void loadMore(); 

    @Override 
    public void onScrollStateChanged(AbsListView view, int scrollState) { 
    } 

    @Override 
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 
     if ((mLeftToDownload > 0) && !isLoading && ((firstVisibleItem + visibleItemCount) >= (totalItemCount - bufferItemCount))) { 
      Log.d("test", "from onScroll: " + mLeftToDownload + ", " + isLoading + ", " + (firstVisibleItem + visibleItemCount) + ">=" + (totalItemCount - bufferItemCount)); 
      isLoading = true; 
      loadMore(); 
     } 
    } 
} 

и

public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) { 
    View v = inflater.inflate(R.layout.news_list_fragment, null); 
    listView = (ListView) v.findViewById(R.id.list_news); 

    mLeftToDownload = -1; 

    listView.setOnScrollListener(new InfiniteScrollListener(5) { 
     @Override 
     public void loadMore() { 
      new ListDownloadNewAsyncTask().execute(); 
     } 
    }); 
    listView.setItemsCanFocus(true); 

    new ListDownloadNewAsyncTask().execute(); 

    return v; 
} 

И поэтому я подумал, что это может быть что-то с двумя задачами, работающих на тот же адаптер. Поэтому я изменил последнюю часть инструкции if в методе onscroll, и это уменьшило количество сбоев, но у меня все еще есть некоторые.

EDIT: Logcat для @Elltz

05-12 00:58:51.027 5108-5108/app.packg E/AndroidRuntime﹕ FATAL EXCEPTION: main 
java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(2131493058, class android.widget.ListView) with Adapter(class ListNewsAdapter)] 
     at android.widget.ListView.layoutChildren(ListView.java:1538) 
     at android.widget.AbsListView$FlingRunnable.run(AbsListView.java:4385) 
     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725) 
     at android.view.Choreographer.doCallbacks(Choreographer.java:555) 
     at android.view.Choreographer.doFrame(Choreographer.java:524) 
     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711) 
     at android.os.Handler.handleCallback(Handler.java:615) 
     at android.os.Handler.dispatchMessage(Handler.java:92) 
     at android.os.Looper.loop(Looper.java:137) 
     at android.app.ActivityThread.main(ActivityThread.java:4849) 
     at java.lang.reflect.Method.invokeNative(Native Method) 
     at java.lang.reflect.Method.invoke(Method.java:511) 
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795) 
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:562) 
     at dalvik.system.NativeStart.main(Native Method) 
+0

Этот список загружается только один раз или постоянно получает новые результаты? –

+0

@DroidChris: список получает новые результаты (получение нескольких старых новостей, когда пользователь прокручивает до конца). – Seraphis

+0

@iRaviiVooda: первый набор элементов помещается в конструктор адаптера. – Seraphis

ответ

0

Ok, после анализа кода, это, кажется, работающее решение, попробуйте следующее:

1.Add этот метод к адаптеру

public void addNewData(ArrayList<News> newData) { 
    if(news != null) { 
     news.addAll(newData); 
     notifyDataSetChanged(); 
    } 
} 

2.Replace onPostExecute с этим

@Override 
protected void onPostExecute(NewsArrayList result) { 
    mLeftToDownload = result.getLeft(); 
    ListNewsAdapter adapter = (ListNewsAdapter) listView.getAdapter(); 
    if (adapter == null) { 
     adapter = new ListNewsAdapter(getActivity(), R.layout.news_list_row, result.getNewsArray(), NewsListFragment.this); 
     listView.setAdapter(adapter); 
    } else { 
     adapter.addNewData(result.getNewsArray()); 
     isLoading = false; 
    } 
    super.onPostExecute(result); 
} 

Надеется, что это поможет

EDIT Так, видимо, это не сработало, так что последнее средство, чтобы изменить адаптер

public class ListNewsAdapter extends BaseAdapter { 
private final ArrayList<News> news; 
private View progressView; 
NewsListFragment fragment; 

LayoutInflater inflater; 

public ListNewsAdapter(Context context, NewsListFragment fragment) { 
    this.fragment = fragment; 
    inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
} 

@Override 
public int getCount() { 
    if(news == null) 
     return 0; 
    return NewsListFragment.isLoading() ? news.size() + 1 : news.size(); 
} 

@Override 
public View getView(final int position, View convertView, ViewGroup parent) { 
    ViewHolder holder; 

    try { 
     if (convertView == null || convertView.findViewById(R.id.title) != null || convertView == progressView) { 

      convertView = inflater.inflate(R.layout.news_list_row, null); 
      holder = new ViewHolder(); 
      holder.title = (TextView) convertView.findViewById(R.id.title); 
      holder.description = (TextView) convertView.findViewById(R.id.description); 
      holder.image = (ImageView) convertView.findViewById(R.id.news_list_item_image); 

      convertView.setTag(holder); 
     } else { 
      holder = (ViewHolder) convertView.getTag(); 
     } 

     if (position < getCount()) { 
      News newsRow = getItem(position); 

      if (newsRow != null) { 
       holder.title.setText(newsRow.getTitle().trim().replaceAll("[\n\r]", " ")); 
       holder.description.setText(newsRow.getDescription().trim().replaceAll("[\n\r]", " ")); 

       if (newsRow.getPhotoUrl() != null && !newsRow.getPhotoUrl().equalsIgnoreCase("null")) { 
        Ion.with(holder.image).placeholder(R.drawable.icon).load(newsRow.getPhotoUrl()); 
       } else { 
        holder.image.setImageResource(R.drawable.icon); 
       } 
      } 
     } 
     convertView.setClickable(true); 
     convertView.setFocusable(true); 
     convertView.setOnClickListener(new OnClickListener() { 

      @Override 
      public void onClick(View v) { 
       Main.instance.changeNewsFragment(news.get(position).getNewsUrl()); 
      } 
     }); 

     return convertView; 

    } catch (IndexOutOfBoundsException e) { 
     progressView = inflater.inflate(R.layout.progress_list_item, null); 
     return progressView; 
    } 
} 

@Override 
public News getItem(int position) { 
    return news.get(position); 
} 

@Override 
public long getItemId(int position) { 
    return 0; 
} 

static class ViewHolder { 
    TextView title; 
    TextView description; 
    ImageView image; 
} 

public void addNewData(ArrayList<News> newData) { 
    if(news == null) { 
     news = new ArrayList<News>(); 
    } 
    news.addAll(newData); 
    notifyDataSetChanged(); 
} 
} 

и заменить onPostExecute

@Override 
protected void onPostExecute(NewsArrayList result) { 
    mLeftToDownload = result.getLeft(); 
    ListNewsAdapter adapter = (ListNewsAdapter) listView.getAdapter(); 
    if (adapter == null) { 
     adapter = new ListNewsAdapter(getActivity(), NewsListFragment.this); 
     listView.setAdapter(adapter); 
    } 

    adapter.addNewData(result.getNewsArray()); 
    isLoading = false; 

    super.onPostExecute(result); 
} 

Я надеюсь, Я не пропускаю ничего, что только что написал, что у меня нет Eclipse.

+0

То же самое: - \ – Seraphis

+0

К сожалению, ничего не изменилось. Может быть, причина в том, что ProgressView? Я отключил его, и похоже, что он работает сейчас ... – Seraphis

Смежные вопросы