Jurko Guba
Jurko Guba

Reputation: 638

java.lang.ArrayIndexOutOfBoundsException really weird

I know that the exception I am getting in the log cat has A VERY STRAIGHTFORWARD name. My only problem is that I can't identify what is causing my exception. I have created an PC-Android multiclient chat.

The PC version works 100% with the server and the client. I implemented the same technique from the PC client to the android client and chatting WORKS.

The only problem I am getting, is when I connect with the android, the clientArea (tracks all users connected), is not tracking the other names, but rather multiples of the android client username. ie. I connect ONLY on android with username:Jurko, the clientArea will have 2 people called Jurko instead of only having one.

Logcat:

10-11 17:19:08.221: ERROR/AndroidRuntime(12379): FATAL EXCEPTION: main
        java.lang.ArrayIndexOutOfBoundsException: length=2; index=2
        at com.example.JurkoAndroidChat.MyActivity$ServerTask.onProgressUpdate(MyActivity.java:175)
        at com.example.JurkoAndroidChat.MyActivity$ServerTask.onProgressUpdate(MyActivity.java:130)
        at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:647)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:4895)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:994)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:761)
        at dalvik.system.NativeStart.main(Native Method)

Android Client:

package com.example.JurkoAndroidChat;

import android.app.Activity;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.view.View;

import java.net.*;
import java.io.*;
import java.util.*;



public class MyActivity extends Activity {
    /**
     * Called when the activity is first created.
     */
    // Right here, we connecting the components of the main.xml form to code
    Button connectButton, disconnectButton, sendButton;
    TextView chatArea, clientArea;
    EditText messageField, usernameField, ipField;

    //Extra variables and sockets
    String username, serverIP;
    int Port = 5000;
    Socket sock;
    PrintWriter out;
    BufferedReader in;
    ArrayList<String> userList = new ArrayList();
    Boolean isConnected = false, exceptionCaught = false;

    ServerTask serverTask;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        System.out.println("Working?");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        connectButton = (Button)findViewById(R.id.button);
        sendButton = (Button)findViewById(R.id.button1);
        disconnectButton = (Button)findViewById(R.id.button2);

        chatArea = (TextView)findViewById(R.id.textView2);
        clientArea = (TextView)findViewById(R.id.textView3);

        messageField = (EditText)findViewById(R.id.editText2);
        usernameField = (EditText)findViewById(R.id.editText);
        ipField = (EditText)findViewById(R.id.editText1);



        connectButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //To change body of implemented methods use File | Settings | File Templates.
                if (isConnected == false) {
                    username = usernameField.getText().toString();
                    usernameField.setFocusable(false);
                    usernameField.setClickable(false);
                    serverIP = ipField.getText().toString();
                    ipField.setFocusable(false);
                    ipField.setClickable(false);
                    serverTask = new ServerTask();
                    serverTask.execute();


                } else if (isConnected == true) {
                    chatArea.append("You are already connected to the server.\n");
                }
            }
        });

        disconnectButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //To change body of implemented methods use File | Settings | File Templates.
                String bye = (username + "µ µDisconnect");
                try {
                    out.print(bye);
                    out.flush();
                    chatArea.append("Disconnected.\n");
                    sock.close();

                } catch (Exception e) {  } // nothing caught so far.
                isConnected = false;
                usernameField.setFocusable(true);
                usernameField.setClickable(true);
                usernameField.setFocusableInTouchMode(true);
                ipField.setFocusable(true);
                ipField.setFocusableInTouchMode(true);
                ipField.setClickable(true);
                clientArea.setText("");

            }
        });

        sendButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //To change body of implemented methods use File | Settings | File Templates.
                String nothing = "";
                if ((messageField.getText().toString().equals(nothing))) {
                    messageField.setText("");
                    messageField.requestFocus();
                } else {
                    try {
                        out.println(username + "µ" + messageField.getText().toString() + "µ" + "Chat");
                        out.flush();


                    } catch (Exception e) {
                        Log.e("Error", e.toString());
                        chatArea.append("Message was not sent.\n" + e);
                    }
                    messageField.setText("");
                    messageField.requestFocus();
                }
            }
        });

    }


    public class ServerTask extends AsyncTask<Void, Void, Void> {

        String[] data;
        String stream, done = "Done", connect = "Connect", disconnect = "Disconnect", chat = "Chat";
        @Override
        protected Void doInBackground(Void... voids) {
            try {
                Log.i("Asynctask", "doInBackground");
                sock = new Socket(serverIP, Port);
                out = new PrintWriter(sock.getOutputStream());
                in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
                out.println(username + "µ" + "has connected." + "µ" + "Connect");
                out.flush();
                isConnected = true;


            } catch (Exception ex) {
                    exceptionCaught = true;
                Log.e("Application", ex.toString());

            }
            try {
                while ((stream = in.readLine()) != null) {

                    publishProgress();
                }
            } catch (Exception e) {}

            return null;
        }

        public void writeUsers() {
            clientArea.setText("");
            Iterator<String> iterator = userList.iterator();
            while (iterator.hasNext()) {
                String token = iterator.next();
                clientArea.append(token + '\n');
            }
        }

        @Override
        protected void onProgressUpdate(Void... values) {

                    data = stream.split("µ");

                    if (data[2].equals(chat)) {
                        if (data[1].equals("has connected.") || data[1].equals("has disconnected."))
                            chatArea.append(data[0] + " " + data[1] + '\n');
                        else
                            chatArea.append(data[0] + ": " + data[1] + '\n');
                    } else if (data[2].equals(connect)) {
                        userList.add(data[0]);
                        writeUsers();
                    } else if (data[2].equals(disconnect)) {
                        userList.remove(data[0]);
                        writeUsers();
                    } else if (data[2].equals(done))
                        userList.clear();

           }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            if (exceptionCaught == true) {
                chatArea.append("Unable to connect to " + serverIP + " at port " + Port + ".\n");
                usernameField.setFocusable(true);
                usernameField.setClickable(true);
                usernameField.setFocusableInTouchMode(true);
                ipField.setFocusableInTouchMode(true);
                ipField.setFocusable(true);
                ipField.setClickable(true);
                exceptionCaught = false;

            }
                //To change body of overridden methods use File | Settings | File Templates.
        }
    }












}

Server (On PC):

/*
 * To change this template, choose Tools : Templates
 * and open the template in the editor.
 */

/*
 * ServerWindow.java
 *
 * Created on Apr 23, 2011, 4:16:05 PM
 */


import java.io.*;
import java.net.*;
import java.util.*;
/**
 *
 * @author JurkoGuba
 */
public class ServerWindow extends javax.swing.JFrame {
    ArrayList clientOutputStreams;
    ArrayList<String> onlineUsers;

    public class ClientHandler implements Runnable  {
        BufferedReader reader;
        Socket sock;
        PrintWriter client;


        public ClientHandler(Socket clientSocket, PrintWriter user) {
            // new inputStreamReader and then add it to a BufferedReader
            client = user;
            try {
                sock = clientSocket;
                reader = new BufferedReader(new InputStreamReader(sock.getInputStream()));
            } // end try
            catch (Exception ex) {
                outputPane.append("Error beginning StreamReader. \n");
            } // end catch

        } // end ClientHandler()

        public void run() {
            String message, connect = "Connect", disconnect = "Disconnect", chat = "Chat" ;
            String[] data;

            try {
                while ((message = reader.readLine()) != null) {

                    outputPane.append("Received: " + message + "\n");
                    data = message.split("µ");

                    if (data[2].equals(connect)) {

                        tellEveryone((data[0] + "µ" + data[1] + "µ" + chat));
                        userAdd(data[0]);

                    } else if (data[2].equals(disconnect)) {

                        tellEveryone((data[0] + "µhas disconnected." + "µ" + chat));
                        userRemove(data[0]);

                    } else if (data[2].equals(chat)) {

                        tellEveryone(message);

                    } else {
                        outputPane.append("No Conditions were met. \n");
                    }


                } // end while
            } // end try
            catch (Exception ex) {
                outputPane.append("Lost a connection. \n");
                ex.printStackTrace();
                clientOutputStreams.remove(client);
            } // end catch
        } // end run()
    } // end class ClientHandler
    /** Creates new form ServerWindow */
    public ServerWindow() {
        initComponents();
    }



    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        outputPane = new javax.swing.JTextArea();
        startButton = new javax.swing.JButton();
        stopButton = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("House Server");

        outputPane.setColumns(20);
        outputPane.setEditable(false);
        outputPane.setLineWrap(true);
        outputPane.setRows(5);
        outputPane.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        jScrollPane1.setViewportView(outputPane);

        startButton.setText("Start");
        startButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                startButtonActionPerformed(evt);
            }
        });

        stopButton.setText("Stop");
        stopButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addGroup(layout.createSequentialGroup()
                                .addContainerGap()
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                        .addGroup(layout.createSequentialGroup()
                                                .addComponent(startButton, javax.swing.GroupLayout.PREFERRED_SIZE, 179, javax.swing.GroupLayout.PREFERRED_SIZE)
                                                .addGap(18, 18, 18)
                                                .addComponent(stopButton, javax.swing.GroupLayout.DEFAULT_SIZE, 183, Short.MAX_VALUE))
                                        .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE))
                                .addContainerGap())
        );
        layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addGroup(layout.createSequentialGroup()
                                .addContainerGap()
                                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 229, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addGap(18, 18, 18)
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                        .addComponent(startButton)
                                        .addComponent(stopButton))
                                .addContainerGap(19, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>                        

    private void startButtonActionPerformed(java.awt.event.ActionEvent evt) {
        // TODO add your handling code here:
        Thread starter = new Thread(new ServerStart());
        starter.start();

        outputPane.append("Server started. \n");
    }

    private void stopButtonActionPerformed(java.awt.event.ActionEvent evt) {
        // TODO add your handling code here:

        tellEveryone("Serverµis stopping and all users will be disconnected.\nµChat");
        outputPane.append("Server stopping... \n");

    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new ServerWindow().setVisible(true);
            }
        });
    }


    public class ServerStart implements Runnable {
        public void run() {
            clientOutputStreams = new ArrayList();
            onlineUsers = new ArrayList();

            try {
                ServerSocket serverSock = new ServerSocket(5000);

                while (true) {
                    // set up the server writer function and then begin at the same
                    // the listener using the Runnable and Thread
                    Socket clientSock = serverSock.accept();
                    PrintWriter writer = new PrintWriter(clientSock.getOutputStream());
                    clientOutputStreams.add(writer);

                    // use a Runnable to start a 'second main method that will run
                    // the listener
                    Thread listener = new Thread(new ClientHandler(clientSock, writer));
                    listener.start();
                    outputPane.append("Got a connection. \n");
                } // end while
            } // end try
            catch (Exception ex)
            {
                outputPane.append("Error making a connection. \n");
            } // end catch

        } // end go()
    }

    public void userAdd (String data) {
        String add = "µ µConnect", done = "Serverµ µDone", name = data;
        outputPane.append("Before " + name + " added. \n");
        onlineUsers.add(name);
        outputPane.append("After " + name + " added. \n");
        tellEveryone(done);

        Iterator<String> iterator = onlineUsers.iterator();
        while (iterator.hasNext()){
             String token = iterator.next();
             tellEveryone(token + add);
        }


    }

    public void userRemove (String user) {
        String add = "µ µDisconnect", done = "Serverµ µDone";
//        Iterator<String> remove = onlineUsers.iterator();
//        while (remove.hasNext()) {
//            String token = remove.next();
//            if (token.equals(user))
//                onlineUsers.remove(token);
//        }
        onlineUsers.remove(user);

        tellEveryone(user + add);
    }

    public void tellEveryone(String message) {
        // sends message to everyone connected to server
        Iterator it = clientOutputStreams.iterator();

        while (it.hasNext()) {
            try {
                PrintWriter writer = (PrintWriter) it.next();
                writer.println(message);
                outputPane.append("Sending: " + message + "\n");
                writer.flush();
                outputPane.setCaretPosition(outputPane.getDocument().getLength());

            } // end try
            catch (Exception ex) {
                outputPane.append("Error telling everyone. \n");
            } // end catch
        } // end while
    } // end tellEveryone()


    // Variables declaration - do not modify                     
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextArea outputPane;
    private javax.swing.JButton startButton;
    private javax.swing.JButton stopButton;
    // End of variables declaration                   

}

Upvotes: -1

Views: 5064

Answers (4)

Jurko Guba
Jurko Guba

Reputation: 638

I have come to a conclusion, whether or not someone is having the same problem as me, some of the professional's who replied to my question might want to know for the sake of adding it to there knowledge.

First, I double checked that every message being sent contained 2 µ's, so there is no way that data[] could have a size less than 3.

However, I work with the socket in an AsyncTask (you have to or you get NetworkTaskOnMainThread exception), after I init the socket and the readers/writers, I call publishProgess while the socket is connected. I realized that somehow there could be a bit of discrepancy through using a whileLoop, and then calling progress based on something that could be changing back and forth, ie. 2 users sending the a message at the same time. So I changed the params of my AsyncTask from <Void, Void, Void> to <Void, String, Void> and then when I do publishProgress in doInBackground, I put stream as the parameter and work with that instead.

That seemed to have solved the problem. If someone wants to touch on it please do!

Upvotes: 0

SJuan76
SJuan76

Reputation: 24885

your stream has not 2 µ characters, so the split returns an array with less than 3 items. When the following code tries to use data[2], such element is outside the range of the array and the exception is thrown.

Make your code more defensive, do not always assume that the data received will be ok. V.g., after the split, add this code

 if (data.length < 3) {
     // Process error (log, user message, whatever)
     return;
 }

Upvotes: 1

rgettman
rgettman

Reputation: 178263

Let's start with the error message:

java.lang.ArrayIndexOutOfBoundsException: length=2; index=2

We know somewhere you have an array of length 2, but you've gone off the end of it, since in Java array indices range from 0 to length - 1.

Likely explanation:

Your data array is initialized with this call:

data = stream.split("µ");

However, if there aren't at least 2 µ characters in stream, then the array will be shorter than 3, and this line will throw the exception:

if (data[2].equals(connect)) {

Check data.length before entering this piece of code, to ensure it's at least 3, and if it's not, handle the error appropriately.

Upvotes: 1

ssantos
ssantos

Reputation: 16536

The exception is clear.-

java.lang.ArrayIndexOutOfBoundsException: length=2; index=2

is telling you that you're trying to access to index 2 position in an array that has only a length of 2 (positions 0 and 1).

I'm guessing that line MyActivity.java:175 is this one.-

if (data[2].equals(chat)) {

so you need to review this.-

data = stream.split("µ");

and check that stream String has the expected value (it should have at least two µ characters to result in an array of 3+ items).

Upvotes: 5

Related Questions