App overview: a simpler server listening on a port for connections. To each client that connects to that port, it sends the GPS NMEA strings as they come out of the GPS chip.
So onCreate starts a single new thread that listens at the port. For each connection, this listener thread spins off another new thread. Each of those threads currently just spits out a "still connected" message every two seconds. This part all works, I can set up a couple telnet sessions and connect, all goes as expected. All of the location stuff is working in this code also; it properly updates the screen with correct and changing GPS info.
I want to register a single Nmealistener, and then have it dispatch that string to each thread serving a connection. However, socketListenerThread.MasterDispatchNmeaMessage(nmea) will not resolve inside addNmeaListener. (It won't resolve just outside of it, either.) the addNmeaListener doesn't seem to have an issue, if I have it just dump messages via Log.d it will happily do that.
Within the socketListenerThread class the method MasterDispatchNmeaMessage is also marked as "never called".
So what is preventing MasterDispatchNmeaMessage from becoming resolved?
For those not familiar, a sample NMEA string looks like this:
$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
They come in bursts, probably averaging five to ten lines a second on Samsung S4 I'm testing with.
Additional note: I'm targeting API 22. Past that, much more permission checking comes into play for the location classes. So I want to get all of this actually working before adding on the new permission checks to have it compliant with the latest libraries.
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);
}
}
Change the member variable declaration
Thread socketListenerThread;
to
SocketListenerThread socketListenerThread;
so you can access SocketListenerThread
methods via the socketListenerThread
instance.