Java 在Android线程内部(和外部)使用类变量
我创建了一个简单的android应用程序来控制一个有WiFi接入点的机器人。该应用程序创建一个UDP套接字和一个线程,用于侦听来自机器人的消息。收到消息后,记录机器人的IP地址和端口,并设置标志,指示机器人已连接。一旦连接,应用程序可以向机器人发送命令 当应用程序收到消息(即UdpServer类返回的socket.receive)时,我观察到isConnected标志被设置为true(在调试器中运行)。但是,当我按下应用程序上的按钮向机器人发送命令消息时,断开连接的标志现在为false。为什么线程中的这个变量的值与另一个类方法中的变量的值不同 源代码如下所示: main活动Java 在Android线程内部(和外部)使用类变量,java,android,multithreading,Java,Android,Multithreading,我创建了一个简单的android应用程序来控制一个有WiFi接入点的机器人。该应用程序创建一个UDP套接字和一个线程,用于侦听来自机器人的消息。收到消息后,记录机器人的IP地址和端口,并设置标志,指示机器人已连接。一旦连接,应用程序可以向机器人发送命令 当应用程序收到消息(即UdpServer类返回的socket.receive)时,我观察到isConnected标志被设置为true(在调试器中运行)。但是,当我按下应用程序上的按钮向机器人发送命令消息时,断开连接的标志现在为false。为什么线
package com.test.robotremote;
import android.os.Bundle;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.view.Menu;
import android.view.View;
public class MainActivity extends Activity {
UdpServer server = null;
enum Directions
{
STOP,
FORWARD,
BACKWARD,
LEFT,
SHARP_LEFT,
RIGHT,
SHARP_RIGHT
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Force activity to landscape orientation
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
//Create the UDP server
server = new UdpServer(49999);
//Start the RX thread
Thread serverThread = new Thread(server);
serverThread.start();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void sendCommand(Directions cmd){
byte[] msg = new byte[2];
//Set direction
msg[0] = (byte) cmd.ordinal();
//Set speed
if(cmd == Directions.STOP)
{
msg[1] = 0;
}
else
{
msg[1] = 100;
}
server.sendUdpMessage(msg, msg.length);
}
public void handleForwardButton(View view){
sendCommand(Directions.FORWARD);
}
public void handleBackwardButton(View view){
sendCommand(Directions.BACKWARD);
}
public void handleRightButton(View view){
sendCommand(Directions.RIGHT);
}
public void handleLeftButton(View view){
sendCommand(Directions.LEFT);
}
public void handleStopButton(View view){
sendCommand(Directions.STOP);
}
}
UdpServer
package com.test.robotremote;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UdpServer implements Runnable {
boolean isRunning = false;
boolean isConnected = false;
int localPort = 0;
int remotePort = 0;
InetAddress remoteIp;
byte[] rxBuffer = new byte[1500];
DatagramSocket socket = null;
public UdpServer(int port) {
localPort = port;
}
@Override
public void run() {
//Run the server receive in the background
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
try
{
//Create an RX packet buffer
DatagramPacket packet = new DatagramPacket(rxBuffer, rxBuffer.length);
//Create our servers socket
socket = new DatagramSocket(localPort);
isRunning = true;
while(isRunning)
{
//Wait for received data
socket.receive(packet);
isConnected = true;
//Record sender's IP address and port
remoteIp = packet.getAddress();
remotePort = packet.getPort();
}
//Close the socket when thread exits
if (socket != null)
{
socket.close();
}
}
catch (Throwable e)
{
e.printStackTrace();
}
}
public int sendUdpMessage(byte[] msg, int length) {
try
{
if(isConnected)
{
DatagramPacket p = new DatagramPacket(msg, length, remoteIp, remotePort);
socket.send(p);
return 1;
}
}
catch (Throwable e)
{
e.printStackTrace();
}
return 0;
}
}
Android将杀死任何使用while(true)或递归线程/任务的进程,这就是连接中断的原因。我会使用从前台开始的Intent服务。这是通知中的小图标,就像启动潘多拉一样。这是Android执行长时间运行进程的最佳方式
经过一些实验,我已经解决了这个问题。我希望这个应用程序始终是横向的,我认为以编程方式设置方向看起来是最好的。然而,也有一些不必要的副作用。问题是以下apps
OnCreate
方法中的声明:
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
setRequestedOrientation
的文档说明此调用可能导致活动重新启动。如果清单文件没有显式强制方向为横向,则活动将重新启动
如果活动重新启动,则会多次调用OnCreate
。在这个应用程序中,UdpServer
对象和接收线程是在OnCreate
方法中构造的。因此,第一次创建OnCreate
被称为UdpServer
对象,并启动线程。第一个线程打开套接字。接下来,当活动重新启动并且第二次调用OnCreate
时,将创建第二个UdpServer
对象并启动第二个线程。现在,第二个UdpServer
将无法打开套接字,因为第一个已打开套接字。因此,当接收到消息时,它们将在创建的第一个UdpServer
实例中接收。但是,由于活动已重新启动,UI按钮按下(调用UdpServer
class方法)将使用第二个UdpServer
实例。因此,在UdpServer
接收线程(第一个实例)中查看isConnected
变量与在UI上按下按钮以使用UdpServer
对象(第二个实例)发送消息时查看变量不同的原因
对此的简单(临时)修复方法是强制在清单中横向定位,并从
OnCreate
方法中删除对setRequestedOrientation
的调用。这仍然存在问题,因为活动可能由于其他原因而重新创建。更理想的解决方案是将持久性数据(即UDP服务器对象)移动到应用程序类,该类在应用程序生命周期内只创建一次 我明白了。但是在这种情况下,线程仍在运行。我继续从线程内的UDP套接字接收消息。问题是“isConnected”变量在线程中的值与在sendUdpMessage方法中的值不同。