Long Story Short: une méthode de mes mises à jour d'activité et fait défiler la ListView par un ArrayAdapter comme il se doit, mais une méthode d'un TimerTask interne pour les messages de vote (qui sont affichés dans le ListView) met à jour le ListView, mais ne défile pas il. Pourquoi?Pourquoi mon bouton peut-il déclencher le défilement de l'interface utilisateur et pas mon TimerTask dans l'activité?
longue histoire:
J'ai une activité de chat avec cette mise en page:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#fff"
>
<ListView android:id="@+id/messageList"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:stackFromBottom="true"
android:transcriptMode="alwaysScroll"
android:layout_weight="1"
android:fadeScrollbars="true"
/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
>
<EditText android:id="@+id/message"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
<Button android:id="@+id/button_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send"
android:onClick="sendMessage"
/>
</LinearLayout>
</LinearLayout>
ListView interne (avec id MessageList) est peuplé par un ArrayAdapter qui gonfle le XML ci-dessous et remplace les chaînes dans ce .
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:background="#fff"
android:paddingLeft="2dp"
android:paddingRight="2dp"
>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textColor="#00F"
android:typeface="monospace"
android:text="2010-10-12 12:12:03"
android:gravity="left"
/>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/sender"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textColor="#f84"
android:text="spidey"
android:gravity="right"
android:textStyle="bold"
/>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/body"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:padding="1dp"
android:gravity="left"
android:layout_below="@id/date"
android:text="Mensagem muito legal 123 quatro cinco seis."
android:textColor="#000"
/>
</RelativeLayout>
Le problème est: dans la mise en page principale, j'ai un EditText pour le message de chat, et un bouton pour envoyer le message. Je l'ai déclaré l'adaptateur dans le champ d'activité:
public class ChatManager extends Activity{
private EditText et;
private ListView lv;
private Timestamp lastDate = null;
private long campaignId;
private ChatAdapter ca;
private List<ChatMessage> vetMsg = new ArrayList<ChatMessage>();
private Timer chatPollingTimer;
private static final int CHAT_POLLING_PERIOD = 10000;
...
}
Ainsi, à l'intérieur sendMessage (Voir v), le notifyDataSetChanged() fait défiler la ListView acordingly, afin que je puisse voir les derniers messages de chat automatiquement:
public void sendMessage(View v) {
String msg = et.getText().toString();
if(msg.length() == 0){
return;
}
et.setText("");
String xml = ServerCom.sendAndGetChatMessages(campaignId, lastDate, msg);
Vector<ChatMessage> vetNew = Chat.parse(new InputSource(new StringReader(xml)));
//Pegando a última data
if(!vetNew.isEmpty()){
lastDate = vetNew.lastElement().getDateSent();
//Atualizando a tela
vetMsg.addAll(vetNew);
ca.notifyDataSetChanged();
}
}
Mais dans mon TimerTask, je ne peux pas. Le ListView est mis à jour, mais il ne défile pas automatiquement. Qu'est-ce que je fais mal?
private class chatPollingTask extends TimerTask {
@Override
public void run() {
String xml;
if(lastDate != null){
//Chama o Updater
xml = ServerCom.getChatMessages(campaignId, lastDate);
}else{
//Chama o init denovo
xml = ServerCom.getChatMessages(campaignId);
}
Vector<ChatMessage> vetNew = Chat.parse(new InputSource(new StringReader(xml)));
if(!(vetNew.isEmpty())){
//TODO: descobrir porque o chat não está rolando quando chegam novas mensagens
//Descobrir também como forçar o rolamento, enquanto o bug não for corrigido.
Log.d("CHAT", "New message(s) acquired!");
lastDate = vetNew.lastElement().getDateSent();
vetMsg.addAll(vetNew);
ca.notifyDataSetChanged();
}
}
}
Comment puis-je forcer le défilement vers le bas? J'ai essayé d'utiliser scrollTo en utilisant lv.getBottom() - lv.getHeight(), mais cela n'a pas fonctionné. Est-ce un bug dans le SDK Android?
Désolé pour la grande quantité de code, mais je suppose que cette façon la question devient assez claire.
J'ai essayé de créer une méthode dans mon activité avant de poster la question ici juste pour essayer de résoudre ce problème « en dehors du principal thread d'interface utilisateur », mais il ne fonctionne pas non plus. – Spidey
setSelection (vetMsgs.size() - 1) ne fonctionnait pas non plus. – Spidey
En fait, maintenant que j'y pense, je ne sais pas pourquoi notifyDatasetChanged devrait obliger la liste à défiler vers le bas. Il semble que vous devriez simplement appeler ListView.setSelection (vetNew.size() -1) juste après avoir appelé notifyDatasetChanged. –