Question

I am new for TCP protocol in Java. I want to make a server-client chatting interface. I can able to send the messages from client to server but when I send message from server to client then my android app crash suddenly. Here is my code..for Android Client..

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(for server)

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

--Edited--

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)
Was it helpful?

Solution

Only the original thread that created a view hierarchy can touch its views.

Your fragment is creating the views on one thread and you are calling notifyDataSetChanged within the (different) message receiver thread.

As the call stack in the log shows, notifyDataSetChanged results in call to requestLayout which is trying to update the associated view.

You need to ensure the notifyDataSetChanged call is run on the same thread as the views were created in. You can do this by calling runOnUiThread for the parent Activity.

OTHER TIPS

I understand your point after google for baseAdapter..and I update my display method which is responsible for updating the 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();

                    }
                });

    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top