Проблемы с многопоточными событиями в Android Development в Eclipse - PullRequest
0 голосов
/ 07 декабря 2011

Привет, я относительно новичок в разработке Android и никогда не использовал многопоточность в Java (у меня есть опыт в более низкоуровневой многопоточности с C). Я также никогда не пытался сделать своих собственных слушателей событий, поэтому, я думаю, я не совсем уверен, что моя ошибка здесь, но я подозреваю, что это что-то на уровне абстракции, которую я не вижу.

По сути, я просто пытаюсь создать протокол прослушивания TCP-клиента. Я пытаюсь придерживаться стандартов стилей API, насколько я их понимаю, поэтому я создал Service TCPClient, который ничего не делает, кроме обработки соединения TCP, отправляя сообщения напрямую через интерфейс удаленного вызова методов IBinder. Я относительно уверен, что это работает, потому что я могу видеть ответ на своем сервере (который просто пока отражает ответы). Насколько я понимаю, forground Activity, которая вызывает удаленный метод, фактически делает его запросом к какому-то другому экземпляру, но обмен данными кажется безопасным.

Сложной частью для меня является многопоточность, потому что я пытался использовать заблокированное чтение для чтения из сокета, потому что я не хочу сидеть и читать снова и снова, тратя впустую процессорное время. Так что у меня есть служба, порождающая поток, который ничего не делает, но сидит там и блокирует чтение. Затем я попытался написать обработчик событий и собственное событие, чтобы справиться с этим. Таким образом, поток, который читает, вызовет прослушиватель событий, чтобы вызвать событие, и отправит прочитанное в Activity для обновления отображения.

Я чувствую, что должна быть какая-то проблема с тем, как она обновляется, потому что при комментировании этой части, похоже, нет проблем. Я выложу части своего кода, которые кажутся актуальными. Извините за мое многословие! (Я, вероятно, более используется синхронизированы).

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;
        }
    }
}

Я могу уточнить все, что мог упустить, я не делал ничего особенного в манифесте, кроме объявления Службы.

Заранее спасибо !!!

1 Ответ

0 голосов
/ 07 декабря 2011

Проблема, с которой большинство людей сталкиваются в Java, заключается в том, что любая модификация GUI должна быть сделана в EDT (Поток диспетчеризации событий или основной поток пользовательского интерфейса в Swing).Это необходимо, поскольку реализация Swing не является поточно-ориентированной.В качестве таких UI-программистов, которые также работают с другими потоками, свободно используется метод EventQueue#invokeLater(Runnable).

Эквивалентом этого для Android является метод Activity#runOnUiThread(Runnable).Итак, вы должны изменить свой код на:

@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);
      }
    });
}

Обычно вам не нужно беспокоиться об этом, потому что большинство методов, которые вы переопределяете в Android, уже выполняются в потоке пользовательского интерфейса.Например, Activity#onCreate(Bundle) вызывается из потока пользовательского интерфейса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...