Místo pro zastavení / zničit závity ve třídě Android Service?

hlasů
36

Vytvořil jsem se závitem Service následujícím způsobem:

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

...
}

Poté, co jsem zavření aplikace telefon funguje docela pomalé a myslím, že to je kvůli navlékat selhání ukončení.

Ví někdo, co je nejlepší způsob, jak ukončit všechny příspěvky před ukončením aplikace?

Položena 25/03/2009 v 05:04
zdroj uživatelem
V jiných jazycích...                            


2 odpovědí

hlasů
89

Dodatek : služby Android Rámec poskytuje mnoho pomocníků pro jednorázové práce, práce na pozadí, atd, což může být výhodnější než se snaží vytvořit vlastní vlákno v mnoha případech. Jak již bylo zmíněno v níže příspěvku AsyncTask je dobrým výchozím bodem, aby se zabývala. Chtěl bych vyzvat čtenáře nahlédnout do rámcových předpisů první ještě předtím, než začal přemýšlet o tom, svůj vlastní závit.

Existuje několik problémů v ukázkovém kódu jste vyslán se budu zabývat v tomto pořadí:

1) Thread.stop () byla ukončena po nějakou dobu nyní, jak to může nechat závislé proměnné v nekonzistentních států za určitých okolností. Viz tuto odpověď strana Sun pro bližší informace (Edit: odkazující je teď mrtvý, vidět tuto stránku, proč nepoužívat Thread.stop () ). Výhodný způsob zastavení a spuštění nitě je následující (za předpokladu, že nit se spustí poněkud po neomezenou dobu):

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

To je jen jeden příklad toho, jak zastavit vlákno, ale stánek s jídlem je, že jsou zodpovědné za ukončení vlákno stejně jako byste jakékoliv jiné metody. Dodržovat metodu křížového vlákna communcation (v tomto případě těkavá variabilní, může být i přes mutexu, atd) a také ve vašem vlákna logiky, používat tento způsob komunikace zjistit, jestli jste měl brzký odchod, vyčištění, atd.

2) V seznamu měření je přistupovat více závity (událost nití a uživatelské závit) najednou bez synchronizace. Vypadá to, že nemáte vytvořit vlastní synchronizaci, můžete použít BlockingQueue .

3) Při vytváření nové zásuvka každé iteraci svého vysílacího Thread. Jedná se o poměrně silný provoz, a jen opravdu smysl, pokud očekáváte, že měření bude velmi častá (řekněme jednu hodinu nebo méně). Buď chcete trvalou zásuvku, která není znovu každou smyčku nitě, nebo chcete jeden výstřel runnable můžete ‚vystřel a zapomeň‘, které vytvoří socket, pošle všechny relevantní údaje, a povrchové úpravy. (Krátká poznámka o používání přetrvávající zásuvka, zásuvka metody, které blokují, jako je čtení, nemůže být přerušen Thread.interrupt (), a tak když chcete zastavit nit, musíte zavřít socket, stejně jako volání přerušení)

4) Nemá smysl házet své vlastní výjimky zevnitř niti, pokud předpokládáte, že chytat někde jinde. Lepším řešením je protokolovat chyby a pokud je to nedobytné, zastavte nit. Vlákno může zastavit se s kódem, jako je (v tomto kontextu jako výše):

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

A konečně, pokud chcete být jisti, že vlákno ukončí se zbytkem aplikace, bez ohledu na to, dobrá technika je volání Thread.setDaemon (pravou) po vytvoření a před zahájením vlákno. Tato flags nit jako daemon závit, což znamená, že VM zajistí, že se automaticky zničeny, pokud nejsou k dispozici žádné non-daemon závit běží (například pokud vaše aplikace ukončí).

Poslouchání osvědčených postupů s ohledem na nitě by měly zajistit, aby vaše aplikace nevisí nebo zpomalit telefon, ačkoli oni mohou být docela složité :)

Odpovězeno 26/03/2009 v 17:36
zdroj uživatelem

hlasů
6

Ve skutečnosti, nemusíte na „runner“ proměnné, jak je popsáno výše, něco jako:

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

Ale obecně, posezení v Thread.sleep () smyčky je opravdu špatný nápad.

Podívejte se na API AsyncTask v novém 1,5 API. To bude asi váš problém vyřešit elegantněji než při použití služby. Tento telefon je stále pomalý, protože služba nikdy vypne - není nic, co způsobí, že službu zabít sám.

Odpovězeno 10/05/2009 v 13:58
zdroj uživatelem

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