Java服务器无法向Android客户端发送消息

时间:2013-10-24 14:35:32

标签: android tcpclient listadapter

我是Java中TCP协议的新手。我想建立一个服务器 - 客户端聊天界面。我可以将消息从客户端发送到服务器但是当我从服务器发送消息到客户端时,我的Android应用程序突然崩溃。 这是我的代码..对于Android客户端..

public class chatWithServer extends Fragment
{
    private ListView mList;
    private ArrayList<String> arrayList;
    private MyCustomAdapter mAdapter;

   Button send;
   EditText editText;
   String serverMessage;
    PrintWriter out;
    BufferedReader in;
    private static final String HOST = "192.168.48.1";  
    private static final int PORT = 5000; 
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState)
    {
        //super.onCreate(savedInstanceState);
        final View myFragmentView = inflater.inflate(
                R.layout.activity_main, container, false);
        arrayList = new ArrayList<String>();

         editText = (EditText)myFragmentView. findViewById(R.id.editText);
        send = (Button)myFragmentView.findViewById(R.id.send_button);
       send.setOnClickListener(onClickSend(myFragmentView));

        //relate the listView from java to the one created in xml
        mList = (ListView)myFragmentView.findViewById(R.id.list);
        mAdapter = new MyCustomAdapter(getActivity(), arrayList);
        mList.setAdapter(mAdapter);


        connectServerTask();

        return myFragmentView;

    }
    //-------->By clicking Send Button<---------//////
    private OnClickListener onClickSend(final View myFragmentView) {
        return new OnClickListener() {

            @Override
            public void onClick(View v) {

                String message = editText.getText().toString();

                //add the text in the arrayList
                arrayList.add("c: " + message);

                //sends the message to the server
                sendToServer(message);

                //refresh the list
                mAdapter.notifyDataSetChanged();
                editText.setText("");
            }


        };
    }

    private void connectServerTask() {
        Runnable runnable= new Runnable() {

            @Override
            public void run() {

                 setSocket();
            }
            private void setSocket() {
                try {
                    // Create Socket instance
                    Socket socket = new Socket(HOST, PORT);

                    out = new PrintWriter(new BufferedWriter(new                 OutputStreamWriter(socket.getOutputStream())), true);
                    out.println("Connected to Client");
                    try{
                    in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    serverMessage =in.readLine();
                    if(serverMessage!=null) {
                         //sends the message to the server
                     chatUp(serverMessage);
                    }
                    serverMessage=null;



                } catch (UnknownHostException e) {
                    e.printStackTrace();
                } finally{
                    socket.close();
                }
                    }catch (IOException e) {
                    e.printStackTrace();
                }

            }
                         private void chatUp(String message) {

               arrayList.add(message);
               mAdapter.notifyDataSetChanged();
            }           

        };
        new Thread(runnable).start(); 

    }
    //method of sending message to server
public void sendToServer(String message){



      if (out != null && !out.checkError())
          {
              out.println(message);
              out.flush();
           };
    }

    }

Here is the code for Java-Server

    public class TCPServer extends Thread {

        public static final int SERVERPORT = 5000;
        private boolean running = false;
        private PrintWriter mOut;
        private OnMessageReceived messageListener;

        public static void main(String[] args) {

            //opens the window where the messages will be received and sent
            ServerBoard frame = new ServerBoard();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.pack();
            frame.setVisible(true);

        }

        /**
     * Constructor of the class
     * @param messageListener listens for the messages
     */
    public TCPServer(OnMessageReceived messageListener) {
        this.messageListener = messageListener;
    }


    /**
     * Method to send the messages from server to client
     * @param message the message sent by the server
     */
    public void sendMessage(String message){
        if (mOut != null && !mOut.checkError()) {
            mOut.println(message);
            mOut.flush();
        }
    }

    @SuppressWarnings("resource")
    @Override
    public void run() {
        super.run();

        running = true;

        try {
            System.out.println("S: Connecting...");

            //create a server socket. A server socket waits for requests to come in over the network.
            ServerSocket serverSocket = new ServerSocket(SERVERPORT);

            //create client socket... the method accept() listens for a connection to be made to this socket and accepts it.
            Socket client = serverSocket.accept();
            System.out.println("S: Receiving...");

             try {

                //sends the message to the client
                mOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true);

                //read the message received from client
                BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));

                //in this while we wait to receive messages from client (it's an infinite loop)
                //this while it's like a listener for messages
                while (running) {
                    String message = in.readLine();

                    if (message != null && messageListener != null) {
                        //call the method messageReceived from ServerBoard class
                        messageListener.messageReceived(message);
                    }
                }

            } catch (Exception e) {
                System.out.println("S: Error");
                e.printStackTrace();
            } finally {
                client.close();
                System.out.println("S: Done.");
            }

        } catch (Exception e) {
            System.out.println("S: Error");
            e.printStackTrace();
        }

    }


    //Declare the interface. The method messageReceived(String message) will must be implemented in the ServerBoard
    //class at on startServer button click
    public interface OnMessageReceived {
        public void messageReceived(String message);
    }

}

ServerBoard.java(用于服务器)

public class ServerBoard extends JFrame {//jFrame is for the desplaying the window and for nice GUI
    private JTextArea messagesArea;//A JTextArea is a multi-line area that displays plain text.
    private JButton sendButton;
    private JTextField message;//JTextField is a lightweight component that allows the editing of a single line of text.
    private JButton startServer;
    private TCPServer mServer;

    public ServerBoard() {

        super("ServerBoard");

        JPanel panelFields = new JPanel();
        panelFields.setLayout(new BoxLayout(panelFields,BoxLayout.X_AXIS));

        JPanel panelFields2 = new JPanel();
        panelFields2.setLayout(new BoxLayout(panelFields2,BoxLayout.X_AXIS));

        //here we will have the text messages screen
        messagesArea = new JTextArea();
        messagesArea.setColumns(30);
        messagesArea.setRows(10);
        messagesArea.setEditable(false);

        sendButton = new JButton("Send");
        sendButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // get the message from the text view
                String messageText = message.getText();
                // add message to the message area
                messagesArea.append("\n" + messageText);
                // send the message to the client
                mServer.sendMessage(messageText);
                // clear text
                message.setText("");
            }
        });

        startServer = new JButton("Start");
        startServer.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // disable the start button
                startServer.setEnabled(false);

                //creates the object OnMessageReceived asked by the TCPServer constructor
                mServer = new TCPServer(new TCPServer.OnMessageReceived() {
                    @Override
                    //this method declared in the interface from TCPServer class is implemented here
                    //this method is actually a callback method, because it will run every time when it will be called from
                    //TCPServer class (at while)
                    public void messageReceived(String message) {
                        messagesArea.append("\n "+message);
                    }
                });
                mServer.start();

            }
        });

        //the box where the user enters the text (EditText is called in Android)
        message = new JTextField();
        message.setSize(200, 20);

        //add the buttons and the text fields to the panel
        panelFields.add(messagesArea);
        panelFields.add(startServer);

        panelFields2.add(message);
        panelFields2.add(sendButton);

        getContentPane().add(panelFields);
        getContentPane().add(panelFields2);


        getContentPane().setLayout(new BoxLayout(getContentPane(),BoxLayout.Y_AXIS));

        setSize(300, 170);
        setVisible(true);
    }
}

- 编辑 -

10-24 17:04:07.039: E/AndroidRuntime(15911): FATAL EXCEPTION: Thread-1131
10-24 17:04:07.039: E/AndroidRuntime(15911): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
10-24 17:04:07.039: E/AndroidRuntime(15911):    at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:5908)
10-24 17:04:07.039: E/AndroidRuntime(15911):    at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:837)
10-24 17:04:07.039: E/AndroidRuntime(15911):    at android.view.View.requestLayout(View.java:15792)
10-24 17:04:07.039: E/AndroidRuntime(15911):    at android.view.View.requestLayout(View.java:15792)
10-24 17:04:07.039: E/AndroidRuntime(15911):    at android.view.View.requestLayout(View.java:15792)
10-24 17:04:07.039: E/AndroidRuntime(15911):    at android.view.View.requestLayout(View.java:15792)
10-24 17:04:07.039: E/AndroidRuntime(15911):    at android.view.View.requestLayout(View.java:15792)
10-24 17:04:07.039: E/AndroidRuntime(15911):    at android.view.View.requestLayout(View.java:15792)
10-24 17:04:07.039: E/AndroidRuntime(15911):    at android.view.View.requestLayout(View.java:15792)
10-24 17:04:07.039: E/AndroidRuntime(15911):    at android.widget.AbsListView.requestLayout(AbsListView.java:1837)
10-24 17:04:07.039: E/AndroidRuntime(15911):    at android.widget.AdapterView$AdapterDataSetObserver.onChanged(AdapterView.java:813)
10-24 17:04:07.039: E/AndroidRuntime(15911):    at android.widget.AbsListView$AdapterDataSetObserver.onChanged(AbsListView.java:5998)
10-24 17:04:07.039: E/AndroidRuntime(15911):    at android.database.DataSetObservable.notifyChanged(DataSetObservable.java:37)
10-24 17:04:07.039: E/AndroidRuntime(15911):    at android.widget.BaseAdapter.notifyDataSetChanged(BaseAdapter.java:50)
10-24 17:04:07.039: E/AndroidRuntime(15911):    at com.example.cardioapp.database.chatWithServer$2.display(chatWithServer.java:142)
10-24 17:04:07.039: E/AndroidRuntime(15911):    at com.example.cardioapp.database.chatWithServer$2.setSocket(chatWithServer.java:123)
10-24 17:04:07.039: E/AndroidRuntime(15911):    at com.example.cardioapp.database.chatWithServer$2.run(chatWithServer.java:94)
10-24 17:04:07.039: E/AndroidRuntime(15911):    at java.lang.Thread.run(Thread.java:841)

2 个答案:

答案 0 :(得分:0)

  

只有创建视图层次结构的原始线程才能触及它   视图。

您的片段正在一个线程上创建视图,并且您在(不同的)消息接收器线程中调用notifyDataSetChanged。

当日志中的调用堆栈显示时,notifyDataSetChanged会导致调用requestLayout,并尝试更新相关视图。

您需要确保notifyDataSetChanged调用在创建视图的同一个线程上运行。您可以通过为父Activity调用runOnUiThread来执行此操作。

答案 1 :(得分:0)

我理解你在google for baseAdapter之后的观点......我更新了我的显示方法,它负责更新baseadapter ..

private void display(String... message) {

                arrayList.add(message[0]);
                 Log.e("setSocket", "arraylist");
                getActivity().runOnUiThread(new Runnable() {

                    @Override
                    public void run() {

                        Log.e("display", "runonuithread");
                        mAdapter.notifyDataSetChanged();

                    }
                });

    }