简体   繁体   中英

Issues with multithreaded events on Android Development in Eclipse

Hi I'm relatively new to Android Development and never have had to use multithreading in Java (I have experience in more low leveled threading with C). I've also never tried to make my own event listeners before so I guess I'm not really sure what my error is here but I suspect it is something on a level of abstraction I cannot see.

Basically I'm just trying to make a TCP client listening protocol. I am trying to stick to API style standards as far as I understand them so I have created a Service TCPClient which does nothing but handle the TCP connection, sending messages out directly through an IBinder remote method call interface. I'm relatively sure this is working because I can see the response on my server (which simply echos responses for now). The way I understand it is that the forground Activity that calls the remote method is actually making it as a request to some other instance but the data sharing seems to be safe.

The complex part for me is the threading because I was trying to use a blocked read to read from the socket, because I don't want to sit and read over and over wasting processor time. So I have my Service spawn a thread to do nothing but sit there and block on reads. Then I tried writing an event listener and event of my own to handle it. So the thread that is reading will call the event listener to raise the event and send what it read to the Activity to update the display.

I feel like there must be some problem with how it's updating because when commenting out this part there seems to be no problem. I'll post parts of my code that seems relevant. Sorry for my verbosity! (I probably over used synchronized).

public class BossActivity extends Activity
implements NetworkListener{
private static TextView responses;

private boolean connected = false;
private TCPClient clientService;
private ServiceConnection tcpConnection = new ServiceConnection() {
    public void onServiceConnected(ComponentName className, IBinder service) {
        clientService = ((TCPClient.LocalBinder)service).getService();
        connected = true;

    }
    public void onServiceDisconnected(ComponentName className) {
        clientService = null;
        connected = false;
    }
};
 public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.bossactivity);        
//...
    bindService(new Intent(this, TCPClient.class),
            tcpConnection, Context.BIND_AUTO_CREATE);
//..
}

    public void onDataRead(Data d) {
    clientService.send(d.str);
    if(null != d && null != d.str)
        responses.setText(d.str);  ///PROBLEM LINE when comment out it                             
                                               ///doesn't die
}
}//End BossActivity


public class TCPClient extends Service{
private final LocalBinder mbinder = new LocalBinder();

public class LocalBinder extends Binder{
    TCPClient getService(){
        return TCPClient.this;
    }
}
private NetworkListener networkListener = null;
public void setOnDataRead(NetworkListener listener){
    networkListener = listener;
}

public synchronized void dataRead(Data data){
    if(null != networkListener && null != data){
        networkListener.onDataRead(data);
    }
}
    public IBinder onBind(Intent intent) {
    return mbinder;
}
    public interface NetworkListener extends EventListener {
    public void onDataRead(Data d);
}

public class NetworkReadEvent extends EventObject {
    private static final long serialVersionUID = -7218678248204219511L;
    public NetworkReadEvent(Object source) {
        super(source);
    }
}

public static class Data {
    String str;
}
}//End TCPClient


public class SocketReader extends Thread {
    BufferedReader in;
boolean alive = true;
boolean updated = false;
Data data;
TCPClient parent;
public SocketReader(BufferedReader input, TCPClient p){
       //...
    }

        public void run() {
    String str;

    while(running()){
        try {
            str = in.readLine();
                    Data dataBuf = new Data();
                    dataBuf.str = str;
                            parent.dataRead(dataBuf);           
                    } catch (IOException e) {
            continue;
        }
    }
}

I can clarify anything that I may have left out, I did not do anything special in the manifest except declaring the Service.

Thanks in advance!!!

A problem that most people come across in Java is that any GUI modification has to be done on the EDT (Event Dispatch Thread, or the main UI thread in Swing). This is required as Swing's implementation is not Thread-safe. As such UI programmers that also work with other Threads liberally use the EventQueue#invokeLater(Runnable) method.

The Android equivalent of this appears to be the method Activity#runOnUiThread(Runnable) . So, you should change your code to:

@Override
public void onDataRead(Data d) {
  clientService.send(d.str);
  if(null != d && null != d.str)
    final String dataString = d.str; // Must be final for Runnable to access.
    runOnUiThread(new Runnable() {
      @Override
      public void run() {
        responses.setText(dataString);
      }
    });
}

The reason you don't need to worry about this normally is that most methods you override in Android already run on the UI thread. For example, Activity#onCreate(Bundle) is called from the UI Thread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM