คือตอนนี้ ผมเขียนฝัง Server ด้วย Java(รันด้วย Editplus) แล้วตัว Client ก็เขียนด้วย Java (รันด้วย Editplus) สามารถ Connect แล้ว Chat กันไปมาได้ปกติครับ ไม่มีปัญหา
แต่พอผมมาเขียนฝั่ง Client บน Android มันมีปัญหาเกี่ยวกับ Thread ตอนอ่านข้อมูลกลับจากฝั่ง Server ครับตัว Client บน Android สามารถส่งข้อความหา Server ได้ปกติเลครับ
แต่ไม่สามารถอ่าน Buffer จาก Serverได้ มันจะเด้ง Error ถ้าผม Print Log ดูตรง
catch(Exception E){
Log.i(this.toString(), "error : " +E.toString());
}
มันมันจะมีปัญหากับ Class Thread ที่ผมเขียนไว้อ่านข้อมูลจาก Server ครับ แก้มาหลายวันลองมาหลายแบบแล้ว แต่ก็ไม่ได้เรื่องเลย ฝากผู้รู้ หรือเคยเขียน แนะนำ หาทางออกให้ผมที่นะคร้าบบบ
//Code ตอนเรียก Class Theard เพื่อรออ่าน Buffer จาก Server
threadrecieve tr = new threadrecieve(S);
tr.start();
//Code Class threadrecieve
public class threadrecieve extends Thread
{
Socket SS;
String msg;
BufferedReader br;
threadrecieve(Socket r)
{
SS=r;
}
public void run()
{
try
{
System.out.println("rock");
br = new BufferedReader(new InputStreamReader(SS.getInputStream()));
while((msg=br.readLine())!=null)
{
projectPCZ.this.mainText.append(msg+"\n"); // Show MSG on Mainboard
if(msg.equals("Server is Shutting Down"))
{
userText.setEnabled(true);
disconnectBtn.setEnabled(false);
connectBtn.setEnabled(true);
mainText.setText("");
serverText.setText("Server is Shutting Down .. .");
break;
}
}
SS.close();
br.close();
}
catch(IOException E){
Log.i(this.toString(), "error: " +E.toString());
}
}
}
//Error by Eclipse
Thread [<7> Thread-8] (Suspended (exception
ViewRoot$CalledFromWrongThreadException))
ViewRoot.checkThread() line: 2802
ViewRoot.invalidateChild(View, Rect) line: 607
ViewRoot.invalidateChildInParent(int[], Rect) line: 633
TableLayout(ViewGroup).invalidateChild(View, Rect) line: 2505
TextView(View).invalidate() line: 5139
TextView.updateAfterEdit() line: 4734
TextView.handleTextChanged(CharSequence, int, int, int) line: 6158
TextView$ChangeWatcher.onTextChanged(CharSequence, int, int, int) line: 6316
SpannableStringBuilder.sendTextChange(TextWatcher[], int, int, int) line: 889
SpannableStringBuilder.change(boolean, int, int, CharSequence, int, int) line: 352
SpannableStringBuilder.change(int, int, CharSequence, int, int) line: 269
SpannableStringBuilder.replace(int, int, CharSequence, int, int) line: 432
SpannableStringBuilder.append(CharSequence, int, int) line: 259
SpannableStringBuilder.append(CharSequence, int, int) line: 28
SpannableStringBuilder(TextView).append(CharSequence, int, int)
line: 2240
TextView.append(CharSequence) line: 2227
projectPCZ$threadrecieve.run() line: 173
//อันนีั้ มัน Error ตอนกด Send อยู่ใน LogChat ของ Android
08-01 10:40:02.604: INFO/global(425): Default buffer size used in BufferedWriter constructor. It would be better to be explicit if an 8k-char buffer is required.
08-01 10:41:00.075: DEBUG/SntpClient(59): request time failed: java.net.SocketException: Address family not supported by protocol
ขอคำแนะนำด้วยนะครับบบบ ทำมาหลายวันแล้วววว
ได้ประกาศ permission ใน manifest หรือยังครับ
ประกาศครับ
จริงๆมัน connect server และส่งข้อมูลได้ แต่มีปัญหาตอนอ่านข้อมูล ด้วย Class นี้แหละครับ
ถ้าเข้าใจไม่ผิด... ปัญหามันเกิดจากคุณอ้างถึง Object ที่ถูกสร้างจากคนละ Thread กันครับ
การเรียกข้าม Thread นั้นต้องใช้ Runnable + View.Post ครับ (อ่านเพิ่มเติมตรงนี้)
หรือไม่ก็ต้องใช้ Class android.os.Handler ครับ
เกรงว่าตัวผมเองอธิบายเป็นภาษาคนไม่ได้ดี ผมขอแปะอันนี้ละกันครับ
แบบที่ท่านแนะนำ มันคล้ายๆ ตัวอย่างนี้ หรือปล่าวครับ
ตัวอย่างที่ผมลองใช้ Runable ครับ
ผมก็ลองทำดูแล้ว แบบที่ใช้ Runnable
มันก็ส่งได้อย่างเด่วครับ มันอ่าน Buffer จาก Server ไม่ได้
code ที่ใช้ส่งข้อความไป server ก็ตามนี้ครับ
ส่วน Code อ่าน Buffer จาก Server ก็ Class ข้างบนครับประมานนั้น
ถ้าเขียนแบบในตัวอย่างถือว่าถูกต้องนะครับ
เพราะสังเกตุได้ว่าตัวอย่างจะมี Handler object อยู่ใน method run ด้วยซึ่ง handler object ตัวนี้เป็น Class ที่จะป้องกันภาวะ Racing (หลาย Thread แย่งกันใช้ resource)
แต่จาก Code ของคุณอันแรก ผมยังไม่เห็นว่าคุณมีการนำอะไรที่เป็นการป้องกัน racing มาใช้เลยครับ
ตัวโปรแกรมที่ผมเขียนครับ
รูปภาพ ตัวโปรแกรม
Console สีดำฝั่งซ้าย เป้น Server ครับ สังเกตุว่า ส่งข้อความหา Server ได้ แต่หน้าจอ Android อ่าน Buffer จาก Server ไม่ได้ ที่เห้นขึ้น XXXXX มันขึ้นก่อนจะเด้งมาฟ้อง Error ข้างล่างของ Eclipse ครับ
คือกดส่งครั้งแรก ไม่ error และขอความหน้าจอ Android ไม่ขึ้น กดรอบสอง ข้อความขึ้นแล้วเด้งไป Error
แต่ก็ยังส่งได้ปกติ
ต้องขอบคุนสำหรับคำแนะนำของท่านจริงๆครับ ตอนนี้ผมสามารถแก้ปัญหานี้ได้แล้วตามคำแนะนำของท่าน
เอะใจตรงที่ท่านบอกว่า " handler object ตัวนี้เป็น Class ที่จะป้องกันภาวะ Racing (หลาย Thread แย่งกันใช้ resource)"
รูปตัวโปรแกรมที่ ใช้งานได้แล้ววว ^^
ที่มันมีปํญหาตอนแรกที่ผมเปลี่ยนมาใช้ Runnable เพราะผมเอา สองส่วนนี้ มาร่วมไว้ใน Runnable เดี่ยวกัน มันเลยเด้งฟ้องทุกครั้งที่ผมกด Send
//ส่วนแรก
mainText.append(msg+"\n"); // Show MSG on Mainboard
//ส่วนสอง
if(msg.equals("Server is Shutting Down"))
{
userText.setEnabled(true);
disconnectBtn.setEnabled(false);
connectBtn.setEnabled(true);
mainText.setText("");
serverText.setText("Server is Shutting Down .. .");
break;
}
ผมเลยลองแยกมันออกมาใหม่ ให้มันอยู่คนล่ะ Runnable ปรากฏว่าใช้ได้
ผมเลยเปลี่ยน TextView เป้น Listview มันจะได้ดูง่ายๆหน่อย
Class สำหรับอ่าน Buffer จาก Server ที่แก้ใหม่ครับ เผื่อใครจะใช้เป้นแนวทาง ..
ขอบคุนมากๆครับ
ยินดีครับที่ได้ใช้ความรู้ให้เป็นประโยชน์ ความจริงแล้วผมเพิ่งเคยเขียนแบบ Multi-thread โดยใช้ Handler แค่ครั้งเดียวเองครับ แต่ที่พอจะจำได้เพราะผมแกะ Code ของ Multitouch Keyboard ที่มากับ Gingerbread ครับ
แกะ Code สนุกกว่าเขียนเองเยอะ