1

長い話短い: 私のアクティビティのメソッドは、本来のように ArrayAdapter を介して ListView を更新およびスクロールしますが、(ListView に表示される) メッセージをポーリングするための内部 TimerTask のメソッドは、ListView を更新しますが、スクロールしません。なんで?

長い話:

このレイアウトのチャット アクティビティがあります。

<?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 (id messageList を持つ) は ArrayAdapter によって取り込まれ、以下の XML を膨張させ、その中の文字列を置き換えます。

<?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>

問題は: メイン レイアウトには、チャット メッセージ用の EditText と、メッセージを送信するための Button があります。アクティビティ スコープでアダプターを宣言しました。

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;
...
}

そのため、sendMessage(View v) 内では、notifyDataSetChanged() がそれに応じて ListView をスクロールするため、最新のチャット メッセージを自動的に表示できます。

 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();
  }
    }

しかし、私の TimerTask の中では、できません。ListView は更新されていますが、自動的にスクロールしません。私は何を間違っていますか?

 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();
   }

  }
 }

スクロールを一番下に強制するにはどうすればよいですか? lv.getBottom()-lv.getHeight() を使用して scrollTo を使用しようとしましたが、機能しませんでした。これは Android SDK のバグですか?

膨大な量のコードで申し訳ありませんが、この方法で質問がかなり明確になると思います。

4

1 に答える 1

0

UI スレッドでデータセットへの変更 (notifyDataSetChanged()) を呼び出す必要があります。TimerTask は別のスレッドで呼び出されます。これを実現するにはいくつかの方法があります。方法のリストについては、このブログ投稿を参照してください。

scrollTo に関しては、リストをスクロールするため、スクロールには使用されません。View 要素全体をスクロールします。期待どおりではありません。代わりに、ListView.setSelection メソッドのいずれかを使用してください。

于 2010-05-19T19:01:38.617 に答える