/ / Android TCP / IP и GUI към комуникация с други нишки - Tic Tac Toe Multiplayer - java, android, multithreading, tcp, handler

Android TCP / IP и GUI към комуникация с други нишки - Tic Tac Toe Multiplayer - java, android, multithreading, tcp, handler

Така че тук е сделката. Бих искал да внедрявам мултиплейър Tic Tac Toe с Android. Разгърнах многопоточен сървър, използвайки Java, но се боря с клиента. Доколкото знам, трябва да използвате фонова нишка, за да обработите комуникацията, и да оставите UI нишката само за неща от потребителския интерфейс. Имам някои проблеми с развитието на игровата линия и комуникация с нишки. Реших да използвам Handlers вместо AsyncTask.

Мисля, че цикълът трябва да бъде реализиран вфонова нишка и изглеждайте някак така: Вземете информацията от потребителския интерфейс с помощта на Handler Напишете данните, за да изведете поток към сървъра Прочетете данните от входящия поток от сървъра Обработвайте данните Изпратете данните в потребителския интерфейс с помощта на друг манипулатор.

Тествам това с помощта на Eclipse и емулаторидейства като клиент. Проблемът е, че просто не мога да настроя обработчиците. Един обработващ UIHandler се изпраща като параметър към ClientThread Constructut, Net Handler се получава чрез метод от клиентска нишка в UIThread.

Прочетох, че трябва да използвам Looper за обработка на входящи данни. Не мога ли просто да извикам метода на дръжка в безкраен цикъл? Аз строго не знам как да го разгърна. Бих се радвал на всякакви идеи.

Основна дейност Клас на клиента:

    package com.example.tictactoecliet;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.StrictMode;
import android.os.StrictMode.ThreadPolicy;
import android.util.Log;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.ViewFlipper;

public class MainActivity extends Activity implements OnClickListener,
ClientVocabulary {

private static final String TAG = MainActivity.class.getSimpleName();
private Socket client;
private PrintWriter pw;
private EditText etIp;
private TextView tvStatus;
private Button bCon;
private Socket socket;
PrintWriter out;
private BufferedReader in;
private RadioButton rbVsPlayer, rbVsAI;
private ViewFlipper vF;
private ClientThread cT;
private ImageButton[][] board = new ImageButton[5][5];
private Handler h, clientHandler;
SocketAddress sockaddr;


/******************************************************************************************/

@Override
protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);


setContentView(R.layout.activity_main);
init();
setupUIHandler();
try {

} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


}



/*****************************************
* initialize
*
* @return nothing ffs
******************************************/

private void init() {

etIp = (EditText) findViewById(R.id.etIP);

tvStatus = (TextView) findViewById(R.id.tvStatus);
rbVsAI = (RadioButton) findViewById(R.id.rbAI);
rbVsPlayer = (RadioButton) findViewById(R.id.rb2players);
bCon = (Button) findViewById(R.id.bCon);

//
// // listeners
//
vF = (ViewFlipper) findViewById(R.id.vF);
bCon.setOnClickListener(this);
board[0][0] = (ImageButton) findViewById(R.id.iB_1A);
board[0][1] = (ImageButton) findViewById(R.id.iB_2A);
board[0][2] = (ImageButton) findViewById(R.id.iB_3A);
board[0][3] = (ImageButton) findViewById(R.id.iB_4A);
board[0][4] = (ImageButton) findViewById(R.id.iB_5A);

board[1][0] = (ImageButton) findViewById(R.id.iB_1B);
board[1][1] = (ImageButton) findViewById(R.id.iB_2B);
board[1][2] = (ImageButton) findViewById(R.id.iB_3B);
board[1][3] = (ImageButton) findViewById(R.id.iB_4B);
board[1][4] = (ImageButton) findViewById(R.id.iB_5B);

board[2][0] = (ImageButton) findViewById(R.id.iB_1C);
board[2][1] = (ImageButton) findViewById(R.id.iB_2C);
board[2][2] = (ImageButton) findViewById(R.id.iB_3C);
board[2][3] = (ImageButton) findViewById(R.id.iB_4C);
board[2][4] = (ImageButton) findViewById(R.id.iB_5C);

board[3][0] = (ImageButton) findViewById(R.id.iB_1D);
board[3][1] = (ImageButton) findViewById(R.id.iB_2D);
board[3][2] = (ImageButton) findViewById(R.id.iB_3D);
board[3][3] = (ImageButton) findViewById(R.id.iB_4D);
board[3][4] = (ImageButton) findViewById(R.id.iB_5D);

board[4][0] = (ImageButton) findViewById(R.id.iB_1E);
board[4][1] = (ImageButton) findViewById(R.id.iB_2E);
board[4][2] = (ImageButton) findViewById(R.id.iB_3E);
board[4][3] = (ImageButton) findViewById(R.id.iB_4E);
board[4][4] = (ImageButton) findViewById(R.id.iB_5E);

for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {

board[i][j].setOnClickListener(this);
}// end of inner for
}// end of outer for

}

