/ / Android TCP / IP i GUI do komunikacji z innymi wątkami - Tic Tac Toe Multiplayer - java, android, multithreading, tcp, handler

Android TCP / IP i GUI do komunikacji z innym wątkiem - Tic Tac Toe Multiplayer - java, android, wielowątkowość, tcp, handler

Więc o to chodzi.Chciałbym zaimplementować grę Tic Tac Toe dla wielu graczy na Androidzie. Wdrożyłem serwer wielowątkowy przy użyciu Javy, ale mam problemy z klientem. O ile wiem, powinieneś używać wątku w tle do obsługi komunikacji i pozostawić wątek interfejsu użytkownika tylko do rzeczy związanych z interfejsem użytkownika. Mam pewne problemy z tworzeniem pętli gry i komunikacją wątkową. Zdecydowałem się użyć Handlerów zamiast AsyncTask.

Myślę, że pętla powinna zostać zaimplementowana wwątek tła i wygląda mniej więcej tak: Uzyskaj informacje z interfejsu użytkownika za pomocą programu Handler Zapisz dane, które mają być przesyłane do serwera Odczytaj dane ze strumienia wejściowego z serwera Przetwarzaj dane Wyślij dane do interfejsu użytkownika za pomocą innego programu obsługi.

Testuję to za pomocą Eclipse i emulatorówdziałając jako klient. Problem polega na tym, że po prostu nie mogę skonfigurować programów obsługi. Jeden moduł obsługi UIHandler jest wysyłany jako parametr do konstrukcji ClientThread, a program obsługi sieci jest uzyskiwany metodą z wątku klienta do UIThread.

Przeczytałem, że muszę używać Loopera do przetwarzania przychodzących danych. Czy nie mogę po prostu wywołać metody handleMessage w nieskończonej pętli? Na szczęście nie wiem, jak to wdrożyć. Byłbym wdzięczny za wszelkie pomysły.

Główna działalność Klasa klienta:

    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ł");
}


}
};

}
}

Wątek w tle:

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);
}
}

Kod nie jest jeszcze ukończony, więc niektóre metody mogą wydawać się dziwne. Jestem zainteresowany rozwiązaniem UIThread do BackGroundThread do komunikacji z serwerem. Nic więcej.

Odpowiedzi:

1 dla odpowiedzi № 1

Handler obiekty są niejawnie powiązane z Looper działa w ramach Thread w którym są tworzone. Twój wątek w tle musi utworzyć własny Looper (albo użyj HandlerThread dbać o Looper dla ciebie.) Następnie twój wątek w tle musi przekazać swoje Handler powrót do głównego wątku interfejsu użytkownika.