I need to instantiate some objects in a separate thread cause i don' t want the UI to get slow. Using AsyncTask i faced the problem of a memory issue: the GC won't deallocate the memory.
So i found the solution declaring AsyncTask as a static inner class. I'm new to android developing so i need your help cause i'm having a NullPointerException. Here is my code:
-static variables because of the inner static class-
public class Wash extends ActionBarActivity {
private static Effetti effect1,effect2,effect3…effect50
private static Effetti[] effects;
.
.
.
-the static inner class-
private static class TaskL extends AsyncTask <Effetti[], Void,Effetti[]> {
#Override
protected Effetti[] doInBackground(Effetti[]... params) {
effects = new Effetti[]{
effects1 = new Effetti(MyApplication.getAppContext(),R.raw.ef1),
effect2=new Effetti(MyApplication.getAppContext(),R.raw.ef2),
effect3 = new Effetti(MyApplication.getAppContext(),R.raw.ef3),
effect4 = new Effetti(MyApplication.getAppContext(),R.raw.ef4),
.
.
.
};
return effects;
}
#Override
protected void onPostExecute(Effetti[] result) {
super.onPostExecute(result);
}
}
The "Effetti" class is a class which contains SoundPool methods for play and stop audio files. Also contains constructors with arguments like context and a resid.
I used MyApplication.getAppContext() trick seen in this post:
Static way to get 'Context' on Android? android
Any suggestion? thaks
I think that this line MyApplication.getAppContext() is giving you the NullPointerException.
You could try doing this:
private static class TaskL extends AsyncTask <Effetti[],Void,Effetti[]> {
Activity activity;
updateDashboardContent(Activity a){
activity=a;
}
#Override
protected Effetti[] doInBackground(Effetti[]... params) {
effects = new Effetti[]{
effects1 = new Effetti(activity.getApplicationContext(),R.raw.ef1),
effect2=new Effetti(activity.getApplicationContext(),R.raw.ef2),
effect3 = new Effetti(activity.getApplicationContext(),R.raw.ef3),
effect4 = new Effetti(activity.getApplicationContext(),R.raw.ef4),
.
.
.
};
return effects;
}
#Override
protected void onPostExecute(Effetti[] result) {
super.onPostExecute(result);
}
}
and according to which part of your code you call it like this:
new TaskL(getActivity()).execute(...); or new TaskL(this).execute(...);
If the above snippet doesn't work then try passing to the constructor of TaskL an Effetti array (doing what I did with 'activity') with variables effects1,effects2... already instantiated avoiding instantiating them in the AsyncTask...
Related
I have created as asynctask to upload data to a server as below. But it shows this warning eaxctly at class AsyncTaskUploadClass. "This AsyncTask class should be static or leaks might occurs......" I have read and tried the weak reference style but i am unable to integrate it in this code. Any leads will be appreciated.
public void ImageUploadToServerFunction(){
final String imageName1 = GetImageNameEditText1.trim();
final String userName = GetUserName.trim();
final String imageView1 = getStringImage1(bitmap1);
class AsyncTaskUploadClass extends AsyncTask<Void,Void,String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = ProgressDialog.show(UploadActivity.this,"Your Data is Uploading....",false,false);
}
#Override
protected void onPostExecute(String string1) {
super.onPostExecute(string1);
progressDialog.dismiss();
}
#Override
protected String doInBackground(Void... params) {
ImageProcessClass imageProcessClass = new ImageProcessClass();
HashMap<String,String> HashMapParams = new HashMap<>();
HashMapParams.put(ImageName1, imageName1);
HashMapParams.put(UserName, userName);
HashMapParams.put(ImagePath1, imageView1);
return imageProcessClass.ImageHttpRequest(ServerUploadPath, HashMapParams);
}
}
AsyncTaskUploadClass AsyncTaskUploadClassOBJ = new AsyncTaskUploadClass();
AsyncTaskUploadClassOBJ.execute();
}
It's in the nature of inner classes of Java- a class within a class has a hidden reference to the parent instance. That can cause memory leaks. The way to avoid that is to make it a static inner class- static class Foo. This will cause it to remove the hidden reference, but the inner class will no longer be able to reference functions or member variables of the parent.
More practically- this type of AsyncTask, while it technically can cause a temporary leak, is fairly safe as long as the doInBackground function terminates in a reasonable amount of time. For this class, if imageProcessClass.ImageHttpReques() runs and terminates (with either a timeout error or by finishing its work) in a reasonable amount of time it isn't a leak worry- it just that the parent class, which looks like an Activity, will not be freed until it does so. So it will force the parent class to stick around for a second or two longer than needed if the Activity is finished but the request is processing.
I have an DB manager class for my queries which runs with Asynctask:
public class DBManager {
private static DBCallback dbCallback;
//I need this for callbacks to main class when operation is finished
public DBManager(DBCallback mClass) {
this.dbCallback = mClass;
}
public static void getAllUsers() {
new AsyncTask<Void, Void, List<UserDB>>() {
#Override
protected List<UserDB> doInBackground(Void... voids) {
return DatabaseClient.getInstance(ApplicationContextProvider.getContext()).getAppDatabase().userDao().getAll();
}
#Override
protected void onPostExecute(List<UserDB> users) {
super.onPostExecute(users);
dbCallback.finishedReadFromDB(users); //Sending callback
}
}.execute();
}
public static void deleteUserLocal(final UserDB user) {
new AsyncTask<UserDB, Void, Void>() {
#Override
protected Void doInBackground(UserDB... users) {
DatabaseClient.getInstance(ApplicationContextProvider.getContext()).getAppDatabase().userDao().delete(users[0]);
return null;
}
}.execute(user);
}
}
At my MainClass I am using
dbManager = new DBManager(this);
for receiving callback, so I am using
dbManager.getAllUsers();
and then gets callback when operation is finished.
But I have fictions where I do not need to return anything like deleteUserLocal. So I can user ether
dbManager.deleteUserLocal(user)
or
DBManager.deleteUserLocal(user)
due to that the function is static.
From classes that not require callback of course I using
DBManager.deleteUserLocal(user)
So... I do not like that every time at onCreate am I am crating new instnce of DBManager:
dbManager = new DBManager(this);
Just for callbacks. How can I create a singleton class which I can use for callback and only use
DBManager.getAllUsers(); instead of dbManager.getAllUsers();
To achieve what you want, get rid of the constructor and change the static callback to public. That way you can set the public static variable externally before calling any of the other static methods. A constructor in a class with all static members is unnecessary.
Now with that being said, this design for accessing a database in Android is not going to scale very well. DBManager will only be able to have one client at any given time. A better approach would be to pass in the callback for any method that requires it and drop the static variable callback.
You may use this pattern
https://www.google.de/amp/s/www.geeksforgeeks.org/singleton-design-Patient tern/amp/
And then work with get instance.
But I would consider to implement the asyncTask without a return value if you are already using Callbacks already.
Try this link
https://de.m.wikibooks.org/wiki/Muster:_Java:_Singleton
I am getting a warning in my code that states:
This AsyncTask class should be static or leaks might occur (anonymous android.os.AsyncTask)
The complete warning is:
This AsyncTask class should be static or leaks might occur (anonymous android.os.AsyncTask)
A static field will leak contexts. Non-static inner classes have an implicit reference to their outer class. If that outer class is for example a Fragment or Activity, then this reference means that the long-running handler/loader/task will hold a reference to the activity which prevents it from getting garbage collected. Similarly, direct field references to activities and fragments from these longer running instances can cause leaks. ViewModel classes should never point to Views or non-application Contexts.
This is my code:
new AsyncTask<Void,Void,Void>(){
#Override
protected Void doInBackground(Void... params) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
return null;
}
}.execute();
How do I correct this?
How to use a static inner AsyncTask class
To prevent leaks, you can make the inner class static. The problem with that, though, is that you no longer have access to the Activity's UI views or member variables. You can pass in a reference to the Context but then you run the same risk of a memory leak. (Android can't garbage collect the Activity after it closes if the AsyncTask class has a strong reference to it.) The solution is to make a weak reference to the Activity (or whatever Context you need).
public class MyActivity extends AppCompatActivity {
int mSomeMemberVariable = 123;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// start the AsyncTask, passing the Activity context
// in to a custom constructor
new MyTask(this).execute();
}
private static class MyTask extends AsyncTask<Void, Void, String> {
private WeakReference<MyActivity> activityReference;
// only retain a weak reference to the activity
MyTask(MyActivity context) {
activityReference = new WeakReference<>(context);
}
#Override
protected String doInBackground(Void... params) {
// do some long running task...
return "task finished";
}
#Override
protected void onPostExecute(String result) {
// get a reference to the activity if it is still there
MyActivity activity = activityReference.get();
if (activity == null || activity.isFinishing()) return;
// modify the activity's UI
TextView textView = activity.findViewById(R.id.textview);
textView.setText(result);
// access Activity member variables
activity.mSomeMemberVariable = 321;
}
}
}
Notes
As far as I know, this type of memory leak danger has always been true, but I only started seeing the warning in Android Studio 3.0. A lot of the main AsyncTask tutorials out there still don't deal with it (see here, here, here, and here).
You would also follow a similar procedure if your AsyncTask were a top-level class. A static inner class is basically the same as a top-level class in Java.
If you don't need the Activity itself but still want the Context (for example, to display a Toast), you can pass in a reference to the app context. In this case the AsyncTask constructor would look like this:
private WeakReference<Application> appReference;
MyTask(Application context) {
appReference = new WeakReference<>(context);
}
There are some arguments out there for ignoring this warning and just using the non-static class. After all, the AsyncTask is intended to be very short lived (a couple seconds at the longest), and it will release its reference to the Activity when it finishes anyway. See this and this.
Excellent article: How to Leak a Context: Handlers & Inner Classes
Kotlin
In Kotlin just don't include the inner keyword for the inner class. This makes it static by default.
class MyActivity : AppCompatActivity() {
internal var mSomeMemberVariable = 123
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// start the AsyncTask, passing the Activity context
// in to a custom constructor
MyTask(this).execute()
}
private class MyTask
internal constructor(context: MyActivity) : AsyncTask<Void, Void, String>() {
private val activityReference: WeakReference<MyActivity> = WeakReference(context)
override fun doInBackground(vararg params: Void): String {
// do some long running task...
return "task finished"
}
override fun onPostExecute(result: String) {
// get a reference to the activity if it is still there
val activity = activityReference.get()
if (activity == null || activity.isFinishing) return
// modify the activity's UI
val textView = activity.findViewById(R.id.textview)
textView.setText(result)
// access Activity member variables
activity.mSomeMemberVariable = 321
}
}
}
Non-static inner classes holds a reference to the containing class. When you declare AsyncTask as an inner class, it might live longer than the containing Activity class. This is because of the implicit reference to the containing class. This will prevent the activity from being garbage collected, hence the memory leak.
To solve your problem, either use static nested class instead of anonymous, local, and inner class or use top-level class.
This AsyncTask class should be static or leaks might occur because
When Activity is destroyed, AsyncTask (both static or non-static) still running
If inner class is non-static (AsyncTask) class, it will have reference to the outer class (Activity).
If a object has no references point to it, Garbage Collected will release it. If a object is unused and Garbage Collected can not release it => leak memory
=> If AsyncTask is non-static, Activity won't release event it is destroyed => leak
Solution for update UI after make AsyncTask as static class without leak
1) Use WeakReference like #Suragch answer
2) Send and remove Activity reference to (from) AsyncTask
public class NoLeakAsyncTaskActivity extends AppCompatActivity {
private ExampleAsyncTask asyncTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
// START AsyncTask
asyncTask = new ExampleAsyncTask();
asyncTask.setListener(new ExampleAsyncTask.ExampleAsyncTaskListener() {
#Override
public void onExampleAsyncTaskFinished(Integer value) {
// update UI in Activity here
}
});
asyncTask.execute();
}
#Override
protected void onDestroy() {
asyncTask.setListener(null); // PREVENT LEAK AFTER ACTIVITY DESTROYED
super.onDestroy();
}
static class ExampleAsyncTask extends AsyncTask<Void, Void, Integer> {
private ExampleAsyncTaskListener listener;
#Override
protected Integer doInBackground(Void... voids) {
...
return null;
}
#Override
protected void onPostExecute(Integer value) {
super.onPostExecute(value);
if (listener != null) {
listener.onExampleAsyncTaskFinished(value);
}
}
public void setListener(ExampleAsyncTaskListener listener) {
this.listener = listener;
}
public interface ExampleAsyncTaskListener {
void onExampleAsyncTaskFinished(Integer value);
}
}
}
I am getting a warning in my code that states:
This AsyncTask class should be static or leaks might occur (anonymous android.os.AsyncTask)
The complete warning is:
This AsyncTask class should be static or leaks might occur (anonymous android.os.AsyncTask)
A static field will leak contexts. Non-static inner classes have an implicit reference to their outer class. If that outer class is for example a Fragment or Activity, then this reference means that the long-running handler/loader/task will hold a reference to the activity which prevents it from getting garbage collected. Similarly, direct field references to activities and fragments from these longer running instances can cause leaks. ViewModel classes should never point to Views or non-application Contexts.
This is my code:
new AsyncTask<Void,Void,Void>(){
#Override
protected Void doInBackground(Void... params) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
return null;
}
}.execute();
How do I correct this?
How to use a static inner AsyncTask class
To prevent leaks, you can make the inner class static. The problem with that, though, is that you no longer have access to the Activity's UI views or member variables. You can pass in a reference to the Context but then you run the same risk of a memory leak. (Android can't garbage collect the Activity after it closes if the AsyncTask class has a strong reference to it.) The solution is to make a weak reference to the Activity (or whatever Context you need).
public class MyActivity extends AppCompatActivity {
int mSomeMemberVariable = 123;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// start the AsyncTask, passing the Activity context
// in to a custom constructor
new MyTask(this).execute();
}
private static class MyTask extends AsyncTask<Void, Void, String> {
private WeakReference<MyActivity> activityReference;
// only retain a weak reference to the activity
MyTask(MyActivity context) {
activityReference = new WeakReference<>(context);
}
#Override
protected String doInBackground(Void... params) {
// do some long running task...
return "task finished";
}
#Override
protected void onPostExecute(String result) {
// get a reference to the activity if it is still there
MyActivity activity = activityReference.get();
if (activity == null || activity.isFinishing()) return;
// modify the activity's UI
TextView textView = activity.findViewById(R.id.textview);
textView.setText(result);
// access Activity member variables
activity.mSomeMemberVariable = 321;
}
}
}
Notes
As far as I know, this type of memory leak danger has always been true, but I only started seeing the warning in Android Studio 3.0. A lot of the main AsyncTask tutorials out there still don't deal with it (see here, here, here, and here).
You would also follow a similar procedure if your AsyncTask were a top-level class. A static inner class is basically the same as a top-level class in Java.
If you don't need the Activity itself but still want the Context (for example, to display a Toast), you can pass in a reference to the app context. In this case the AsyncTask constructor would look like this:
private WeakReference<Application> appReference;
MyTask(Application context) {
appReference = new WeakReference<>(context);
}
There are some arguments out there for ignoring this warning and just using the non-static class. After all, the AsyncTask is intended to be very short lived (a couple seconds at the longest), and it will release its reference to the Activity when it finishes anyway. See this and this.
Excellent article: How to Leak a Context: Handlers & Inner Classes
Kotlin
In Kotlin just don't include the inner keyword for the inner class. This makes it static by default.
class MyActivity : AppCompatActivity() {
internal var mSomeMemberVariable = 123
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// start the AsyncTask, passing the Activity context
// in to a custom constructor
MyTask(this).execute()
}
private class MyTask
internal constructor(context: MyActivity) : AsyncTask<Void, Void, String>() {
private val activityReference: WeakReference<MyActivity> = WeakReference(context)
override fun doInBackground(vararg params: Void): String {
// do some long running task...
return "task finished"
}
override fun onPostExecute(result: String) {
// get a reference to the activity if it is still there
val activity = activityReference.get()
if (activity == null || activity.isFinishing) return
// modify the activity's UI
val textView = activity.findViewById(R.id.textview)
textView.setText(result)
// access Activity member variables
activity.mSomeMemberVariable = 321
}
}
}
Non-static inner classes holds a reference to the containing class. When you declare AsyncTask as an inner class, it might live longer than the containing Activity class. This is because of the implicit reference to the containing class. This will prevent the activity from being garbage collected, hence the memory leak.
To solve your problem, either use static nested class instead of anonymous, local, and inner class or use top-level class.
This AsyncTask class should be static or leaks might occur because
When Activity is destroyed, AsyncTask (both static or non-static) still running
If inner class is non-static (AsyncTask) class, it will have reference to the outer class (Activity).
If a object has no references point to it, Garbage Collected will release it. If a object is unused and Garbage Collected can not release it => leak memory
=> If AsyncTask is non-static, Activity won't release event it is destroyed => leak
Solution for update UI after make AsyncTask as static class without leak
1) Use WeakReference like #Suragch answer
2) Send and remove Activity reference to (from) AsyncTask
public class NoLeakAsyncTaskActivity extends AppCompatActivity {
private ExampleAsyncTask asyncTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
// START AsyncTask
asyncTask = new ExampleAsyncTask();
asyncTask.setListener(new ExampleAsyncTask.ExampleAsyncTaskListener() {
#Override
public void onExampleAsyncTaskFinished(Integer value) {
// update UI in Activity here
}
});
asyncTask.execute();
}
#Override
protected void onDestroy() {
asyncTask.setListener(null); // PREVENT LEAK AFTER ACTIVITY DESTROYED
super.onDestroy();
}
static class ExampleAsyncTask extends AsyncTask<Void, Void, Integer> {
private ExampleAsyncTaskListener listener;
#Override
protected Integer doInBackground(Void... voids) {
...
return null;
}
#Override
protected void onPostExecute(Integer value) {
super.onPostExecute(value);
if (listener != null) {
listener.onExampleAsyncTaskFinished(value);
}
}
public void setListener(ExampleAsyncTaskListener listener) {
this.listener = listener;
}
public interface ExampleAsyncTaskListener {
void onExampleAsyncTaskFinished(Integer value);
}
}
}
im trying to remove values from an arrayList im my android app, but they keep re-appearing.
My arrayList is in a separate class,
in my Main Activty I create an instance of that class and remove a value from the array.
I exit the Main Activity and return the value re-appears.
My Question is how can I can some kind of static instance of the array class???
//ArrayClass
public class ArrayClass {
public final static ArrayList<String> words = new ArrayList<String>();
public ArrayClass() {
words.add("WORD");
words.add("WORD");
words.add("WORD");
}
//Main Class
ArrayClass wordc = new ArrayClass();
#Override
protected void onCreate(Bundle savedInstanceState) {
wordc.removeWord(0);
}
Orest is correct you do want a singleton pattern, but remember when you access the class's methods you always need to use the getInstance() method.
For example a method within the Class:
public String getWord(index i) {
.......
}
Should be called statically as follows
ArrayClass.getInstance().getWord(i);
NOT like this
wordc.getWord(i);
This guarantees that there is one and only one instance (thus the singleton)
I might be confused on what you are doing but to access the static Array you don't want to create an instance of the class. Everytime you do that you are running the constructor which, in the example code, populates your static Array each time with 3 values.
I don't see exactly what you are trying to accomplish so maybe you could explain that a little better but I'm guessing this really isn't what you want your constructor doing. I think you want to access the Array itself statically
//Main Class
ArrayClass wordc = new ArrayClass();
#Override
protected void onCreate(Bundle savedInstanceState) {
wordc.removeWord(0); //don't need this
ArrayClass.words.remove(0); // would remove the element at index 0
}
But this still wouldn't solve your problem. You need a method inside your ArrayClass class that adds items to your Array. Doing it in your constructor will add these items each time you create a new instance of your class.
If this doesn't answer your question then maybe you can explain your assignment a little better.
Have you tried the Singleton patter? You will have one static reference of ArrayClass and it's internal state won't be violated by activity lifecycle.
public class ArrayClass {
private static ArrayClass instance;
public static ArrayClass getInstance() {
if(instance == null) instance = new ArrayClass();
return instance;
}
//...rest goes as is.