Android中傳送序列化物件出現的ClassNotFoundException解決辦法
http://waynehu16.iteye.com/blog/1530760
最近在做課程設計,老師要求是基於Android上的wifi通訊的,之前沒事的時候寫過一個套接字程式設計的,完成了一個類似於聊天工具的功能。於是就想著改改,湊合著用用交上去。沒想到在寫的時候發現了一個很讓人摸不著頭腦的異常:ClassNotFoundException。
先說一下編碼之前的思路,我想在PC上做服務端,在Android上做客戶端,同時,在兩端封裝了RequestObject,ResponseObject等序列化的物件,用於在服務端和客戶端之前傳遞請求和響應物件(通過ObjectInputStream和ObjectOutputStream),如下專案結構,可是在傳送物件的時候發現了RequestObject出現了ClassNotFoundException,然後就直接無語中,明明服務端和客戶端的RequestObject等用於傳遞進物件流的物件都是一模一樣的,沒道理找不到類啊。
經過一番嘗試未果,索性把兩個.java檔案中唯一不一樣的一行改掉,即為import xxx.xxx.xxx,我將兩個專案中有關傳遞資訊的model包的包名改為一樣的。果然測試通過了,可能識別這種物件的時候,包名也是一個必要的因素吧。
問題雖然解決了,但是總覺得不方便,因為如果服務端這邊的序列化物件要更改資訊,勢必客戶端這邊的物件也要改,同一次修改缺要改兩遍資訊,而且還很容易混淆,於是我又做了如下處理:新建了一個專案,用於儲存有關任何需要傳遞的序列化物件,將這個專案匯出.jar檔案,再作為外部jar檔案匯入至客戶端和服務端的專案裡,這樣就省去了很多工作,在正式往專案裡新增操作之前,做了一個demo測試。
建立3個專案,分別是Android客戶端,需要傳遞的資料,PC的服務端。分別編寫好各個程式碼
服務端程式碼- /**
- * 2012-5-15
- * By WayneHu
- */
- package pc.test;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.ObjectInputStream;
- import java.net.ServerSocket;
- import java.net.Socket;
-
import object.RequestObject;
- public class MyServer {
- public static void main(String[] args) {
- try {
- ServerSocket server = new ServerSocket(10000);
- while (true) {
- System.out.println("Server is waiting...");
- Socket socket = server.accept();
- InputStream is;
- is = socket.getInputStream();
- ObjectInputStream ois = new ObjectInputStream(is);
- RequestObject request = (RequestObject) ois.readObject();
- System.out.println(request.getRequestClass());
- ois.close();
- is.close();
- socket.close();
- }
- } catch (IOException e) {
- e.printStackTrace();
- } catch (ClassNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- package android.test;
- import java.io.IOException;
- import java.io.ObjectOutputStream;
- import java.io.OutputStream;
- import java.net.Socket;
- import java.net.UnknownHostException;
- import object.RequestObject;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.EditText;
- public class AndroidClientActivity extends Activity {
- /** Called when the activity is first created. */
- private EditText et_input;
- private String input;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- et_input = (EditText) findViewById(R.id.input);
- }
- public void onClick_send(View view) {
- input = et_input.getText().toString();
- RequestObject request = new RequestObject(1, input, null);
- try {
- Socket socket = new Socket("10.0.2.2", 10000);
- OutputStream os = socket.getOutputStream();
- ObjectOutputStream oos = new ObjectOutputStream(os);
- oos.writeObject(request);
- oos.close();
- os.close();
- socket.close();
- } catch (UnknownHostException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
這裡多說一句,在模擬器上的客戶端,給PC上的服務端建立連線的時候,IP應為10.0.2.2
Xml程式碼- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical" >
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/hello" />
- <EditText
- android:id="@+id/input"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content" />
- <Button
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:onClick="onClick_send"
- android:text="SEND" />
- </LinearLayout>
- /**
- * 2012-5-15
- * By WayneHu
- */
- package object;
- import java.io.Serializable;
- public class RequestObject implements Serializable {
- public static final int LOGIN_REQUEST = 1;
- public static final int REGIST_REQUEST = 2;
- public static final int CHAT_REQUEST = 3;
- private int requestType;
- private String requestClass;
- private Object requestBody;
- /**
- * @param requestType 請求型別
- * @param requestClass 請求類名
- * @param requestBody 請求物件
- */
- public RequestObject(int requestType, String requestClass,
- Object requestBody) {
- super();
- this.requestType = requestType;
- this.requestClass = requestClass;
- this.requestBody = requestBody;
- }
- /**
- * @return the requestType
- */
- public int getRequestType() {
- return requestType;
- }
- /**
- * @param requestType the requestType to set
- */
- public void setRequestType(int requestType) {
- this.requestType = requestType;
- }
- /**
- * @return the requestClass
- */
- public String getRequestClass() {
- return requestClass;
- }
- /**
- * @param requestClass the requestClass to set
- */
- public void setRequestClass(String requestClass) {
- this.requestClass = requestClass;
- }
- /**
- * @return the requestBody
- */
- public Object getRequestBody() {
- return requestBody;
- }
- /**
- * @param requestBody the requestBody to set
- */
- public void setRequestBody(Object requestBody) {
- this.requestBody = requestBody;
- }
- }
然後在儲存傳遞物件的專案那裡匯出JAR檔案,如下圖,然後分別在客戶端專案和服務端專案右鍵選擇構建路徑-配置構建路徑-新增外部JAR,選擇之前匯出的JAR檔案,即可。
測試效果如下:
第一次寫這麼長的部落格,用來記錄自己學習路程的同時,也希望能幫助遇到同樣問題的朋友。寫的不好的地方歡迎朋友們提意見,寫的有錯的地方也希望各位大神能夠不吝賜教。還是那句話,文明看帖,歡迎輕拍。
歡迎轉載,轉載請註明出處: