我知道我在log cat中获得的异常有一个非常严格的名字。我唯一的问题是我无法确定导致我的异常的原因。我创建了一个PC-Android多客户聊天。
PC版本与服务器和客户端100%协同工作。我实现了从PC客户端到Android客户端和聊天工作相同的技术。
我遇到的唯一问题是,当我连接android,clientArea(跟踪所有连接的用户)时,不跟踪其他名称,而是跟踪android客户端用户名的倍数。 即。我只使用用户名:Jurko连接到android,clientArea将有2个人叫Jurko而不是只有一个。
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客户端:
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.
}
}
}
服务器(在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
}
答案 0 :(得分:5)
例外是明确的.-
java.lang.ArrayIndexOutOfBoundsException: length=2; index=2
告诉您,您正试图访问长度为index 2
(位置2
和0
)的数组中的1
位置。< / p>
我猜这一行是MyActivity.java:175
.-
if (data[2].equals(chat)) {
因此您需要查看此内容.-
data = stream.split("µ");
并检查stream String
是否具有预期值(它应至少包含两个µ
字符,以生成包含3个以上项目的数组。)
答案 1 :(得分:1)
让我们从错误消息开始:
java.lang.ArrayIndexOutOfBoundsException: length=2; index=2
我们知道某个地方你有一个长度为2的数组,但是你已经离开它了,因为Java数组索引的范围从0
到length - 1
。
可能的解释:
您的data
数组已使用此调用初始化:
data = stream.split("µ");
但是,如果µ
中至少有2个stream
个字符,则数组将短于3,并且此行将引发异常:
if (data[2].equals(connect)) {
在输入这段代码之前检查data.length
,确保它至少为3,如果不是,请正确处理错误。
答案 2 :(得分:1)
您的stream
没有2 µ
个字符,因此split
会返回少于3个项目的数组。当以下代码尝试使用data[2]
时,此元素超出了数组的范围,并抛出异常。
让您的代码更具防御性,不要总是假设收到的数据没问题。例如,在拆分后,添加此代码
if (data.length < 3) {
// Process error (log, user message, whatever)
return;
}
答案 3 :(得分:0)
我得出结论,无论某人是否遇到与我相同的问题,回答我问题的一些专业人士可能想知道为了将其添加到那里而知道。
首先,我仔细检查发送的每条消息都包含2μs,因此数据[]的大小不能小于3。
但是,我在AsyncTask中使用套接字(你必须或者你得到NetworkTaskOnMainThread异常),在我初始化套接字和读/写器之后,我在连接套接字时调用publishProgess。我意识到,通过使用whileLoop,然后根据可能来回变化的东西调用进度,可能会有一些差异,即。 2个用户同时发送消息。所以我将AsyncTask的参数从<Void, Void, Void>
更改为<Void, String, Void>
,然后当我在doInBackground中执行publishProgress时,我将stream作为参数并使用它来代替。
这似乎解决了这个问题。如果有人想触摸它,请做!