2010-05-19 4 views
0

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.

Répondre

0

Vous devez invoquer des modifications à l'ensemble de données (notifyDataSetChanged()) sur le thread d'interface utilisateur. Le TimerTask est appelé sur un thread différent. Il y a un certain nombre de manières d'accomplir ceci, voir this blog post pour une liste de manières.

En ce qui concerne scrollTo, qui ne sert pas à défiler dans le depuis de faire défiler une liste. Il fait défiler l'ensemble de l'élément de vue .. pas exactement ce que vous attendez. Au lieu de cela, utilisez l'une des méthodes ListView.setSelection.

+0

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

+0

setSelection (vetMsgs.size() - 1) ne fonctionnait pas non plus. – Spidey

+0

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. –