2011-04-01 19 views
23

我使用AsyncTask來執行一個漫長的過程。從doInBackground中的函數內部publishProgress?

我不想將我的長處理代碼直接放在doInBackground中。相反,我的長程序代碼位於另一個類中,我在doInBackground中調用它。

我想能夠從longProcess函數內部調用publishProgress。 在C++中,我會將一個回調指針傳遞給我的longProcess函數publishProgress。

我該如何做到這一點在Java?

編輯:

我漫長的過程代碼:

public class MyLongProcessClass 
    { 
    public static void mylongProcess(File filetoRead) 
     { 
     // some code... 
     // here I would like to call publishProgress 
     // some code... 
     } 
    } 

我的AsyncTask代碼:

private class ReadFileTask extends AsyncTask<File, Void, Boolean> 
    { 
    ProgressDialog taskProgress; 

    @Override 
    protected Boolean doInBackground(File... configFile) 
     { 
     MyLongProcessClass.mylongProcess(configFile[0]); 
     return true; 
     } 
    } 

編輯#2 漫長的過程方法也可以是非靜態的,並呼籲像這個:

MyLongProcessClass fileReader = new MyLongProcessClass(); 
fileReader.mylongProcess(configFile[0]); 

但這並不能改變我的問題。

回答

32

的困難在於publishProgressprotected final所以即使你通過this到您static方法叫你仍然不能直接調用publishProgress

我還沒有嘗試過這個自己,但如何:

public class LongOperation extends AsyncTask<String, Integer, String> { 
    ... 

    @Override 
    protected String doInBackground(String... params) { 
     SomeClass.doStuff(this); 
     return null; 
    } 
    ... 

    public void doProgress(int value){ 
     publishProgress(value); 
    } 
} 
... 
public class SomeClass { 
    public static void doStuff(LongOperation task){ 
     // do stuff 
     task.doProgress(1); 
     // more stuff etc 
    } 
} 

,如果這個工程,請讓我知道!請注意,從doInBackground調用的方法以外的地方調用doProgress幾乎肯定會導致錯誤。

感覺我很骯髒,其他人有更好的方法?

+0

它可以工作,如果我的LongOperation類沒有調用xmlReader.parse(耗時代碼所在的位置)。看起來我會陷入一個簡單的旋轉進度對話框。 – 2011-04-01 19:43:20

+0

這似乎是一個很好的解決方案。豎起大拇指! – Wroclai 2011-04-01 21:42:11

+0

