2016-09-25 65 views
0

我在Android中使用adapters,在极少数情况下,该应用崩溃时为ListView设置数据...请帮助。 例外的是如下Android版本4.4.4的java.lang.IllegalStateException

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. 
    Make sure your adapter calls notifyDataSetChanged() when its content changes. 
    [in ListView(2131558745, class android.widget.ListView) 
    with Adapter(class com.adapters.CustomToBeSyncAdapter) 

这里是我的代码片段

private class ImportAsyncTask extends AsyncTask<Void, Integer, Integer> { 

       @Override 
       protected Integer doInBackground(Void... params) { 
        Realm realm = Realm.getDefaultInstance(); 

        realm.executeTransaction(new Realm.Transaction() { 
         @Override 
         public void execute(Realm realm) { 
          try { 
           RealmResults<AssetsActivitiesRealm> mResultsActivities = realm.where(AssetsActivitiesRealm.class).findAll(); 
           for (int i = 0; i < mResultsActivities.size(); i++) { 
            AssetsActivitiesRealm mAssetsActivitiePj = mResultsActivities.get(i); 
             SyncPojoList.add(new SyncPojo(mAssetsActivitiePj.getBatch(), mAssetsActivitiePj.getItemCode())); 
           } 
          } catch (Exception e) { 
           e.printStackTrace(); 
          } 
         } 
        }); 
        realm.close(); 
        return 1; 
       } 

       @Override 
       protected void onPreExecute() { 
        showLoading(); 
       } 

       @Override 
       protected void onPostExecute(Integer sum) { 
        try { 
         cancelLoading(); 
         displayListView(); 
        } catch (Exception e) { 
         e.printStackTrace(); 
        } 
       } 
      } 

      private void notifyAdapter() { 
       getActivity().runOnUiThread(new Runnable() { 
        public void run() { 
         listViewSync.setAdapter(null); 
         if (mdataAdapter != null) { 
          mdataAdapter.notifyDataSetChanged(); 
          listViewSync.requestLayout(); 
         } 
        } 
       }); 
      } 

      private void displayListView() { 
        mdataAdapter = new CustomToBeSyncAdapter(getActivity(), 
          R.layout.custom_tobesync_row, SyncPojoList); 
        notifyAdapter(); 
        listViewSync.setAdapter(mdataAdapter); 
        listViewSync.invalidate(); 
      } 
+3

*确保您的适配器在其内容更改时调用notifyDataSetChanged()* - 请尝试将'notifyDataSetChanged()'应用于ListView以通知其背景更改。 – rupinderjeet

+0

是的我已经调用notifyDataSetChanged()但仍然在极少数情况下崩溃..不知道如何解决这个错误 – Deepak

+2

发生崩溃时发布确切的Logcat和代码,使用http://hastebin.com – rupinderjeet

回答

1

当您要添加内部对象AsyncTask#doInBackground()你还是从背景改变ListView的适配器的型号线。

尝试在for-loop内使用AsyncTask#publishProgress(Progress...),然后覆盖AsyncTask#onProgressUpdate(Progress...),其中Progress是您的型号。

所以你for-loop可能是这个样子:

RealmResults<AssetsActivitiesRealm> mResultsActivities = realm.where(AssetsActivitiesRealm.class).findAll(); 
for (int i = 0; i < mResultsActivities.size(); i++) { 
    AssetsActivitiesRealm mAssetsActivitiePj = mResultsActivities.get(i); 
    publishProgress(new SyncPojo(mAssetsActivitiePj.getBatch(), mAssetsActivitiePj.getItemCode()); 
} 

而且你onProgressUpdate看起来是这样的:

public void onProgressUpdate(SyncPojo progress) { 
    SyncPojoList.add(progress); 
    mdataAdapter.notifyDataSetChanged(); // Notifying changes to the adapter here. 
} 

目前尚不清楚为什么你需要运行所有这一切的AsyncTask内, Realm实际上宣称你并不需要在后台线程中运行查询,因为他们的查询速度非常快(他们在获取数据时使用延迟加载),因此在大多数情况下它会影响UI线程 - especi当你根本没有任何“特殊”查询时。

另一方面,您不需要创建Realm.Transaction来查询数据。事务仅用于确保更改数据时的正确性。

你肯定可以简化代码很多:

  • 您使用requestLayoutListView调用notifyDatasetChanged这可能是没用的了。
  • 您使用的是通用try-catchException,原因是什么?您应该在代码导致异常之前处理代码,而不是在容易出错的代码周围添加try-catch
  • 您的AsyncTask返回无意义的整数,而不是实际返回结果。
  • 设置适配器也会通知ListView进行更新,所以无需打电话给您的notifyAdapter
  • notifyAdapter方法做了很多事情,它不需要做 - 例如将适配器设置为null

希望这有帮助,否则我会很乐意详细说明任何方面。

+0

如果我不使用Realm executeTransaction来加载数据,UI会特别冻结进度条..而且我将使用与您建议的代码相同的和平,并让您知道.. :) – Deepak

+0

它似乎是一个错误版本https://code.google.com/p/android/issues/detail?id=71936 – Deepak

+1

@Deepak:这行代码是专门做什么的:'SyncPojoList.add(new SyncPojo(mAssetsActivitiePj.getBatch(),mAssetsActivitiePj .getItemCode()));'? – Darwind