Android的问题ListView的更新基于动态关闭套接字 [英] Android issue updating ListView dynamically based off sockets

查看:155
本文介绍了Android的问题ListView的更新基于动态关闭套接字的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Android应用程序是一个简单的聊天服务器的客户端。我能够连接到服务器和我的ObjectStreams。问题是,当我收到一个消息,即在其更新列表视图我的显示信息处理我的服务器连接调用线程。

我收到错误只有创建一个视图层次可以触摸其观点原来的线程。

我是pretty确信它,因为我打电话给我的displayMessage()从我的连接线的方法,但我不知道如何安排我的线程对服务器的连接,并动态更新列表视图我。

下面是我的主要活动。

 公共类MainActivity延伸活动{专用连接serverConnection;
私人的ArrayList<串GT;时listItems =新的ArrayList<串GT;();
私人ArrayAdapter<串GT;适配器;
/ **
 *将ArrayAdaptor,并启动connectThread。
 * /
@覆盖
保护无效的onCreate(捆绑savedInstanceState){
    super.onCreate(savedInstanceState);
    的setContentView(R.layout.activity_main);    runOnUiThread(新的Runnable(){
        公共无效的run(){
            ListView控件列表视图=(ListView控件)findViewById(R.id.list);
            适配器=新ArrayAdapter<串GT;(MainActivity.this,
                    android.R.layout.simple_list_item_1,
                            listItems中);
            listview.setAdapter(适配器);
        }
    });
    / **
     *开始一个新的连接线程
     * /
    螺纹connectThread =新主题(新的Runnable(){
        公共无效的run(){
            serverConnection =新的连接(MainActivity.this);
            serverConnection.run();
        }
    });
    connectThread.start();
}
/ **
 *添加一条消息列表视图。
 * @参数字符串 - 消息以复加。
 * /
公共无效displayMessage(字符串字符串){
    listItems.add(字符串);
    adapter.notifyDataSetChanged();
}
}

下面是我的连接线程类。

 公共类连接扩展Thread {私人客户端的Socket;
私人ObjectOutputStream的输出;
私人ObjectInputStream的输入;
私人MainActivity mainActivity;
私人字符串信息;
/ **
 *构造开始插座和ObjectStreams
 *
 * @参数mainActivity - 参考在MainActivity
 * /
公共连接(MainActivity mainActivity){
    this.mainActivity = mainActivity;
    尝试{
        客户端=新的Socket(192.168.1.105,50499);
        mainActivity.displayMessage(连接到:
                + client.getInetAddress()的gethostname())。
        输出=新的ObjectOutputStream(client.getOutputStream());
        output.flush();
        输入=新的ObjectInputStream(client.getInputStream());
    }赶上(IOException异常五){
        e.printStackTrace();
    }}
/ **
 *为线程运行的方法。
 * /
公共无效的run(){
    为(;;){
        尝试{
            消息=(字符串)input.readObject();
            mainActivity.displayMessage(消息);
        }赶上(OptionalDataException E){
            // TODO自动生成catch块
            e.printStackTrace();
        }赶上(ClassNotFoundException的E){
            // TODO自动生成catch块
            e.printStackTrace();
        }赶上(IOException异常五){
            // TODO自动生成catch块
            e.printStackTrace();
        }
    }
}
}


解决方案

您是在后台线程更新界面。您应该更新UI线程UI。移动你的code,在后台线程更新UI。你是在后台线程刷新列表视图。

  mainActivity.displayMessage(连接到
            + client.getInetAddress()的gethostname())。
 mainActivity.displayMessage(消息); 公共无效displayMessage(字符串字符串){
   listItems.add(字符串);
   adapter.notifyDataSetChanged();
   }

以上应的线程之外,也可以使用runonuithread内螺纹更新UI。

  runOnUiThread(新的Runnable(){
            @覆盖
            公共无效的run(){
               //更新UI
            }
        });

的另一种方式是使用AsyncTask的。做onPostExecute在doInbackground()所有网络相关的运行和更新用户界面()。

异步任务

编辑:不知道你正在尝试做的。

 公共类MainActivity延伸活动{ 专用连接serverConnection;
 私人的ArrayList<串GT;时listItems =新的ArrayList<串GT;();
 私人ArrayAdapter<串GT;适配器; @覆盖
 保护无效的onCreate(捆绑savedInstanceState){
 super.onCreate(savedInstanceState);
 的setContentView(R.layout.activity_main);
        ListView控件列表视图=(ListView控件)findViewById(R.id.lv);
        适配器=新ArrayAdapter<串GT;(MainActivity.this,
                android.R.layout.simple_list_item_1,
                        listItems中);
        listview.setAdapter(适配器);
     //使用一个按钮,按钮上​​点击启动线程。螺纹connectThread =新主题(新的Runnable(){
    公共无效的run(){
        serverConnection =新的连接(MainActivity.this);
        serverConnection.run();
    }
});
connectThread.start();
}公共无效displayMessage(字符串字符串){
listItems.add(字符串);
adapter.notifyDataSetChanged();
}
一流的连接扩展Thread {私人客户端的Socket;
私人ObjectOutputStream的输出;
私人ObjectInputStream的输入;
私人MainActivity mainActivity;
私人字符串信息;公共连接(MainActivity mainActivity){
this.mainActivity = mainActivity;
尝试{
    客户端=新的Socket(192.168.1.105,50499);
    runOnUiThread(新的Runnable(){
        @覆盖
        公共无效的run(){
            displayMessage(连接到:
                   );
        }
    });    输出=新的ObjectOutputStream(client.getOutputStream());
    output.flush();
    输入=新的ObjectInputStream(client.getInputStream());
}赶上(IOException异常五){
    e.printStackTrace();
}
} 公共无效的run(){
 为(;;){
    尝试{
          消息=(字符串)input.readObject();
          runOnUiThread(新的Runnable(){
              @覆盖
              公共无效的run(){
                displayMessage(消息);
              }
          });    }赶上(OptionalDataException E){
        // TODO自动生成catch块
        e.printStackTrace();
    }赶上(ClassNotFoundException的E){
        // TODO自动生成catch块
        e.printStackTrace();
    }赶上(IOException异常五){
        // TODO自动生成catch块
        e.printStackTrace();
    }
}
}
}
}

