Где остановиться / уничтожить потоков в классе Android службы?

голоса
36

Я создал Резьбовое-сервис следующим образом:

public class TCPClientService extends Service{  
...

@Override
public void onCreate() {
    ...
    Measurements = new LinkedList<String>();
    enableDataSending();    
}

@Override
public IBinder onBind(Intent intent) {
    //TODO: Replace with service binding implementation
    return null;
}

@Override
public void onLowMemory() {
    Measurements.clear();
    super.onLowMemory();
}

@Override
public void onDestroy() {
    Measurements.clear();
    super.onDestroy();
    try {
        SendDataThread.stop();
    } catch(Exception e){
        ...     
    }

}

private Runnable backgrounSendData = new Runnable() {

    public void run() {
        doSendData();
    }
};

private void enableDataSending() {
    SendDataThread = new Thread(null, backgrounSendData, send_data);
    SendDataThread.start();
}

 private void addMeasurementToQueue() {
     if(Measurements.size() <= 100) {
         String measurement = packData();
         Measurements.add(measurement);
     }
 }

 private void doSendData() {
     while(true) {
         try {      
             if(Measurements.isEmpty()) {
                 Thread.sleep(1000);
                 continue;
             }
             //Log.d(TCP, C: Connecting...);
             Socket socket = new Socket();
             socket.setTcpNoDelay(true);
             socket.connect(new InetSocketAddress(serverAddress, portNumber), 3000);
             //socket.connect(new InetSocketAddress(serverAddress, portNumber));
             if(!socket.isConnected()) {
                 throw new Exception(Server Unavailable!);
             }
             try {
                 //Log.d(TCP, C: Sending: ' + message + ');
                 PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())),true);
                 String message = Measurements.remove();
                 out.println(message);
                 Thread.sleep(200);
                 Log.d(TCP, C: Sent.);
                 Log.d(TCP, C: Done.);
                 connectionAvailable = true;              
             } catch(Exception e) {
                 Log.e(TCP, S: Error, e);
                 connectionAvailable = false;
             } finally {
                 socket.close();
                 announceNetworkAvailability(connectionAvailable);
             }
         } catch (Exception e) {
             Log.e(TCP, C: Error, e);
             connectionAvailable = false;
             announceNetworkAvailability(connectionAvailable);
         }
    }
}

...
}

После того, как я закрыть приложение телефон работает очень медленно, и я предполагаю, что это происходит из-за нитку отказа терминации.

Кто-нибудь знает, что это лучший способ, чтобы завершить все темы, перед завершением приложения?

Задан 25/03/2009 в 05:04
источник пользователем
На других языках...                            


2 ответов

голоса
89

Приложение : Андроид структура обеспечивает много помощников для единовременной работы, фон работы, и т.д., которые могут быть предпочтительнее , чем пытаться свернуть свой собственный поток во многих случаях. Как уже упоминалось в ниже должности, AsyncTask является хорошей отправной точкой для изучения. Я призываю читателей заглянуть в рамочные положения , прежде чем даже начинают думать о делать свои собственные нарезание резьбы.

Есть несколько проблем, в примере коды вы публикуемый обратимся в следующем порядке:

1) Thread.stop () является устаревшим в течение довольно продолжительного времени, так как она может оставить зависимые переменные в несовместимых состояний при некоторых обстоятельствах. Смотрите эту страницу Sun ответа для более подробной информации (Edit: что ссылка теперь мертва, см этой страницы, почему не использовать Thread.stop () ). Предпочтительный способ остановки и запуска поток выглядит следующим образом (предполагается , что поток будет работать несколько неопределенно долго):

private volatile Thread runner;

public synchronized void startThread(){
  if(runner == null){
    runner = new Thread(this);
    runner.start();
  }
}

public synchronized void stopThread(){
  if(runner != null){
    Thread moribund = runner;
    runner = null;
    moribund.interrupt();
  }
}

public void run(){
  while(Thread.currentThread() == runner){
    //do stuff which can be interrupted if necessary
  }
}

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

2) Ваш список измерений доступен несколько потоков (поток событий и ваша нить пользователя) в то же время без какой - либо синхронизации. Похоже , вам не придется свернуть свои собственные синхронизации, вы можете использовать BlockingQueue .

3) Вы создаете новый сокет каждую итерацию вашей отправки Thread. Это довольно тяжеловес операция, и только действительно имеет смысл, если вы ожидаете измерения чрезвычайно редко (скажем, один час или меньше). Либо вы хотите постоянный сокет, который не воссоздается каждый циклом нити, или вы хотите работоспособные вы можете один выстрел «огнь и забыть», который создает сокет, отправляет все необходимые данные, и отделку. (Небольшое примечание об использовании стойкого гнезда, методы сокетов, которые блокируют, такие как чтение, не могут быть прерваны Thread.interrupt (), и поэтому, когда вы хотите, чтобы остановить поток, необходимо закрыть сокет, а также вызов прерывания)

4) Существует мало смысла бросать свои собственные исключения из в тему, если вы не ожидаете, чтобы поймать его где-нибудь в другом месте. Лучшее решение для регистрации ошибок и если это безвозвратное, остановить поток. Поток может остановить себя с кодом как (в том же контексте, как указано выше):

public void run(){
    while(Thread.currentThread() == runner){
      //do stuff which can be interrupted if necessary

      if(/*fatal error*/){
        stopThread();
        return; //optional in this case since the loop will exit anyways
      }
    }
  }

И, наконец, если вы хотите быть уверены, что нить не выходит с остальной частью вашего приложения, независимо от того, что, хорошая техника является вызов Thread.setDaemon (истинный) после создания и перед тем, как начать нить. Это помечает нить как демон поток, то есть VM будет гарантировать, что она автоматически уничтожается, если нет, не демон нити работает (например, если ваше приложение завершает работу).

Повинуясь передовой практики в отношении Нити должны гарантировать, что ваше приложение не зависает или замедлить телефон, хотя они могут быть достаточно сложными :)

Ответил 26/03/2009 в 17:36
источник пользователем

голоса
6

На самом деле, вам не нужно «бегун» переменный, как описано выше, что-то вроде:

while (!interrupted()) {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException ex) {
        break;
    }
}

Но вообще-то, сидя в Thread.sleep () петли действительно плохая идея.

Посмотрите на API AsyncTask в новом 1.5 API. Это, вероятно, решить вашу проблему более элегантно, чем при использовании сервиса. Ваш телефон становится медленным, потому что служба никогда не выключается - там нет ничего, что вызовет службу, чтобы убить себя.

Ответил 10/05/2009 в 13:58
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more