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...).
Related
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.
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).
I want to create a generic AsynceTask class that all my activities use/share for downloading content from a url. for this reason, I don't want the OnPostExecute to do anything other than to send the content back to some method in the activity that invoked the AsyncTask class.
I know that I need to create a constructor that sets the context of the Activity that invoked the AsyncTask, but then what, how do I use the context to send something back the the activity corresponding to that context. I've seen no tutorials that show how to use context in this manner.
Lets say I have:
public class LoginActivity {
public int ActivityMember;
public void HandleButtonClick(void){
DownloadFromURL task = new DownloadFromURL(this);
task.execute(url);
}
public void HandleLoginResult(int x){
ActivityMember = x;
}
}
now in a separate java file I have:
private class DownloadFromURL extends AsyncTask<List<NameValuePair>, Long, JSONObject> {
Context context;
public void DownloadFromURL (Context context){
this.context = context;
}
#Override
protected void onPostExecute(JSONObject json) {
context.(<- *my question involves this part of code)
}
}
I'm pretty sure I cant call context.ActivityMember, or context.HandleLoginResult(y) inside onPostExecute, because context is not of the type LoginActivity, its a Context.
So how can I access members or methods belonging to LoginActivity, using it's context?
you can use ((ActivityName)contextName).methodName()
But it is not a good solution. You can try something like this
pass your activity name along with the context to the async class.
protected void onPostExecute(SoapObject result)
{
if(classname.equals("LoginActivity"))
{
((LoginActivity) object).method();
}
else if(classname.equals("MainActivity"))
{
((MainActivity) object).method();
}
}
Easy to do, you just create a method in your activity and call it from the instance you pass through AsyncTask parent class constructor.
Assume you have in your activity some like this:
public void Foo(ArrayList<DataType> data)
{
//Do some with data
}
You then call this method from onPostExecute like this:
#Override
protected void onPostExecute(ArrayList<DataType> data)
{
activity.Foo(data);
}
Where activity is the instance passed through the constructor.
Cheers
This involves basic Object Oriented Programming knowledge.
If you look closely at http://developer.android.com/reference/android/app/Activity.html you can see Activity extends Context, that's why you can get away with passing this to your AsyncTask constructor and having the compiler do the required object slicings.
We can use that to your advantage: Create an abstract class extending Activity (Let's say: DataActivity, just an example though, name it whatever you want) and write a method named onDataDownloadComplete(JSONObject json) (A callback) on it, that you would of call on your AsyncTask's onPostExecute. Make all your activities extend from DataActivity and implement that method. Change the AsyncTask context from Context to DataActivity so you can call the onDataDownloadComplete callback and you are done. Again, as DataActivity would of extend Activity and Activity extends Context, DataActivity or anyhting extending it would be a valid context for the AsyncTask.
Hope you find this useful.
I realized there is another way to achieve what I was trying to do. This takes away the Asyncrony, but for the case of login, I actually do want the UI to be inactive while the app trys to log in.
After I call
asyncTask.execute()
I can call
asyncTask.get()
and that will retrieve the result of doInBackground and allow you to run it on the spot. Alternatively I can use a timeout so I dont block forever:
asynceTask.get(5000, TimeUnit.MILLISECONDS)
I currently have a helper class to perform rudimentary AsyncTasks such as the following. I call the function from an activity as and when needed. The code seems to work fine and I haven't encountered any problems. But, I was wondering if this is a good coding practice or if there were any ramifications that I am unaware of. Any feedback would be gladly accepted and appreciated.
public class OtherUtils {
public static void updatePromptsOption(final boolean showPrompt, final Context context) {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
Editor preferenceEditor = PreferenceManager.getDefaultSharedPreferences(context).edit();
preferenceEditor.putBoolean(Constants.SHOW_PROMPT, showPrompt).commit();
return null;
}
}.execute();
}
}
I don't see anything wrong with doing things that way. Being a static function, you're not hiding implicit this references that could bite you later. Seems like a reasonable convenience function to me.
So, my first major application is almost coded and I'm doing optimizations on my code. The app works fine, but I'm not sure about my way of passing the context to other classes. I don't want to do it the wrong way. I stumbled upon articles and questions here in Stackoverflow about contexts and which is the right way to pass it to non-activity classes. I read the documentation as well, but being a Finn makes complicated tech speak even harder to understand.
So, a simple question. Is my way of passing my main activity's context to other (helper) classes correct? If not, where can I read more about better practice on these situations.
For example:
MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle sis){
super(sis);
new Helper(MyActivity.this).makeMyAppAwesome();
}
}
Helper.java
public class Helper {
Context context;
Helper(Context ctx){
this.context = ctx;
}
public void makeMyAppAwesome(){
makeBaconAndEggsWithMeltedCheese(context);
}
}
Is this OK? It would be nice if someone could provide an easy to read article with examples on this subject.
You can do that using ContextWrapper, as described here.
For example:
public class MyContextWrapper extends ContextWrapper {
public MyContextWrapper(Context base) {
super(base);
}
public void makeMyAppAwesome(){
makeBaconAndEggsWithMeltedCheese(this);
}
}
And call the non activity class like this from an Activity
new MyContextWrapper(this);
It is usually in your best interest to just pass the current context at the moment it is needed. Storing it in a member variable will likely lead to leaked memory, and start causing issues as you build out more Activities and Services in your app.
public void iNeedContext(Context context) {...
Also, in any class that has context, I'd recommend making a member variable for readability and searchability, rather than directly passing or (ClassName.)this. For example in MainActivity.java:
Context mContext = MainActivity.this;
Activity mActivity = MainActivity.this;
I have passed context like this which solved my problem:
public class Utils extends ContextWrapper {
private final Context context;
public Utils(Context context) {
super(context);
this.context = context;
}
public void mymethod(){}
}
super(context); with ContextWrapper helped to make getBaseContext() and getApplicationContext() valid and this.context = context; captured context in variable which I can use wherever needed in methods.
Maybe alternatively you can just opt for using a constructor with this.context = context; and replace all occurrences of getApplicationContext() and getBaseContext().
Well, an even better way is to pass context directly to the method if using only few from a class for avoiding memory leaks.
You could also create a static instance reference to your MainActivity initialized in the onCreate() method
public class MainActivity extends AppCompatActivity {
public static MainActivity mMainActivity;
#Override
private onCreate(Bundle savedInstanceState){
//...
mMainActivity = this;
}
}
and call the context like this:
MainActivity.mMainActivity;
or write a method getInstanceOf() if it's clearer and/or you prefer using an accessor
MainActivity.getInstanceOf();
This strategy might provide you with some flexibility if you decide later that you would like to call an instance method contained in your main activity like so:
MainActivity.mMainActivity.myInstanceMethod();
Just a suggestion. Criticism is welcome and encouraged.