Why inner AsyncTask needs to be static but Thread doesn't? - android

In the following example if I declare an AsyncTask android studio gives a warning so that I should define it static. According to the this great explanation we define it as a static class to make it possible for virtual machine to garbage collect the service.
But it appears that thread does not need to be static. Why is that? Is it just android studio that doesn't give a warning or thread behaves in a totally different way?
public class MyTrackingService extends Service {
class TrackingThread extends Thread {
private final Context cotext;
TrackingThread(Context context){
this.cotext = context;
}
#Override
public void run() {
super.run();
}
}
class TrackingTask extends AsyncTask<Void, Void, Void> {
private final Context context;
TrackingTask(Context context){
this.context = context;
}
#Override
protected Void doInBackground(Void... voids) {
return null;
}
}
}

In the following example if I declare an AsyncTask android studio gives a warning so that I should define it static
The Lint warning is over-aggressive. The need for it to be static mostly comes with activities and fragments.
Of course, having an AsyncTask in a Service, as you do here, is pointless. You almost never want to do anything on the main application thread in a Service, and the point of AsyncTask is to do something on the main application thread when the task completes. Having an AsyncTask without onPostUpdate() is a code smell and indicates that you should be using something else, such as a regular thread.
Also note that while AsyncTask is not officially deprecated, its use is has been frowned upon for the past few years.
But it appears that thread does not need to be static
It suffers from the same problems that AsyncTask does. There just isn't a Lint warning for it.
Is it just android studio that doesn't give a warning
Correct.

Related

Using context as a member variable in all classes

I am really new to Android development. In my app, I perform different async task and needed to save the result from those task to the database which requires context. Inspired from this answer I started using context in all my classes as a member variable. This seemed like a good method, but now ALL my background task and other classes which deal with preference have context as a member variable.
Code example -
public class Task extends AsyncTask<Void, Void, String> {
Context context;
public Task(Context context){
super();
this.context = context;
}
protected String doInBackground() {
//myAsyncTask
..
}
..
protected void onPostExecute(String response) { //response from the request
DbHelper helper = new DbHelper(context);
//save to db
}
I have about 3 or more of such tasks running consecutively at times. So whenever I need to do a background task, I first have to initialize the async task with the context and then initialize the DbHelper using that context. I feel like I'm doing it all wrong. This doesn't seem like a good method to me now (may lead to huge memory leaks imo). Plus it feels like duplication and that I can have access to the context in a better way.
Is it recommended to use context like this? Or does it actually have a disadvantage and I'm better off using some other method? Something like
public class MyApplication extends Application {
private static Context context;
public void onCreate(){
super.onCreate();
MyApplication.context = getApplicationContext();
}
public static Context getAppContext() {
return MyApplication.context;
//use context as MyApplication.getAppContext();
}
}
Which one is better to use?
Neither is correct. Do NOT maintain a reference to Context anywhere, it gives memory leaks because then the VM cannot garbage-collect the Context. We also tried several solutions but all failed. There's no other solution than pass the Context whenever you need it (if you look at the Android API you will see that it also works this way, and it's for a reason).

How to implement a "fire-and-forget" async call in Android?

