【问题标题】:Android issue updating ListView dynamically based off socketsAndroid 问题基于套接字动态更新 ListView
【发布时间】:2013-05-29 16:12:45
【问题描述】:

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

我收到错误消息“只有创建视图层次结构的原始线程才能接触其视图。”

我很确定这是因为我正在从我的连接线程调用我的 displayMessage() 方法,但我不确定如何组织我的线程以连接到服务器并动态更新我的列表视图。

这是我的主要活动。

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

这是我的连接线程类。

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

【问题讨论】:

    标签: java android multithreading listview


    【解决方案1】:

    您正在后台线程上更新 Ui。您应该在 ui 线程上更新 ui。在后台线程中移动更新 ui 的代码。您正在后台线程上刷新列表视图。

     mainActivity.displayMessage("Connected to: "
                + client.getInetAddress().getHostName()); 
     mainActivity.displayMessage(message);
    
     public void displayMessage(String string) {
       listItems.add(string);
       adapter.notifyDataSetChanged(); 
       }
    

    以上应该是线程外的或者你可以在线程内使用runonuithread来更新ui。

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

    另一种方法是使用异步任务。在 doInbackground() 中执行所有与网络相关的操作,并在 onPostExecute() 中更新 ui。

    Async Task

    编辑:不确定您要做什么。

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

    【讨论】:

    • @Collin 在您的 displayMessage 方法中,您正在刷新列表视图。并且您的显示方法是从线程中调用的。因此,使用 runOnUiThread 或使用 asyntask 在 ui 线程上更新 ui。检查链接中提供的链接
    • @Collin 这就是为什么在编辑中我将连接类设置为活动类的内部类
    • 检查并运行相同的。如果它有助于通过单击勾号将答案标记为已接受。如果您有足够的声誉,您也可以投票。如果您有任何疑问,请告诉我
    • 我想您应该将 Connection 类的构造函数中的代码移动到 run 方法。同样在这种情况下,我建议您使用 asynctask。这很容易。你有 3 个被覆盖的方法。 onPreExecute() 在 ui 线程上调用。 onPostExecute() 涉及 ui 线程和 doInbackground() 用于网络相关操作。所以它更容易,没有混淆
    • 我的计划是更改我的代码以使用异步任务。我只是想使用线程来学习和练习
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-15
    • 2016-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-28
    • 1970-01-01
    相关资源
    最近更新 更多