从doInBackground中的函数内部发布进程?

时间:2011-04-01 18:58:42

标签: android

我使用AsyncTask执行一个很长的过程。

我不想将我的长进程代码直接放在doInBackground中。相反,我的长进程代码位于另一个类中,我在doInBackground中调用。

我希望能够从longProcess函数中调用publishProgress。 在C ++中,我将一个sendProgress的回调指针传递给我的longProcess函数。

我如何在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。编辑#2 长处理方法也可以是非静态的,并且如下所示:

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

但这不会改变我的问题。

5 个答案:

答案 0 :(得分:33)

困难在于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
    }
}

如果有效,请告诉我!请注意,从doProgress调用的方法以外的任何地方调用doInBackground几乎肯定会导致错误。

对我来说感觉很脏,其他人有更好的方法吗?

答案 1 :(得分:5)

解决方案可能是在AsyncTask中放置一个简单的public类(确保您定义的任务也是public),该类具有调用public的{​​{1}}方法。通过该课程应该可以从任何其他包或类中获得。

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

这对我有用。

答案 2 :(得分: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;
}

答案 3 :(得分:1)

  

如果有效,请告诉我!请注意,从doInBackground调用的方法以外的任何地方调用doProgress几乎肯定会导致错误。

是的,它有效。我扩展它,以便您不需要将AsyncTask作为参数传递给您的方法。如果(像我一样)在决定实际上你需要发布一些进度之前已经编写了所有方法,或者在我的情况下,从AsyncTask更新UI时,这个特别有用:

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

}
  

对我来说感觉很脏,其他人有更好的方法吗?

我的方式可能更糟。我正在为doProgress调用一个静态方法(我称之为publishProgressCustom)。它可以从任何地方调用而不会产生错误(好像该线程在hashMap中没有相应的AsyncTask,它不会调用publishProgress)。缺点是你必须在线程启动后自己添加Thread-AsyncTask映射。 (你不能轻易地覆盖AsyncTask.execute(),因为这是最终的)。我在这里通过覆盖超类中的doInBackground()来完成它,所以扩展它的任何人都必须将super.doInBackground()作为它们自己的doInBackground()中的第一行。

我不太了解Threads和AsyncTask,以便在Thread和/或AsyncTask结束后知道HashMap引用会发生什么。我怀疑发生了不好的事情,所以我不建议任何人尝试我的解决方案作为他们自己的一部分,除非他们知道更好

答案 4 :(得分:0)

当你说“我的长流程代码位于我在doInBackground中调用的另一个类”时,你的意思是“位于另一个方法中,我是在doInBackground中调用“?

如果是这样,您可以将该方法设置为AsynTask类的私有方法。然后,您可以在需要时在方法内调用publishProgress。