J'ai un ListView qui est mis à jour par une intention d'envoi de service. Si l'événement de mise à jour arrive alors que j'appuie sur un élément de la ListView, j'ai un comportement bizarre. Le rectangle orange par défaut de l'élément sélectionné disparaît et le texte d'autres éléments devient plus sombre (comme si l'élément était enfoncé).Comment empêcher la mise à jour de ListView lorsque l'élément est enfoncé?
Comment est-ce que je diffère la mise à jour ListView après qu'il ne soit pas "pressé"? Ou plus spécifiquement, quels événements dois-je écouter pour déterminer que ListView n'est plus pressé? (Je peux créer un thread exécuté périodiquement pour mettre à jour quand c'est approprié, mais je pense que c'est excessif). Ou peut-être y at-il une meilleure solution ou solution de contournement.
Voici un exemple de code illustrant le problème. Le service envoie les intentions de mise à jour toutes les 2 secondes. Si j'essaie d'appuyer longuement sur un élément de la liste, j'obtiens le comportement bizarre que j'ai décrit ci-dessus.
L'activité:
package org.me.listviewupdate;
import android.app.ListActivity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ArrayAdapter;
public class MyActivity extends ListActivity {
private class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_DATA:
mAdapter.notifyDataSetChanged();
break;
default:
super.handleMessage(msg);
break;
}
}
}
private class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
mHandler.sendEmptyMessage(MSG_UPDATE_DATA);
}
}
private static final int MSG_UPDATE_DATA = 0;
private String[] mItems = new String[] { "Item1", "Item2", "Item3", "Item4" };
private ArrayAdapter<String> mAdapter;
private Handler mHandler;
private BroadcastReceiver mBroadcastReceiver;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mHandler = new MyHandler();
mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,
android.R.id.text1, mItems);
setListAdapter(mAdapter);
mBroadcastReceiver = new MyBroadcastReceiver();
registerReceiver(mBroadcastReceiver, new IntentFilter(MyService.UPDATE_EVENT));
startService(new Intent(this, MyService.class));
}
@Override
protected void onDestroy() {
unregisterReceiver(mBroadcastReceiver);
stopService(new Intent(this, MyService.class));
super.onDestroy();
}
}
Le service:
package org.me.listviewupdate;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class MyService extends Service {
private class MyUpdateTask implements Runnable {
public void run() {
sendBroadcast(new Intent(UPDATE_EVENT));
}
}
public static final String UPDATE_EVENT =
"org.me.listviewupdate.intent.event.UPDATED";
private static final int UPDATE_INTERVAL = 2;
private ScheduledExecutorService mUpdater;
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
mUpdater = Executors.newSingleThreadScheduledExecutor();
}
@Override
public void onDestroy() {
mUpdater.shutdownNow();
super.onDestroy();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
mUpdater.scheduleAtFixedRate(new MyUpdateTask(), UPDATE_INTERVAL,
UPDATE_INTERVAL, TimeUnit.SECONDS);
}
}
Merci.
Ma solution. Eh bien, juste au cas où cela pourrait aider quelqu'un ici est ma solution. Le code ajouté à MyActivity.onCreate()
:
getListView().setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
boolean isReleased = event.getAction() == MotionEvent.ACTION_UP
|| event.getAction() == MotionEvent.ACTION_CANCEL;
if (mHasPendingUpdate && isReleased) {
mHandler.sendEmptyMessage(MSG_UPDATE_DATA);
}
return false;
}
});
getListView().setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
boolean isKeyOfInterest = keyCode == KeyEvent.KEYCODE_DPAD_CENTER
|| keyCode == KeyEvent.KEYCODE_ENTER;
boolean isReleased = event.getAction() == KeyEvent.ACTION_UP;
if (mHasPendingUpdate && isKeyOfInterest && isReleased) {
mHandler.sendEmptyMessage(MSG_UPDATE_DATA);
}
return false;
}
});
J'ai également ajouté une variable mHasPendingUpdate
et modifiée MyHandler
:
private class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_DATA:
if (getListView().isPressed()) {
mHasPendingUpdate = true;
} else {
mAdapter.notifyDataSetChanged();
mHasPendingUpdate = false;
}
break;
default:
super.handleMessage(msg);
break;
}
}
}
J'ai trouvé une solution basée en partie sur votre réponse :) Merci. – brambury