2017-07-28 3 views
0

So hatte ich einen Riss bei der Codierung meiner eigenen AsyncTask Klasse wie System, das nativ auf einem ThreadPoolExecutor läuft. Alles funktionierte gut, bis ich beschloss, die Fortschrittsseite der Dinge umzusetzen. Der Fortschritt funktioniert ähnlich wie AsyncTask, die onProgressUpdate Funktion wird auf dem UI-Thread aufgerufen. Das Problem, das ich erfahre, ist, dass immer, wenn es eine System.out oder Log.x Zeile in der onProgressUpdate gibt, es unbegrenzt ohne Fehler oder Warnung hängt. Der Code ist wie folgt:Android AsyncTask Fortschritt Update hängen

public abstract class Task<A, B> { 

    private static final Executor EXECUTOR = getExecutor(); 
    private static final int DEFAULT_PRIORITY = Thread.MIN_PRIORITY; 
    private static final int DEFAULT_PROGRESS_INCREMENT = 1; 

    private static final Executor getExecutor() { 
     ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool(); 
     executor.setCorePoolSize(1); 
     executor.allowCoreThreadTimeOut(false); 
     // TODO set rejection handler 
     //executor.setRejectedExecutionHandler(new Handler()); 
     // TODO set thread factory 
     executor.prestartCoreThread(); 
     return executor; 
    } 

    public static class ExecutionListener<B> { 

     public void onPreExecute() { 
      Log.i("TASK", "Pre - Thread: " + Thread.currentThread().getId()); 
     } 

     public void onPostExecute(B output) { 

      Log.i("TASK", "Post - Thread: " + Thread.currentThread().getId() + " - Output: " + output); 
     } 

     public void onProgressUpdate(int progress) { 
      Log.d("TASK", "Hello"); 
     } 
    } 

    private Handler handler; 
    private ExecutionListener<B> executionListener; 
    private volatile int progress = 0; 
    private AtomicBoolean progressPublished = new AtomicBoolean(true); 
    private B output; 

    public Task() { 
     this.handler = new Handler(); 
     this.executionListener = new ExecutionListener(); 
    } 

    public void setExecutionListener(ExecutionListener executionListener) { 
     if(executionListener == null) { 
      this.executionListener = new ExecutionListener(); 
     } 
     else { 
      this.executionListener = executionListener; 
     } 
    } 

    protected void updateProgress(int progressMade) { 
     Log.d("TASK", "Test"); 
     progress += progressMade; 
     if(progressPublished.compareAndSet(true, false)) { 
      if(!handler.post(new Runnable() { 
       @Override 
       public void run() { 
        Log.d("TASK", new Integer(progress).toString() + " - a"); 
        executionListener.onProgressUpdate(progress); 
        // Hangs below 
        progressPublished.lazySet(true); 
        Log.d("TASK", new Integer(progress).toString() + " - b"); 
       } 
      })) { 
       Log.d("TASK", "Failed to post"); 
      } 
     } 
    } 

    protected void updateProgress() { 
     updateProgress(DEFAULT_PROGRESS_INCREMENT); 
    } 

    protected abstract B doTask(A input); 

    public void execute(final A input, final int priority) { 
     EXECUTOR.execute(new Runnable() { 
      @Override 
      public void run() { 
       Thread.currentThread().setPriority(priority); 
       handler.post(new Runnable() { 
        @Override 
        public void run() { 
         executionListener.onPreExecute(); 
        } 
       }); 
       output = doTask(input); 
       if(!handler.post(new Runnable() { 
        @Override 
        public void run() { 
         Log.d("TASK", "Done"); 
         executionListener.onPostExecute(output); 
        } 
       })) { 
        Log.d("TASK", "Failed to post post"); 
       } 
      } 
     }); 
    } 

    public void execute(final A input) { 
     execute(input, DEFAULT_PRIORITY); 
    } 
} 

Die ExecutionListener nur eine Klasse, die Methoden zu überschreiben auf der Benutzeroberfläche ähnlich wie AsyncTask Methoden ausgeführt werden soll das gleiche zu tun. Der Code verwendet Runnable-Objekte, um die doTask-Methode auszuführen und Aktualisierungen/das Ergebnis an die entsprechende Methode im ExecutionListener zu senden.

Die Thread.currentThread() Teile sind nur um sicherzustellen, dass die Dinge auf dem Thread ausgeführt werden, den ich sie beabsichtigte. Das Problem zeigt sich nur beim Ausführen einer Aufgabe, die häufig updateProgress() aufruft - ich habe versucht, einen Thread schlafen in der onProgressUpdate()-Methode und das scheint so Dinge zu lösen, obwohl das offensichtlich keine gute Lösung ist.

Es scheint auch nur ein Problem mit Log.x/System.out - Ich weiß nicht, ob die Anrufhäufigkeit von beiden von ihnen diese Art von Problem verursachen könnte. Ich bin mit dieser Fortschrittsfunktion und Protokollierung ratlos, so dass jeder Ratschlag sehr geschätzt würde - ich habe auch festgestellt, dass dies ziemlich schwer zu erklären ist, also bitte frag, ob du mich etwas klären musst!

Antwort