@Regis St-Gelais如果你試圖監視解析的進度,你可以試試[這種方法]或者[這個方法](http://stackoverflow.com/questions/5015856/android-sax-parser-progress-monitoring)或[this一個](http://stackoverflow.com/questions/3100013/java-sax-parser-progress-monitoring) – 2011-04-01 21:49:52

0

當你說「我漫長的過程代碼位於另一個類,我在doInBackground叫」你的意思是「位於另一個方法我在doInBackground稱之爲」?

如果是這樣,您可以使該方法成爲AsynTask類的私有方法。然後,只要需要,您可以在方法內部調用publishProgress。

+0

不是。它是位於AsyncTask類之外的靜態類中的一種靜態方法。 – 2011-04-01 19:14:03

+0

我編輯了我的問題以澄清 – 2011-04-01 19:23:05

2

longProcess()函數分解爲更小的函數。

示例代碼:

@Override 
protected Boolean doInBackground(Void... params) { 
    YourClass.yourStaticMethodOne(); 
    publishProgress(1); 
    YourClass.yourStaticMethodTwo(); 
    publishProgress(2); 
    YourClass.yourStaticMethodThree(); 
    publishProgress(3); 

    // And so on... 
    return true; 
} 
+0

不可能(或不適用)。這是一個XML解析器。 – 2011-04-01 19:24:21

+0

@Regis St-Gelais:有什麼複雜的?如果你從這些靜態方法中獲得一個值,你可以將它追上並傳遞給下一個函數。 AFAIK,沒有其他解決方案可用。 – Wroclai 2011-04-01 19:26:01

+0

代表怎麼樣? – 2011-04-01 19:32:29

1

如果此作品請讓我知道!請注意,從doInBackground調用的方法以外的任何地方調用doProgress幾乎肯定會導致錯誤。

是的,它的工作原理。我擴展了它,以便您不需要將AsyncTask作爲參數傳遞給您的方法。

public abstract class ModifiedAsyncTask<A,B,C> extends AsyncTask<A,B,C>{ 

    private static final HashMap<Thread,ModifiedAsyncTask<?,?,?>> threads 
      = new HashMap<Thread,ModifiedAsyncTask<?,?,?>>(); 

    @Override 
    protected C doInBackground(A... params) { 
     threads.put(Thread.currentThread(), this); 
     return null;   
    } 

    public static <T> void publishProgressCustom(T... t) throws ClassCastException{ 
     ModifiedAsyncTask<?, T, ?> task = null; 
     try{ 
      task = (ModifiedAsyncTask<?, T, ?>) threads.get(Thread.currentThread()); 
     }catch(ClassCastException e){ 
      throw e; 
     } 
     if(task!=null) 
      task.publishProgress(t); 
    } 
} 

public class testThreadsActivity extends Activity { 

/** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main);   
    } 

    public void Button1Clicked(View v){ 
     MyThread mthread = new MyThread(); 
     mthread.execute((Void[])null);  
    } 

    private class MyThread extends ModifiedAsyncTask<Void, Long, Void>{ 

     @Override 
     protected Void doInBackground(Void... params) { 
      super.doInBackground(params); 

      while(true){ 
       myMethod(System.currentTimeMillis());    
       try { 
        Thread.sleep(1000L); 
       } catch (InterruptedException e) {     
        return null; 
       } 
      }   
     } 

     protected void onProgressUpdate(Long... progress) { 
      //Update UI 
      ((TextView) findViewById(R.id.textView2)).setText("The Time is:" + progress[0]); 
     } 


    } 

    private void myMethod(long l){ 

     // do something 

     // request UI update 
     ModifiedAsyncTask.publishProgressCustom(new Long[]{l}); 
    } 

} 

:如果(像我一樣),你已經寫了決定,實際上你需要發佈一些進展,或在我的情況下,從一個的AsyncTask更新UI之前所有方法這是特別有用對我來說感覺很骯髒,其他人有更好的辦法嗎?

我的方式可能更糟。我打電話給doProgress的靜態方法(我稱之爲publishProgressCustom)。它可以從任何地方調用而不會產生錯誤(就好像線程在hashMap中沒有相應的AsyncTask,它不會調用publishProgress)。不利的一面是你必須在線程啓動後自己添加Thread-AsyncTask映射。 (你不能重寫AsyncTask.execute(),因爲這是最後的)。我在這裏通過覆蓋超類中的doInBackground()來完成它,所以任何擴展它的人都必須在他們自己的doInBackground()中將super.doInBackground()作爲第一行。

我對Threads和AsyncTask知之甚少,無法知道Thread和/或AsyncTask何時結束會對HashMap引用造成什麼影響。我懷疑發生了不好的事情,所以我不會建議任何人嘗試我的解決方案作爲他們自己的一部分,除非他們知道更好

+0

非常糟糕的主意這樣做。如果調用線程是不同的,它不會工作。另外你正在把線程放在HashMap中,但是不能刪除它們。 – xmen 2014-12-01 05:34:52

5

解決方案可以在AsyncTask中放置一個簡單的public類(確保您定義的任務也是它有一個public方法,它調用publishProgress(val)。傳遞該類應該可以從任何其他包或類中獲得。

public abstract class MyClass { 

    public MyClass() { 
     // code... 
    } 

    // more code from your class... 

    public class Task extends AsyncTask<String, Integer, Integer> { 
     private Progress progress; 

     protected Task() { 
      this.progress = new Progress(this); 
     } 

     // ... 

     @Override 
     protected Integer doInBackground(String... params) { 
      // ... 
      SomeClass.doStuff(progress); 
      // ... 
     } 

     // ... 

     @Override 
     protected void onProgressUpdate(Integer... progress) { 
      // your code to update progress 
     } 

     public class Progress { 
      private Task task; 

      public Progress(Task task) { 
       this.task = task; 
      } 

      public void publish(int val) { 
       task.publishProgress(val); 
      } 
     } 
    } 
} 

,然後在其他類:

public class SomeClass { 
    public static void doStuff(Progress progress){ 
     // do stuff 
     progress.publish(20); 
     // more stuff etc 
    } 
} 

這爲我工作。

+0

+1爲完美答案...爲我工作...謝謝:) – 2014-09-10 14:56:25

相關問題