@Override
public void onClick(View v) {

switch (v.getId()) {

case (R.id.bCon):
vF.showNext();
blockAllTile();
cT = new ClientThread((short) (rbVsPlayer.isChecked() ? 2:1), clientHandler, etIp.getText().toString());
cT.start();
break;
case (R.id.iB_1A):
sendLocation(0);
break;
case (R.id.iB_2A):
sendLocation(1);
break;
case (R.id.iB_3A):
sendLocation(2);
break;
case (R.id.iB_4A):
sendLocation(3);
break;
case (R.id.iB_5A):
sendLocation(4);
break;
case (R.id.iB_1B):
sendLocation(5);
break;
case (R.id.iB_2B):
sendLocation(6);
break;
case (R.id.iB_3B):
sendLocation(7);
break;
case (R.id.iB_4B):
sendLocation(8);
break;
case (R.id.iB_5B):
sendLocation(9);
break;
case (R.id.iB_1C):
sendLocation(10);
break;
case (R.id.iB_2C):
sendLocation(11);
break;
case (R.id.iB_3C):
sendLocation(12);
break;
case (R.id.iB_4C):
sendLocation(13);
break;
case (R.id.iB_5C):
sendLocation(14);
break;
case (R.id.iB_1D):
sendLocation(15);
break;
case (R.id.iB_2D):
sendLocation(16);
break;
case (R.id.iB_3D):
sendLocation(17);
break;
case (R.id.iB_4D):
sendLocation(18);
break;
case (R.id.iB_5D):
sendLocation(19);
break;
case (R.id.iB_1E):
sendLocation(20);
break;
case (R.id.iB_2E):
sendLocation(21);
break;
case (R.id.iB_3E):
sendLocation(22);
break;
case (R.id.iB_4E):
sendLocation(23);
break;
case (R.id.iB_5E):
sendLocation(24);
break;

}

}

public void unblockAllTile(){
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {

board[i][j].setEnabled(true);
}// end of inner for
}//
}

public void sendLocation(int location){

}

public void blockAllTile(){
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {

board[i][j].setEnabled(false);
}// end of inner for
}// end of outer for

}
private void setupUIHandler(){

h = new Handler(){

@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
Bundle b = msg.getData();
String content = b.getString("msg");
if(content.equals(KKIP_ALL_CONNECTED)){
tvStatus.setText(KKIP_ALL_CONNECTED);
}else{
Log.i("i no noł", "i no noł");
}


}
};

}
}

Фонова нишка:

package com.example.tictactoecliet;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

public class ClientThread extends Thread implements ClientVocabulary {

private Socket socket;
private short game_mode;

private Handler uiHandler;
private Handler netHandler;
private Bundle inMsgBundle, outMsgBundle;
private final static String TAG = ClientThread.class.getSimpleName();
private BufferedReader in;
private String ip, serverResponse;
PrintWriter out;

public ClientThread(Short game_mode, Handler h, String ip) {
this.game_mode = game_mode;
this.uiHandler = h;
this.ip = ip;
inMsgBundle = new Bundle();
outMsgBundle = new Bundle();

}

@Override
public void run() {
// TODO Auto-generated method stub
Log.i("Thread started",TAG);
connectionSetup();
Log.i("Setup connection",TAG);
Looper.prepare();
setupHandler();
Log.i("Handler set",TAG);
try {

play();




} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Looper.loop();
}// end of run

public  Handler getHandlerToMsgQueue() {
while (netHandler == null) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return netHandler;
}

// //////////////////////////////////////////
public void connectionSetup() {
try {
Log.i("Setup start",TAG);
InetAddress serverAddress = InetAddress.getByName(ip);
SocketAddress sockaddr = new InetSocketAddress(serverAddress, 4321);
// socket = new Socket("192.168.0.102",4321);
socket = new Socket();
socket.connect(sockaddr);
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream())), true);
out.println(game_mode);

in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
Log.i("Setup finish",TAG);
} catch (Exception e) {
e.printStackTrace();
}
}
////////////////
public void setupHandler(){

Log.i("Handler ready",TAG);
netHandler = new Handler(){



@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
notifyAll();

}
};

Log.i("Handler done",TAG);
}
///////////////////////////play//////////////////////////
public void play() throws Exception{
String response;
Log.v("Play start", "Play start");



try {
response =null;
if(in.readLine()!=null){
response=in.readLine();
Log.v(response, response);
}else{
Log.v(TAG, "Resposne is empty");
}

if( response.startsWith(KKIP_WELCOME)){
Log.i("wow welcome so much", "so much welcome");
char mark = response.charAt(8);
}else if (response.startsWith(KKIP_WAITING_FOR_OPPONENT)){


while (true){


//updatuj status zegarem, może wait i notify?
if(response.startsWith(KKIP_ALL_CONNECTED)){



Log.v("now we play","play");
sendMessageToUI(KKIP_ALL_CONNECTED);
response=in.readLine();
if(response.startsWith(KKIP_VALID_MOVE)){

//update board
}else if (response.startsWith(KKIP_MOVED)){
int loc = Integer.parseInt(response.substring(15));
//update board
}else if (response.startsWith(KKIP_VICTORY)){

}else if(response.startsWith(KKIP_DEFEAT)){

}else if (response.startsWith(KKIP_TIE)){

}
}

}//end of while (true)


//end of if connected


}
out.print(KKIP_QUIT);
}




catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
finally{
socket.close();
}

}
private void sendMessageToUI(String msg){
Bundle data = new Bundle();
data.putString("msg", msg);
Message m = new Message();
m.setData(data);
uiHandler.sendMessage(m);
}
}

Кодът все още не е завършен, така че някои методи може да изглеждат странни. Интересувам се да реша UIThread към BackGroundThread към сървърната комуникация. Нищо друго.

Отговори:

1 за отговор № 1

Handler обектите са имплицитно обвързани с Looper работи в рамките на Thread в която са създадени. Вашата фонова нишка трябва да създаде своя собствена Looper (или използвайте HandlerThread да се грижи за Looper за вас.) Тогава вашата фонова нишка трябва да я съобщи Handler обратно към основната нишка на потребителския интерфейс.