J'observe les mises à jour de contenu sur une ListActivity à l'aide d'un ContentObserver comme suit:
protected void onCreate(Bundle savedState)
{
super.onCreate(savedState);
ContentResolver cr = getContentResolver();
Cursor cursor = cr.query(TrackHeader.CONTENT_URI, sTrackListProjection, null, null, null);
startManagingCursor(cursor);
this.mAdapter = new TrackHeaderDataAdapter(this, R.layout.track_list_item, cursor, sTrackListProjection, null);
setListAdapter(mAdapter);
Handler handler = new Handler();
mTrackHeaderObserver = new ContentObserver(handler) {
@Override
public boolean deliverSelfNotifications() {
return false;
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
ContentResolver cr = getContentResolver();
mAdapter.changeCursor(cr.query(TrackHeader.CONTENT_URI, sTrackListProjection, null, null, null));
}
};
getContentResolver().registerContentObserver (TrackHeader.CONTENT_URI, true, mTrackHeaderObserver);
}
Cet observateur de contenu semble être correct - il est rappelé sur le thread d'interface utilisateur, mais je reçois le crash aléatoire suivant de manière assez prévisible sur le ListView sous-jacent:
02-21 14:06:00.440: ERROR/AndroidRuntime(739): Java.lang.NullPointerException
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.widget.AbsListView.obtainView(AbsListView.Java:1276)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.widget.ListView.makeAndAddView(ListView.Java:1668)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.widget.ListView.fillDown(ListView.Java:637)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.widget.ListView.fillSpecific(ListView.Java:1224)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.widget.ListView.layoutChildren(ListView.Java:1499)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.widget.AbsListView.onLayout(AbsListView.Java:1113)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.view.View.layout(View.Java:6830)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.widget.FrameLayout.onLayout(FrameLayout.Java:333)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.view.View.layout(View.Java:6830)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.widget.FrameLayout.onLayout(FrameLayout.Java:333)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.view.View.layout(View.Java:6830)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.widget.FrameLayout.onLayout(FrameLayout.Java:333)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.view.View.layout(View.Java:6830)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.widget.LinearLayout.setChildFrame(LinearLayout.Java:1119)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.widget.LinearLayout.layoutVertical(LinearLayout.Java:998)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.widget.LinearLayout.onLayout(LinearLayout.Java:918)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.view.View.layout(View.Java:6830)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.widget.FrameLayout.onLayout(FrameLayout.Java:333)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.view.View.layout(View.Java:6830)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.widget.FrameLayout.onLayout(FrameLayout.Java:333)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.view.View.layout(View.Java:6830)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.widget.FrameLayout.onLayout(FrameLayout.Java:333)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.view.View.layout(View.Java:6830)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.view.ViewRoot.performTraversals(ViewRoot.Java:996)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.view.ViewRoot.handleMessage(ViewRoot.Java:1633)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.os.Handler.dispatchMessage(Handler.Java:99)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.os.Looper.loop(Looper.Java:123)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Android.app.ActivityThread.main(ActivityThread.Java:4363)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Java.lang.reflect.Method.invokeNative(Native Method)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at Java.lang.reflect.Method.invoke(Method.Java:521)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:860)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:618)
02-21 14:06:00.440: ERROR/AndroidRuntime(739): at dalvik.system.NativeStart.main(Native Method)
02-21 14:09:56.159: ERROR/AndroidRuntime(749): ERROR: thread attach failed
02-21 14:09:59.480: ERROR/AndroidRuntime(760): ERROR: thread attach failed
02-21 14:12:19.449: ERROR/AndroidRuntime(778): ERROR: thread attach failed
02-21 14:12:22.779: ERROR/AndroidRuntime(789): ERROR: thread attach failed
02-21 14:12:26.479: ERROR/gralloc(51): [unregister] handle 0x3f13b8 still locked (state=40000001)
Quiconque a déjà vu quelque chose comme ça auparavant - a été bloqué sur celui-ci pendant quelques jours ...
Tim
J'avais une trace de pile similaire et j'ai découvert que je retournais un null de ma méthode getView () dans certains cas.
Si vous avez une liste et étendez BaseAdapter ou Adapter pour obtenir une liste personnalisée, assurez-vous que getView renvoie une valeur non nulle.
Si vous avez une vue à onglets et l'un de vos fragments est une liste qui remplace Adapter/BaseAdapter et getView renvoie null, vous obtiendrez ce problème.
Si vous utilisez une classe statique ViewHolder pour stocker vos éléments de vue dans l'adaptateur, vous pouvez oublier de définir l'objet viewHolder comme balise de convertView. Par exemple:
if (convertView == null) {
LayoutInflater mInflater = (LayoutInflater) context
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = mInflater.inflate(R.layout.adapter_drivers_and_riders, null);
holder = new ViewHolder();
holder.tvDate = (TextView)convertView.findViewById(R.id.tvDate);
holder.tvTime = (TextView)convertView.findViewById(R.id.tvTime);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Dans mon cas, je n'utilisais pas de curseur mais ayant le même problème, je me suis rendu compte que j'avais oublié de définir la balise comme viewHolder pour convertirView, donc lorsque les premières vues d'adaptateur sont créées pour la liste, c'est correct mais lorsque vous faites défiler et le mécanisme de recyclage fonctionne, il se bloque car il ne peut pas restaurer le viewHolder de convertView.
Au cas où, je voulais le mentionner.
Je n'ai pas utilisé changeCursor()
. Et, puisque la requête que vous avez utilisée pour créer le Cursor
est la même que la requête que vous utilisez pour "changer" le curseur, je viderais l'appel de changeCursor()
tout de suite et j'appellerais simplement requery()
sur le Cursor
que vous avez.