I am reviewing/cleaning up some Android code. The code did some "asynchronous" network and data operations using this pattern:
new Thread() { public void run() { { ... runOnUiThread( { .. } ) }
A lot. With all the ugly consequences (no error checks, Sleeps, boolean finish variables...).
Till now, I ended up using (few) AsyncTasks and (more) Loaders as replacements.
Now I have stumbled upon a couple of "fire-and-forget" network communications: the code (currently, a Thread, as always) calls a web service posting some data.
I do not need to know if the data was received, and I do not need to know if there was any error.
Which is the best way of doing this? A Runnable or AsyncTask (static nested class, so I do not "leak" a reference to "this" activity?)
Or is there something better (more "lightweight" and cleaner?)
If you don't need to know when task execution is finished then you definitely don't need AsyncTask at all. Therefore the most lightweight solution is just a Thread. You can use Executor which will create threads for you. To get rid of nested classes you could predefine tasks. Sample:
Predefined task:
public static class TaskA implements Runnable{
private int someParam;
public TaskA(int someParam) {
this.someParam = someParam;
}
#Override
public void run() {
//
}
}
Static Executor
public static class FireAndForgetExecutor{
private static Executor executor = Executors.newFixedThreadPool(5);
public static void exec(Runnable command){
executor.execute(command);
}
}
And usage:
FireAndForgetExecutor.exec(new TaskA(10));
PS don't forget that a Thread is connected to the GC root! So if you pass heavy object like an activity or a bitmap into the task it could lead to memory leak.

Async Task OnProgressUpdate CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views

I am using an AsyncTask to download a database with a progressdialog that shows progress on the UI. Some of my users are receiving the error:
CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
As I understand it, this should only happen if you are trying to update Views off of the UI thread. Here is the error:
com...updateops.DbCreate.onProgressUpdate(DbCreate.java:70)
at com...updateops.DbCreate.onProgressUpdate(DbCreate.java:1)
and here is my code:
public class DbCreate extends AsyncTask<String, String, String>{
private static Context mCtx;
private static ProgressDialog mDialog;
public static AmazonSimpleDBClient mSDbClient;
public static AmazonS3Client mS3Client;
private static int mAppVersion;
private static boolean mCreate;
public DbCreate(Context ctx, int versionCode, boolean create) {
mCtx = ctx.getApplicationContext();
mAppVersion = versionCode;
mDialog = new ProgressDialog(ctx);
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDialog.setMessage("Checking for server access. Please wait...");
mDialog.setCancelable(false);
mDialog.setMax(1);
mDialog.show();
mCreate = create;
}
protected void onProgressUpdate(String... name) {
if (name[0].equals("item")) {
mDialog.incrementProgressBy(1);
} else if (name[0].equals("setMax")) {
mDialog.setProgress(0);
mDialog.setMax(Integer.parseInt(name[1])); <-- This is line 70
}}
#Override
protected String doInBackground(String... arg0) {
**do stuff**
publishProgress("setMax", ""+ 3);
}
It looks to me like I am following exactly what I am supposed to do in order to avoid this error. Anyone know why it's happening?
Edit: I should also mention that this code works most of the time. I am receiving crash reports on the Developer Console.
According to the onProgressUpdate(Progress...) is invoked on the UI thread after a call to publishProgress(Progress...).
You should analyze the whole log report to check if there is any chance that your async task was created on other thread.
And if you really cannot find the root cause you can use a handler created on UI thread to workaround.
You code looks fine and in most of the cases it should work. I would suggest you to use handler. You can write a handler in UI thread and call it from onProgressUpdate(). This will completely ensure that the UI work is done in UI thread.
This will fix your issue for sure, but I dont know why you are gettin error at first hand. I have seen this kind of issue before and never got a concrete reason for it.
I had the same problem that you are describing and I fixed it by using a runOnUiThread() call against the context owned by the AsyncTask (as you also have in your example).
The following solution should absolve your issues;
#Override
protected void onProgressUpdate(final String... messages){
myActivityReference.runOnUiThread(new Runnable() {
#Override
public void run() {
// Your UI changes here.
}
});
}
It's worth noting that my AsyncTask was originally called from within a AlertDialog, which is what I believe is causing the issue to begin with.
I found the same issue on Android 2.3.x devices and here's the crash log:
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRoot.checkThread(ViewRoot.java:2934)
...
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.os.HandlerThread.run(HandlerThread.java:60)
The log indicates that onProgressUpdate and onPostExecute are executed on HandlerThread which is essentially a worker thread with a custom Looper. So that's why the crash occurs.
Therefore, in your case it is likely the internal handler of AsyncTask is bound to non main looper associated with a worker thread like HandlerThread and onUpdateProgress is processed on worker thread instead.
I found this bug appear pervasively on Android 2.3 devices. Therefore I checked the source code of AsyncTask in 2.3 and found this:
private static final InternalHandler sHandler = new InternalHandler();
private static class InternalHandler extends Handler {
#SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
#Override
public void handleMessage(Message msg) {
...
}
}
The chance is that the internal handler might be bound to a non main looper.
I also checked the latest source code of AsyncTask and saw the change:
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
...
}
The InternalHandler constructor eliminate the chance that it might be bound to a non main looper therefore onUpdateProgress behaves normal on post Android 2.3 devices.

Android AsyncTask with notification

I am currently starting to develop Android applications, and I must say that it all came out very very simple and straightforward.
I have a small question about the AsyncTask. Maybe I've been doing something wrong, but here's the situation.
I have a small app that needs to load a list's content from the web.
I developed everything based on fake requests, and it all came out awesome. Then I updated the code with actual requests and got the 'Network on main thread error'. So I decided to switch to AsyncTask.
I was wondering if I could let AsyncTask just do the asynchronous work, and handle the result somewhere else (where I actually have the GUI connections and everything). I thought that in terms of readability and logic it makes more sense to have all the code that handles the interface in the Activity, but how could I let the Activity know when a task was completed?
I wrote these simple classes and interfaces (and it works) but I wanted to know from you if this is a good thing or there are better methods to do that.
So, here's the code:
public interface AsyncDelegate {
public void executionFinished(LazyLoaderWithDelegate lazyLoaderWithDelegate);
}
This is a simple interface. The purpose is to have the Activity implement this and handle the 'executionFinished' method. Something like a listener.
import android.os.AsyncTask;
public class LazyLoaderWithDelegate<Params, Progress, Result> extends AsyncTask<Params, Progress, Result>{
AsyncDelegate delegate;
Result result;
public LazyLoaderWithDelegate(AsyncDelegate delegate){
this.delegate = delegate;
}
#Override
protected Result doInBackground(Object... params) {
//This will be Overridden again from the subclasses anyway.
return null;
}
#Override
protected void onPostExecute(Result r){
this.result = r;
delegate.executionFinished(this);
}
public Result getResult(){
return result;
}
}
This class basically gives a skeleton structure to notify the delegate when the task is finished.
That's all. Here's an example of using this classes:
public class LazyVideoLoader extends LazyLoaderWithDelegate<Void, Void, List<List<Video>>>{
public LazyVideoLoader(AsyncDelegate delegate) {
super(delegate);
}
#Override
protected List<Video> doInBackground(Void ...params) {
return ServerInterface.getVideos();
}
}
public class MainActivity extends Activity implements AsyncDelegate {
private LazyVideoLoader videoLoader;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*
* Set up the lazy loaders
*/
videoLoader = new LazyVideoLoader(this);
videoLoader.execute();
}
#Override
public void executionFinished(LazyLoaderWithDelegate task) {
if(task == videoLoader){
List<Video> result = videoLoader.getResult();
//Do whatever you need...
}
}
Everything you run on onPostExecute is in the UI Thread. Also you can run a code on UI Thread once a certain part of the work is done simply on onProgressUpdate by calling publishProgress on doInBackground.
Refer this for more information. It has everything you need to know about AsyncTask.
If I understand this correct you have a seperate class, which runs an AsyncTask. If the task is completed the as callback used interface informs the Activity. This is good if you think in components to make the code more modular.
The most common practice is to use an AsyncTask as an inner class in an Activity. If you just wanna download a picture or something similar with relative small size this is the prefered way. Because you can access all fields in your inner class, which makes things easier than passing them around in constructors/interfaces.
Don't use an AsyncTask in an extra Class just for readability. If you have to do some fair calculation/modification on the results with different methods your way is ok.

How to use SQLite DB from AsyncTask?

I've been using my Activity class to access my DB which made my program freeze sometimes.
So I decided to use AsyncTask instead to handle the DB.
My problem is I don't know how to instantiate my SQLite DB "TheDB" from AsyncTask's class
public class myClass extends AsyncTask<Void, Void, Void>{
private TheDB db;
any method() {
this.db = new TheDB(this); //<-- Error here
}
this worked fine on the Activity class, but it I dont know how to use it here
TheDB's constructor is TheDB(Context context) but this class is not a "context" so how can i use my DB here?
please provide examples if you can
and please do not give me links to google's references, am a newbie and i find them hard to follow
you need to pass the application context here
this.db = new TheDB(getApplicationContext());
import android.content.Context;
public class SuperTask extends AsyncTask<Void, Void, Void> {
private final Context mContext;
public SuperTask(Context context) {
super();
this.mContext = context
}
protected Void doInBackground(Void... params) {
// using this.mContext
}
}
public class MainActivity extends Activity {
// and run from Activity
public void onButtonClick(View view) {
new SuperTask(this.getApplicationContext()).execute();
}
}
There are two ways that i see:
Pass a context object to your AsyncTask constructor, then instantiate database like this this.db = new TheDB(context);
Or you probably can pass the actual database object to the constructor, but the first approach seems better.
An important part of learning to program is learning to read and understand documentation. As documentation goes, the Android docs are pretty detailed, so its really worth your time to understand how they work.
As you can see in the AsyncTask docs, there is no onCreate or onExecute method in an AsyncTask.
The docs clearly walk you through the 4 main functions of an AsyncTask, onPreExecute(), doInBackground(Params...), onProgressUpdate(Progress...), onPostExecute(Result).
The likely choices for your instance are onPreExecute() or doInBackground(Params...). The difference is whether or not you want the initializition to occur on the UI thread. If you don't, then do it in doInBackground(Params...).

Categories

Resources