Итак, я только начинаю изучать, как подключить два телефона по беспроводной сети через WifiP2p с помощью моего приложения.
Мое приложение - простая игра «Камень, Ножницы, Бумага».Ничего слишком сложного, и я пытаюсь получить два тестовых телефона, которые я использую, чтобы «разговаривать» друг с другом (пример: один выбирает рок, другой выбирает бумагу, и они обновляются соответствующим образом).
Моя проблема в том, что мое приложение будет постоянно падать, или если я введу
if (android.os.Build.VERSION.SDK_INT >= 23) {
StrictMode.ThreadPolicy policy = new
StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
только для того, чтобы запустить его в целях тестирования (я знаю, что приведенный выше код - ужасная идея), иногда это будет работать, но в основном это просто сбой.
Я также постоянно получаю NetworkOnMainThreadException
, что, как я думал, не следует, поскольку я расширил класс Thread.
Так что яЯ добавил все необходимые разрешения
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
И я попытался создать методы "реализует Runnable", но безрезультатно.Я подумал об использовании AsyncTask, но из того, что я прочитал, это не совсем лучший выбор, а также уголок разработчиков Android предложил использовать класс Thread для простоты того, что я пытаюсь сделать, что, по сути, просто отправкасообщение с одного телефона на другой.
Мой код был создан в соответствии с руководством "Технологии Сарти", в частности с этой строкой видео: https://www.youtube.com/watch?v=nw627o-8Fok&list=PLFh8wpMiEi88SIJ-PnJjDxktry4lgBtN3&index=1
Все еще не получается заставить работать что-либо.
У меня есть два класса, которые пытаются запустить все, класс приемника вещания здесь:
public class Wifi_P2P_Receiver extends BroadcastReceiver {
private WifiP2pManager mManager;
private WifiP2pManager.Channel mChannel;
private MultiPlayer mActivity;
public Wifi_P2P_Receiver(WifiP2pManager manager, WifiP2pManager.Channel channel, MultiPlayer mainActivity) {
this.mManager = manager;
this.mChannel = channel;
this.mActivity = mainActivity;
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if(state == WifiP2pManager.WIFI_P2P_STATE_ENABLED){
// Toast.makeText(context, "Wifi is ON", Toast.LENGTH_LONG).show();
} else {
// Toast.makeText(context, "Wifi is OFF", Toast.LENGTH_LONG).show();
}
}
if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
if(mManager != null) {
mManager.requestPeers(mChannel, mActivity.peerListListener);
}
}
else if(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
if(mManager == null){
return;
}
NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
if(networkInfo.isConnected()){
mManager.requestConnectionInfo(mChannel, mActivity.CIL);
} else {
mActivity.status.setText("Device Disconnected");
}
}
else if(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
}
}
}
А потом у меня есть мой основной вызывающий класс многопользовательского класса Multiplayer, который очень большой, поэтому яРазбей его.
Вот первая часть до метода onCreate ():
public class MultiPlayer extends AppCompatActivity {
Button btnDiscover;
Button sendRock;
Button sendPaper;
Button sendScissors;
String tempMsg = "";
TextView status;
TextView opponentChoice;
TextView gameResult;
String playerChoice = "";
ListView playerList;
WifiP2pManager mManager;
WifiP2pManager.Channel mChannel;
IntentFilter filter;
Wifi_P2P_Receiver mReceiver;
WifiManager wifi;
List<WifiP2pDevice> peers = new ArrayList<WifiP2pDevice>();
String[] deviceNameArray;
WifiP2pDevice[] deviceArray;
static final int MESSAGE_READ = 1;
ServerClass serverClass;
ClientClass clientClass;
SendReceive sendReceive;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.connect);
initialWork();
exqListener();
}
initialWork () и exqListener () выполняют всю основную работу.Вот initialWork ():
public void initialWork() {
btnDiscover = (Button) findViewById(R.id.btnFindPlayers);
playerList = (ListView) findViewById(R.id.listPlayerView);
wifi = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mManager.initialize(this, getMainLooper(), null);
mReceiver = new Wifi_P2P_Receiver(mManager, mChannel, this);
filter = new IntentFilter();
filter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
filter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
filter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
sendRock = (Button) findViewById(R.id.btnSendRock);
sendPaper = (Button) findViewById(R.id.btnSendPaper);
sendScissors = (Button) findViewById(R.id.btnSendScissors);
}
И exqListener () обрабатывает все нажатия кнопок (у меня есть кнопка для Rock, Paper и Scissors, которая отправляет строковое «сообщение» по сети):
private void exqListener() {
status = (TextView) findViewById(R.id.connectStatusTV);
opponentChoice = (TextView) findViewById(R.id.opponentChoiceTV);
gameResult = (TextView) findViewById(R.id.gameResultTV);
btnDiscover = (Button) findViewById(R.id.btnFindPlayers);
btnDiscover.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
// Toast.makeText(getApplication(), "Discovery Started", Toast.LENGTH_LONG).show();
status.setText("Discovery Started");
}
@Override
public void onFailure(int i) {
// Toast.makeText(getApplication(), "Discovery Failed", Toast.LENGTH_LONG).show();
status.setText("Discovery Failed");
}
});
}
});
playerList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
final WifiP2pDevice device = deviceArray[i];
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
mManager.connect(mChannel, config, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Toast.makeText(getApplication(), "Connected to " + device.deviceName, Toast.LENGTH_LONG).show();
}
@Override
public void onFailure(int i) {
Toast.makeText(getApplication(), "Not connected", Toast.LENGTH_LONG).show();
}
});
}
});
sendRock.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String msg = "Rock";
playerChoice = "Rock";
sendReceive.write(msg.getBytes());
if(tempMsg.length() > 0){
colorChange();
}
}
});
sendPaper.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String msg = "Paper";
playerChoice = "Paper";
sendReceive.write(msg.getBytes());
if(tempMsg.length() > 0){
colorChange();
}
}
});
sendScissors.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String msg = "Scissors";
playerChoice = "Scissors";
sendReceive.write(msg.getBytes());
if(tempMsg.length() > 0){
colorChange();
}
}
});
}
У меня есть listView, который отображает все близлежащие устройства, к которым пользователь может подключиться, щелкнув по элементу.У меня также есть WifiP2pManager.ConnectionInfoListener
и соответствующие методы для установки пользователя на host
, а другого на client
.Похоже, они работают, поэтому я не буду вставлять код, чтобы избежать как можно большего количества помех.Я также не буду публиковать методы onResume () или onPause (), поскольку они не являются проблемой.
У меня есть ServerClass
, SendReceive
и ClientClass
, которые являются подклассами Multiplayer
.Вот ServerClass:
public class ServerClass extends Thread {
Socket socket;
ServerSocket serverSocket;
@Override
public void run(){
try {
serverSocket = new ServerSocket(8888);
socket = serverSocket.accept();
sendReceive = new SendReceive(socket);
sendReceive.start();
} catch(IOException e) {
e.printStackTrace();
}
}
}
И мой ClientClass:
public class ClientClass extends Thread {
Socket socket;
String hostAdd;
public ClientClass(InetAddress hostAddress){
hostAdd = hostAddress.getHostAddress();
socket = new Socket();
}
@Override
public void run(){
// super.run();
try {
socket.connect(new InetSocketAddress(hostAdd, 8888), 500);
sendReceive = new SendReceive(socket);
sendReceive.start();
} catch(IOException e){
e.printStackTrace();
}
}
}
И, наконец, подкласс SendReceive:
private class SendReceive extends Thread {
private Socket socket;
private InputStream inputStream;
private OutputStream outputStream;
public SendReceive(Socket skt) {
socket = skt;
try {
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
// super.run();
byte[] buffer = new byte[1024];
int bytes;
while(socket != null){
try {
bytes = inputStream.read(buffer);
if(bytes > 0){
handler.obtainMessage(MESSAGE_READ, bytes, -1, buffer).sendToTarget();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void write(byte[] bytes){
try {
outputStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Последнее, что я забыл упомянуть, это мойметод-обработчик, который сам по себе является частью класса Multiplayer.Вот что я делаю с сообщениями:
Handler handler = new Handler(new Handler.Callback() {
@SuppressLint("ResourceAsColor")
@Override
public boolean handleMessage(Message message) {
switch(message.what){
case MESSAGE_READ:
byte[] readBuff = (byte[]) message.obj;
tempMsg = new String(readBuff, 0, message.arg1);
opponentChoice.setText("Your opponent chooses " + tempMsg + "!");
break;
}
return true;
}
});
Я считаю, что одной из основных проблем является метод write(byte[] bytes)
, так как каждый раз, когда я нажимаю одну из кнопок, например Rock
, Я получаю NetworkOnMainThreadException
, где stackTrace указывает на строку sendReceive.write(msg.getBytes());
кода кнопки.Поэтому я думаю, что это имеет какое-то отношение к классу SendReceive, находящемуся в основном потоке пользовательского интерфейса, чего я и не думал, поскольку я переопределил метод run (), когда у меня был подкласс, расширяющий класс Thread.
Любая помощь будет принята с благодарностью.