Android 为什么我的按钮可以触发UI滚动,而活动中的我的TimerTask可以';T

Android 为什么我的按钮可以触发UI滚动,而活动中的我的TimerTask可以';T,android,listview,android-arrayadapter,Android,Listview,Android Arrayadapter,长话短说:“我的活动”的方法通过ArrayAdapter更新和滚动ListView,但用于轮询消息(显示在ListView中)的内部TimerTask的方法更新ListView,但不滚动它。为什么? 长话短说: 我有一个具有此布局的聊天活动: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" and

长话短说:“我的活动”的方法通过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>

问题是:在主布局中,我有一个用于聊天信息的编辑文本,以及一个用于发送信息的按钮。我已在活动范围中声明了适配器:

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;
...
}
公共类ChatManager扩展活动{
私人编辑;
私有ListView lv;
私有时间戳lastDate=null;
私人长途电话;
私人聊天室;
private List vetMsg=new ArrayList();
私人定时器;
私有静态最终int-CHAT\u POLLING\u周期=10000;
...
}
因此,在sendMessage(视图v)中,notifyDataSetChanged()会相应地滚动列表视图,这样我就可以自动查看最新的聊天信息:

 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();
  }
    }
公共无效发送消息(视图v){
字符串msg=et.getText().toString();
如果(msg.length()==0){
返回;
}
et.setText(“”);
字符串xml=ServerCom.sendAndGetChatMessages(活动ID、最后日期、消息);
Vector vetNew=Chat.parse(新的InputSource(新的StringReader(xml));
//Pegando aúltima数据
如果(!vetNew.isEmpty()){
lastDate=vetNew.lastElement().getDateSent();
//阿图利赞多电视台
vetMsg.addAll(vetNew);
ca.notifyDataSetChanged();
}
}
但在我的时间任务里,我不能。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();
   }

  }
 }
私有类chatPollingTask扩展TimerTask{
@凌驾
公开募捐{
字符串xml;
if(lastDate!=null){
//查莫更新程序
xml=ServerCom.getChatMessages(活动ID,最后日期);
}否则{
//查马诺伊诺沃酒店
xml=ServerCom.getChatMessages(活动ID);
}
Vector vetNew=Chat.parse(新的InputSource(新的StringReader(xml));
如果(!(vetNew.isEmpty()){
//TODO:descobrir porque o chat não estárolando quando chegam novas mensagens
//塔姆·科莫代表罗拉门托,恩奎托·巴格·诺代表科里吉多。
Log.d(“聊天”,“获取新消息!”);
lastDate=vetNew.lastElement().getDateSent();
vetMsg.addAll(vetNew);
ca.notifyDataSetChanged();
}
}
}
如何强制滚动到底部?我尝试过使用scrollTo和lv.getBottom()-lv.getHeight(),但没有成功。这是Android SDK中的一个bug吗


抱歉,代码太多了,但我想这样问题就很清楚了。

您需要在UI线程上调用对数据集(notifyDataSetChanged())的更改。TimerTask在不同的线程上被调用。有许多方法可以实现这一点,请参阅以获取方法列表


关于scrollTo,它不用于在滚动列表后滚动。它滚动整个视图元素..与您期望的不完全一样。相反,请使用ListView.setSelection方法之一

在将问题发布到这里之前,我尝试在活动中创建一个方法,只是为了解决这个“主UI线程之外”的问题,但它也不起作用。事实上,现在我想起来了,我不确定为什么notifyDatasetChanged必然会导致列表滚动到底部。似乎您应该在调用notifyDatasetChanged之后立即调用ListView.setSelection(vetNew.size()-1)。这正是我正在做的,现在不工作。。。vetMsg.addAll(vetNew);ca.notifyDataSetChanged();lv.setSelection(vetMsg.size()-1)。。。我认为notifyDataSetChanged()会自动滚动它,因为我的ListView将stackFromBottom属性设置为true,而sendMessage按钮的作用几乎相同(发布到Web服务,然后以XML格式检索新状态),只与notifyDataSetChanged()一起工作.从stackFromBottom查看文档…我认为它只是翻转项目1所在的位置,不会影响列表的滚动。您是否尝试过将TranscriptMode设置为true?它声称总是滚动显示新项目。我不知道为什么选举不起作用,当你称之为选举时,你会看到什么样的行为?什么都没发生?什么都没发生。我将尝试setSelection(0),因为stackFromBottom会反转项目顺序。