I have an android application that is a client for a simple chat server. I am able to connect to the server and my ObjectStreams. The problem is when I receive a message, the thread that handles my server connection calls upon my display message which updates the list view.

I am getting the error "only the original thread that created a view hierarchy can touch its views."

I am pretty sure its because I'm calling my displayMessage() method from my connect thread, but I am not sure how to organize my threads to have a connection to the server and dynamically update my listview.

Here is my main activity.

public class MainActivity extends Activity {

private Connection serverConnection;
private ArrayList<String> listItems = new ArrayList<String>();
private ArrayAdapter<String> adapter;
/**
 * Sets the ArrayAdaptor, and starts the connectThread. 
 */
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    runOnUiThread(new Runnable() {
        public void run() {
            ListView listview = (ListView) findViewById(R.id.list);
            adapter = new ArrayAdapter<String>(MainActivity.this,
                    android.R.layout.simple_list_item_1, 
                            listItems);
            listview.setAdapter(adapter);
        }
    }); 
    /**
     * Starts a new connection Thread
     */
    Thread connectThread = new Thread(new Runnable(){
        public void run(){
            serverConnection = new Connection(MainActivity.this);
            serverConnection.run();
        }
    });
    connectThread.start();
}
/**
 * Adds a message to the list view. 
 * @param string - message to be added. 
 */
public void displayMessage(String string) {
    listItems.add(string);
    adapter.notifyDataSetChanged();
}
}

Here is my connection thread class.

public class Connection extends Thread {

private Socket client;
private ObjectOutputStream output;
private ObjectInputStream input;
private MainActivity mainActivity;
private String message;
/**
 * Constructor starts the socket and ObjectStreams
 * 
 * @param mainActivity - reference to the MainActivity
 */
public Connection(MainActivity mainActivity) {
    this.mainActivity = mainActivity;
    try {
        client = new Socket("192.168.1.105", 50499);
        mainActivity.displayMessage("Connected to: "
                + client.getInetAddress().getHostName());
        output = new ObjectOutputStream(client.getOutputStream());
        output.flush();
        input = new ObjectInputStream(client.getInputStream());
    } catch (IOException e) {
        e.printStackTrace();
    }

}
/**
 * Run method for the Thread. 
 */
public void run() {
    for (;;) {
        try {
            message = (String) input.readObject();
            mainActivity.displayMessage(message);
        } catch (OptionalDataException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
}

解决方案

You are updating Ui on the background thread. You should update ui on the ui thread. Move your code that updates ui in the background thread. You are refreshing your listview on the background thread.

 mainActivity.displayMessage("Connected to: "
            + client.getInetAddress().getHostName()); 
 mainActivity.displayMessage(message);

 public void displayMessage(String string) {
   listItems.add(string);
   adapter.notifyDataSetChanged(); 
   }

The above should be outside the thread or You can use runonuithread inside the thread to update ui.

      runOnUiThread(new Runnable() {
            @Override
            public void run() {
               // update ui 
            }
        });

Another way would be to use asynctask. Do all your network related operation in doInbackground() and update ui in onPostExecute().

Async Task

Edit: Not sure what you are trying to do.

 public class MainActivity extends Activity {

 private Connection serverConnection;
 private ArrayList<String> listItems = new ArrayList<String>();
 private ArrayAdapter<String> adapter;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
        ListView listview = (ListView) findViewById(R.id.lv);
        adapter = new ArrayAdapter<String>(MainActivity.this,
                android.R.layout.simple_list_item_1, 
                        listItems);
        listview.setAdapter(adapter);
     // use a button and on button click start the thread.

Thread connectThread = new Thread(new Runnable(){
    public void run(){
        serverConnection = new Connection(MainActivity.this);
        serverConnection.run();
    }
});
connectThread.start();
}

public void displayMessage(String string) {
listItems.add(string);
adapter.notifyDataSetChanged();
}
class Connection extends Thread {

private Socket client;
private ObjectOutputStream output;
private ObjectInputStream input;
private MainActivity mainActivity;
private String message;

public Connection(MainActivity mainActivity) {
this.mainActivity = mainActivity;
try {
    client = new Socket("192.168.1.105", 50499);
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            displayMessage("Connected to: "
                   );
        }
    });

    output = new ObjectOutputStream(client.getOutputStream());
    output.flush();
    input = new ObjectInputStream(client.getInputStream());
} catch (IOException e) {
    e.printStackTrace();
}
}

 public void run() {
 for (;;) {
    try {
          message = (String) input.readObject();
          runOnUiThread(new Runnable() {
              @Override
              public void run() {
                displayMessage(message);
              }
          });



    } catch (OptionalDataException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
}
}
}

这篇关于Android的问题ListView的更新基于动态关闭套接字的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