【问题标题】:Why does a public method in a thread not resolve in onCreate?为什么线程中的公共方法无法在 onCreate 中解析?
【发布时间】:2015-11-30 20:35:07
【问题描述】:

应用程序概述:一个更简单的服务器在端口上侦听连接。向连接到该端口的每个客户端发送 GPS NMEA 字符串,因为它们从 GPS 芯片中出来。

因此 onCreate 会启动一个新线程来侦听端口。对于每个连接,此侦听器线程都会衍生出另一个新线程。这些线程中的每一个当前只是每两秒吐出一条“仍然连接”的消息。这部分一切正常,我可以设置几个 telnet 会话并连接,一切都按预期进行。所有位置信息也在这段代码中工作;它会使用正确且不断变化的 GPS 信息正确更新屏幕。

我想注册一个 Nmealistener,然后让它将该字符串分派给每个服务于连接的线程。但是,socketListenerThread.MasterDispatchNmeaMessage(nmea) 不会在 addNmeaListener 中解析。 (它也不会在它之外解决。) addNmeaListener 似乎没有问题,如果我有它只是通过 Log.d 转储消息,它会很乐意这样做。

在 socketListenerThread 类中,方法 MasterDispatchNmeaMessage 也被标记为“从不调用”。

那么是什么阻止了 MasterDispatchNmeaMessage 得到解决?

对于那些不熟悉的人,示例 NMEA 字符串如下所示:

$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47

在我正在测试的三星 S4 上,它们以突发形式出现,可能平均每秒 5 到 10 行。

附加说明:我的目标是 API 22。除此之外,位置类还需要更多的权限检查。因此,我希望在添加新的权限检查以使其与最新的库兼容之前,让所有这些工作真正发挥作用。

public class ActivityMain extends AppCompatActivity implements LocationListener {
static final String TAG = "GPSOverWiFi";
static final int LISTENING_PORT = 8085;

private TextView latitudeField;
private TextView longitudeField;
private LocationManager locationManager;
private String provider;

Thread socketListenerThread;

TextView info, infoip;
ServerSocket serverSocket;
int gConnectionCount = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    latitudeField   = (TextView) findViewById(R.id.liveLatitude);
    longitudeField  = (TextView) findViewById(R.id.liveLongitude);
    infoip          = (TextView) findViewById(R.id.infoip);
    info            = (TextView) findViewById(R.id.info);

    // Get the GPS location manager
    locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    Criteria criteria = new Criteria();
    provider = locationManager.getBestProvider(criteria, false);
    Location location = locationManager.getLastKnownLocation(provider);



    // Initialize the location fields
    if (location != null) {
        System.out.println("Provider " + provider + " has been selected.");
        onLocationChanged(location);
    } else {
        latitudeField.setText("Location not available");
        longitudeField.setText("Location not available");
    }

    infoip.setText("IP Addresss: " + getIpAddress() + ":" + LISTENING_PORT);
    socketListenerThread = new SocketListenerThread();
    socketListenerThread.start();

    //for giggles, it doesn't resolve here either, but this it needs to resolve a few lines down...
    //socketListenerThread.MasterDispatchNmeaMessage("asdf");

    locationManager.addNmeaListener(new GpsStatus.NmeaListener() {
        public void onNmeaReceived(long timestamp, String nmea) {
            // ////////////////////////////////////////////////////////////
            // socketListenerThread.MasterDispatchNmeaMessage errors here with 'can't resolve
            // ////////////////////////////////////////////////////////////
            socketListenerThread.MasterDispatchNmeaMessage(nmea);
            Log.d(TAG, "NMEA: " + nmea);
        }
    });
}



public class SocketListenerThread extends Thread {
    Socket socket;
    ArrayList<EachConnectionThread> connectionThreads = new ArrayList<EachConnectionThread>();
    public void run() {
        try {
            serverSocket = new ServerSocket(LISTENING_PORT);
            while (!isInterrupted()) { //You should handle interrupts in some way, so that the thread won't keep on forever if you exit the app.
                socket = serverSocket.accept();
                gConnectionCount++;
                EachConnectionThread thread = new EachConnectionThread(socket);
                connectionThreads.add(thread);
                thread.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void MasterDispatchNmeaMessage(String nmeaMessage) {
        for (EachConnectionThread serverThread : connectionThreads)
            serverThread.dispatchNmeaMessage(nmeaMessage);

    }
}


public class EachConnectionThread extends Thread {
    private Socket hostThreadSocket;

    EachConnectionThread(Socket socket) {
        hostThreadSocket = socket;
    }

    PrintStream printStream;

    @Override
    public void run() {
        try {
            OutputStream outputStream;
            outputStream = hostThreadSocket.getOutputStream();
            printStream = new PrintStream(outputStream);
            printStream.print("Connected\r\n");

            while(!printStream.checkError()) {
                SystemClock.sleep(2000);
                printStream.print("Still connected\r\n");
            }
            printStream.close();
            outputStream.close();
            hostThreadSocket.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
        gConnectionCount--;
    }

    public void dispatchNmeaMessage(String nmeaString){
        printStream.print(nmeaString);
    }
}

【问题讨论】:

  • Thread socketListenerThread; Thread 没有那个方法。方法解析是针对声明的类型 (Thread),而不是定义的类型 SocketListenerThread
  • 您是否考虑过使用服务而不是活动,它们都有上下文并且可以访问 gps 和其他通信功能,将所有这些逻辑绑定到活动并不是很好
  • 我没有考虑过服务。是时候接受更多的教育了。 ;)

标签: java android multithreading sockets serversocket


【解决方案1】:

更改成员变量声明

Thread socketListenerThread;

SocketListenerThread socketListenerThread;

因此您可以通过socketListenerThread 实例访问SocketListenerThread 方法。

【讨论】:

  • laato,您的更改绝对解决了问题。它不会让我再接受 8 分钟,所以请稍等。我什至没有想过该变量的声明会以这种方式改变行为。今天的精彩课程。你是一个学者,一个绅士。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-07
  • 2016-10-28
  • 2021-10-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多