It is throwing an error:
Caused by: java.lang.IllegalArgumentException: You must call this method on the main thread
Code:
Class CacheClearAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
Glide.get(getActivity()).clearDiskCache();
Glide.get(getActivity()).clearMemory();
return null;
}
#Override
protected void onPostExecute (Void result)
{
//Toast.makeText(getActivity(), "Cache cleared", Toast.LENGTH_LONG).show();
}
}
Setting preference on click event:
clearCacheBtnPref=findPreference(getResources().getString(R.string.pref_btn_clear_cache_key));
clearCacheBtnPref.setOnPreferenceClickListener(new
Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
new CacheClearAsyncTask().execute();
return true;
}
});
This can not be called in main thread as it is also throws errors and also it does not let me use asynctask.
Glide.get(getActivity()).clearDiskCache();
Glide.get(getActivity()).clearMemory();
clearDiskCache() must be called from background thread while clearMemory() from main thread so:
class CacheClearAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
Glide.get(getActivity()).clearDiskCache();
return null;
}
#Override
protected void onPostExecute (Void result) {
Glide.get(getActivity()).clearMemory();
}
}
I don't know your use case or app flow. But doInBackground is specifically used to do operations in background thread than Main UI thread.
Now if you need to do changes corresponding to Main UI thread in doInBackground , then do as following
#Override
protected Void doInBackground(Void... params) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
Glide.get(getActivity()).clearDiskCache();
Glide.get(getActivity()).clearMemory();
}
});
return null;
}
For more examples on runOnUiThread refer this
Try this
Both method works in different thread.
clearDiskCache() must be called on a background thread.
clearMemory() must be called on the main thread.
You can't call both at once on the same thread.
void clearGlideCache()
{
new Thread()
{
#Override
public void run()
{
Glide.get(DemoActivity.this).clearDiskCache();
}
}.start();
Glide.get(DemoActivity.this).clearMemory();
}
Related
I would need some help to figure out how to return a doInBackground() value in AsyncTask which code is an interface. Here is an example
private class MyAsyncTask extends AsyncTask<Void, Void, Boolean> {
public MyAsyncTask() {
super();
// do stuff
}
#Override
protected Boolean doInBackground(Void... void) {
checkIfContentAvailable(new interfaceMediaAvailableToDownload() {
#Override
public void onComplete(boolean resutl) {
return result; //This must be doInBackground return value, not onSuccess which is Void
}
#Override
public void onInternetError() {
return false; //This must be doInBackground return value, not onSuccess which is Void
}
};
}
#Override
protected void onPostExecute(Boolean result) {
if (result){
//Do stuff
}else{
//Do stuff
}
}
}
Obviously, this above code can't work because I don't know how to return onSuccess() value to doInBackground().
I hope this is clear enough....
EDIT
Okay my bad, I thought it would have been more readable to hide MyInterface usage, but I realize through your answers it is not. So I completed the code to add more details.
Any idea please?
Thank you in advance.
Create the object of the Mynterface in the place where you execute the AsyncTask.
Create a object reference of the MyInterface inside the AsyncTask ans set your interface object.
Then call the onSuccess method like below
`
private class MyAsyncTask extends AsyncTask<Void, Void, Boolean> {
MyInteface myInterface;
setMyInterface(MyInterface interface){this.myInterface = interface;}
public MyAsyncTask() {
super();
// do stuff
}
#Override
protected Boolean doInBackground(Void... void) {
this.myInterface.onSuccess(); // or call on failure if failure happened
}
#Override
protected void onPostExecute(Boolean result) {
//Do stuff with result
}
}
`
Use it like ...
MyAsyncTask async = new MyAsyncTask();
async.setMyInterface(this);
async.execute();
Implement the interface in the place where your are executing.
This how you can do it.
I have a method which has a async task and it is called from several different services and those services runs periodically . I want to make sure when one task is on going , no other thing can call it unless the task is finished.
public class Helper {
public static void doSomethingAsync() {
new AsyncTask<String, Void, Integer>() {
#Override
protected void onPreExecute() {
}
#Override
protected Integer doInBackground(String... strings) {
//doing something
}
#Override
protected void onPostExecute(Integer resultCode) {
}
}.execute();
}
public static void someOtherMethod(){
}
}
AsyncTask.getStatus() will give the status of the task, i.e. whether finished or not.
Declare a member variable
private static AsyncTask<String, Void, Integer> mTask;
Modify your method as,
public static void doSomethingAsync() {
if(null != mTask && mTask.getStatus() != AsyncTask.Status.FINISHED){
return; //Returning as the current task execution is not finished yet.
}
mTask = new AsyncTask<String, Void, Integer>() {
#Override
protected void onPreExecute() {
}
#Override
protected Integer doInBackground(String... strings) {
//doing something
}
#Override
protected void onPostExecute(Integer resultCode) {
}
};
mTask.execute();
}
You can try this by making your "doSomethingAsync()" as synchronized method.
public synchronized static void doSomethingAsync() {
new AsyncTask<String, Void, Integer>() {
#Override
protected void onPreExecute() {
}
#Override
protected Integer doInBackground(String... strings) {
//doing something
}
#Override
protected void onPostExecute(Integer resultCode) {
}
}.execute();
}
Note:
static synchronized method will lock the class instead of the object, and it will lock the class because the keyword static means: "class instead of instance". The keyword synchronized means that only one thread can access the method at a time.
And together they mean: "Only one can access class at one time".
Make sure all your services has access to same Mutex which can be accesses throughout your application.
Now before accessing the Async Task, do as follows
public class Mutex {
public void acquire() throws InterruptedException { }
public void release() { }
public boolean attempt(long msec) throws InterruptedException { }
}
Which then can be used as:
try {
mutex.acquire();
try {
// do something
} finally {
mutex.release();
}
} catch(InterruptedException ie) {
// ...
}
Check out more details over here
In Android we have Semaphore. For which the following will be the steps
java.util.concurrent.Semaphore semaphore=new Semaphore(1);
boolean isAvailable = semaphore.tryAcquire();
if(isAvailable){
// Access AsyncTask
}
Once all actions are done, till onPostExecute
semaphore.release();
Try using an IntentService instead as this supports queuing and runs in a background thread
You should refer Synchronization concept, it will help u.
Link
I am trying to work with Asynctask, but everytime I'm getting its status, it always returns running.
What is wrong in my code?
This is how I load my asynctask:
LongOperation LongOperation = new LongOperation(finalLink[0], download_data);
LongOperation.execute();
Toast.makeText(getApplicationContext(), LongOperation.getStatus().toString(), Toast.LENGTH_SHORT).show();
This is my asynctask:
private class LongOperation extends AsyncTask<Void, Void, Void> {
public Download_data download_data;
public String link;
public boolean loading;
public LongOperation(String link, Download_data download_data){
this.link = link;
this.download_data = download_data;
}
#Override
protected Void doInBackground(Void... params) {
download_data.download_data_from_link(link);
return null;
}
protected void onPostExecute() {
finish();
}
#Override
protected void onPreExecute() {
Toast.makeText(getApplicationContext(),"Executed.", Toast.LENGTH_LONG).show();
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
Because you are checking status right after executing it:
LongOperation.execute();
Toast.makeText(getApplicationContext(), LongOperation.getStatus().toString(), Toast.LENGTH_SHORT).show();
AsyncTask runs on background thread. So right after calling execute() controls moves to display Toast. And by that time, task is still running.
You will receive finished status in onPreExecute of AsyncTask.
#Override
protected void onPostExecute(Void mVoid) {
Toast.makeText(getApplicationContext(), this.getStatus().toString(), Toast.LENGTH_SHORT).show();
finish();
}
In case you are confused about threads, do read this: Java Multithreading
The correct signature of onPostExecute() is really;
protected void onPostExecute (Result result)
Since you're not overriding the one in AsyncTask but defining another overload, it (and in its turn finish() is never called).
Fix the signature and it should complete as intended.
I have an IME service class and a long operation method in it. I want to run the LongOperation task in a asyncTask class that is in the IME Service class.
public class Myimeservice extends InputMethodService
implements KeyboardView.OnKeyboardActionListene {
//...
//some code here....
//...
public void setDictionary(){
//....
}
private class LongOperation extends AsyncTask<String, Void, String> {
private Myimeservice parent;
public LongOperation(Myimeservice pim){
parent = pim;
}
#Override
protected String doInBackground(String... params) {
Myimeservice tmp = new Myimeservice();
tmp.setDictionary();
return "Executed";
}
#Override
protected void onPostExecute(String result) {
//app.hideLoading();
}
#Override
protected void onPreExecute() {
//app.showLoading();
}
#Override
protected void onProgressUpdate(Void... values) {}
}
When i run it, the application forced to close. please help me.
I think the error is somewhere in your public void setDictionary() method.
I assume that you are manipulating a variable that is bound to the UIThread/MainThread, the application will crash since doInBackground is on another Thread.
Instead make the setDictionary() method return the dictionary and return it instead of "Executed" in doInBackground().
This will call the onPostExecute(Object result) which is run on UIThread/MainThread.
Something like this:
private class LongOperation extends AsyncTask<String, Void, Dictionary> {
#Override
protected Dictionary doInBackground(String... params) {
Myimeservice tmp = new Myimeservice();
Dictionary dict = tmp.setDictionary();
return dict;
}
#Override
protected void onPostExecute(Dictionary result) {
//do what ever you meant to do with it;
}
}
If you are not expecting any result from it you can just do:
AsyncTask.execute(new Runnable() {
#Override
public void run() {
tmp.setDictionary();
}
});
I use the Runnable instead of AsyncTask and the problem solved.
final Runnable r = new Runnable(){
public void run(){
setDictionary();
}
};
this code is in onCreate() method of service.
Tanks a lot Tristan Richard.
I am using AsyncTask and there are threads running inside the doInBackground method, isn't the purpose of AsyncTask is to let all the code finish executing inside the doInBackground and THEN go to PostExecute? Then why is it that some of my threads are running after the code block in PostExecution has started?
What should I do to solve this problem?
public class myActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
...
}
#Override
public void onClick(View view) {
new myTask().execute();
}
class myTask extends AsyncTask<Void, Void, Void> {
Boolean success;
#Override
protected void onPreExecute() {
success = true
}
#Override
protected Void doInBackground(Void... params) {
try {
Callback callback = new Callback() {
public void successCallback(String name, Object response) {
}
public void errorCallback(String name, error) {
success = false;}
};
} catch (Exception e) {
success = false;
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
if (success == true){
// do something
}
}
}
}
It is inside the error callback, that I want the success field to change to false. But the error callback runs after the postExecute method.
I think that you misunderstand the threading model.
AsyncTask does indeed execute doInBackground first, on a background thread, and then executes onPostExecute on the foreground thread, passing it the result from doInBackground.
However, from the wording of your question, it sounds like you are starting new threads from doInBackground. I'm sure that doInBackground does indeed complete before onPostExecute starts, but there is nothing that would cause the AsyncTask to wait for your additional threads to complete as well.
Edit:
It looks like you could skip the AayncTask altogether. The reason that you have callbacks is probably that method is already asynchronous
But note that you are only creating the callback, never using it. Perhaps you just left that part out?