I got so tired of Memory leaks in my android application which was caused mainly by the AsyncTask object of the Android framework, so I've implemented my own as part of my "
Cyborg"
project, this works for me...
I can use the same instance of the task over and over and over, and to publish to the UI on a UI thread...
Shame on you Android and shame on you Google... :(
No warranty... use at your own risk!!!
I've updated this on the
16-03-2012, previous version had a design flaw.
package com.nu.art.software.android.core;
import java.lang.ref.WeakReference;
import android.os.Handler;
import android.os.Message;
import com.nu.art.software.android.log.AndroidLogImpl;
import com.nu.art.software.android.log.Logger;
public abstract class AsyncTaskModel<Model, Progress, Result>
extends Handler
implements Logger {
@Override
@SuppressWarnings("unchecked")
public void handleMessage(Message msg) {
switch (msg.what) {
case ProgressUpdate :
onProgressUpdate((Progress) msg.obj);
break;
case ExecutionCompleted :
onExecuteCompleted((Result) msg.obj);
break;
case ExecutionCancelled :
onExecutionCancelled((Result) msg.obj);
break;
case Dispose :
model = null;
threadReference = null;
break;
}
super.handleMessage(msg);
}
private static final int ProgressUpdate = 1;
private static final int ExecutionCompleted = 2;
private static final int ExecutionCancelled = 3;
protected static final int Dispose = 4;
protected Model model;
private final String name;
private WeakReference<Thread> threadReference;
private volatile boolean cancelled;
protected AsyncTaskModel(String name) {
super();
this.name = name;
}
public final boolean isRunning() {
return threadReference != null;
}
public final void execute(Model model) {
if (isRunning())
throw new TaskInProcessException("Task is already running");
this.model = model;
cancelled = false;
onPreExecute();
Runnable r = new Runnable() {
@Override
public void run() {
Result result = doInBackgroundImpl();
Message message;
if (cancelled)
message = obtainMessage(ExecutionCancelled);
else
message = obtainMessage(ExecutionCompleted);
message.obj = result;
message.sendToTarget();
message = obtainMessage(Dispose);
message.sendToTarget();
}
};
Thread thread = new Thread(r, name);
thread.start();
threadReference = new WeakReference<Thread>(thread);
}
protected abstract Result doInBackgroundImpl();
protected abstract void onProgressUpdate(Progress progress);
public final void cancel() {
cancelled = true;
cancelImpl();
if (threadReference != null)
threadReference.get().interrupt();
}
@SuppressWarnings("unused")
protected void onExecutionCancelled(Result result) {}
protected void cancelImpl() {}
@SuppressWarnings("unused")
protected void onExecuteCompleted(Result result) {}
protected void onPreExecute() {}
public void publishProgress(Progress progress) {
if (cancelled)
return;
Message message = obtainMessage(ProgressUpdate);
message.obj = progress;
message.sendToTarget();
}
public boolean wasCancelled() {
return cancelled;
}
@Override
public void logDebug(String debug) {
AndroidLogImpl.LogImpl.logDebug(debug);
}
@Override
public void logError(String error) {
AndroidLogImpl.LogImpl.logError(error);
}
@Override
public void logError(String error, Throwable e) {
AndroidLogImpl.LogImpl.logError(error, e);
}
@Override
public void logError(Throwable e) {
AndroidLogImpl.LogImpl.logError(e);
}
@Override
public void logInfo(String info) {
AndroidLogImpl.LogImpl.logInfo(info);
}
@Override
public void logVerbose(String verbose) {
AndroidLogImpl.LogImpl.logVerbose(verbose);
}
@Override
public void logWarning(String warning) {
AndroidLogImpl.LogImpl.logWarning(warning);
}
@Override
public void logWarning(String warning, Throwable e) {
AndroidLogImpl.LogImpl.logWarning(warning, e);
}
}
|
Java2html
|
Kenny Singer,
ReplyDeleteFYI, the thing the original AsyncTask is missing, is an under management of the:
public void disconnect ()
{
if (mActivity != null) {
mActivity = null;
Log.d ("Demo", "RandomColorsTask has successfully disconnected from the activity.");
}
} // end disconnect
Mentioned in 'RandomColorTask.java' file...
Together with a field of the UI component associated with the Task.
Hey!! Sorry to revive this post but... why the model is never used? you put in the execute method as a parameter and then you only dispose it.
ReplyDeletedoInBackgroundImpl() implementation in the inheriting Class would have access to the model and once the call to that method ends, it would nullify the model reference, thus preventing the Memory leak.
Delete