2011-04-01 33 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