android - oncancelled - publishProgress desde dentro de una función en doInBackground?
oncancelled asynctask android (5)
Utilizo una AsyncTask para realizar un proceso largo.
No quiero colocar mi código de proceso largo directamente dentro de doInBackground. En cambio, mi código de proceso largo está ubicado en otra clase, a la que llamo en DoInBackground.
Me gustaría poder llamar a publishProgress desde dentro de la función longProcess. En C ++ pasaría un puntero de devolución de llamada a publishProgress a mi función longProcess.
¿Cómo hago eso en java?
EDITAR:
Mi código de proceso largo:
public class MyLongProcessClass
{
public static void mylongProcess(File filetoRead)
{
// some code...
// here I would like to call publishProgress
// some code...
}
}
Mi código de AsyncTask:
private class ReadFileTask extends AsyncTask<File, Void, Boolean>
{
ProgressDialog taskProgress;
@Override
protected Boolean doInBackground(File... configFile)
{
MyLongProcessClass.mylongProcess(configFile[0]);
return true;
}
}
EDITAR # 2 El método de proceso largo también podría ser no estático y llamado así:
MyLongProcessClass fileReader = new MyLongProcessClass();
fileReader.mylongProcess(configFile[0]);
Pero eso no cambia mi problema.
Si esto funciona, por favor hágamelo saber! Tenga en cuenta que llamar a doProgress desde cualquier lugar que no sea un método que ha sido invocado desde doInBackground es casi seguro que cause un error.
Si, funciona. Lo extendí para que no tenga que pasar AsyncTask como parámetro a su método. Esto es particularmente útil si (como yo) ya ha escrito todos sus métodos antes de decidir que realmente necesita publicar algún progreso, o en mi caso, actualizar la interfaz de usuario desde una 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});
}
}
Me parece bastante sucio, ¿alguien más tiene una mejor manera?
Mi camino es probablemente peor. Estoy llamando a un método estático para doProgress (al que llamé publishProgressCustom). Se puede llamar desde cualquier lugar sin producir un error (como si el subproceso no tiene una AsyncTask correspondiente en el hashMap, no llamará publishProgress). La desventaja es que usted debe agregar la asignación Thread-AsyncTask una vez que el hilo haya comenzado. (No puede anular AsyncTask.execute () tristemente ya que esto es definitivo). Lo he hecho aquí al anular doInBackground () en la súper clase, de modo que cualquiera que lo extienda solo tiene que poner super.doInBackground () como primera línea en su propio doInBackground ().
No sé lo suficiente sobre Threads y AsyncTask para saber qué sucede con las referencias de HashMap una vez que Thread y / o AsyncTask llegan a su fin. Sospecho que suceden cosas malas, por lo que no sugeriría que nadie intente mi solución como parte de la suya a menos que sepan mejor.
Cuando dices " mi código de proceso largo está ubicado en otra clase a la que llamo en DoInBackground ", ¿te refieres a " ubicado en otro método que llamo en DoInBackground "?
Si es así, podrías hacer que ese método sea un método privado de tu clase AsynTask. Luego, puede llamar a publishProgress dentro del método cuando sea necesario.
La dificultad es que publishProgress
está protected final
por lo que incluso si pasa this
a su método static
, aún no puede llamar a publishProgress
directamente.
No lo he intentado yo mismo, pero ¿qué tal?
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
}
}
Si esto funciona, por favor hágamelo saber! Tenga en cuenta que llamar a doProgress
desde cualquier lugar que no sea un método que ha sido invocado desde doInBackground
es casi seguro que cause un error.
Me parece bastante sucio, ¿alguien más tiene una mejor manera?
Una solución podría ser colocar una clase public
simple dentro de AsyncTask (asegúrese de que la tarea que defina también sea public
) que tenga un método public
que llame publishProgress(val)
. Pasar esa clase debe estar disponible desde cualquier otro paquete o clase.
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);
}
}
}
}
y luego en la otra clase:
public class SomeClass {
public static void doStuff(Progress progress){
// do stuff
progress.publish(20);
// more stuff etc
}
}
Esto funcionó para mí.
longProcess()
función longProcess()
en funciones más pequeñas.
Código de muestra:
@Override
protected Boolean doInBackground(Void... params) {
YourClass.yourStaticMethodOne();
publishProgress(1);
YourClass.yourStaticMethodTwo();
publishProgress(2);
YourClass.yourStaticMethodThree();
publishProgress(3);
// And so on...
return true;
}