Problems in Calling AsyncTask from IntentService - android

I have created IntentService class and performing asyncTask but getting exception when onPreExecute() is called at this code line pDialog.show();
AsyncHandlerService Class ---
public class AsyncHandlerService extends IntentService{
ProgressDialog pDialog;
HttpPost post;
HttpResponse response;
Context ctx;
public AsyncHandlerService() {
super("AsyncHandlerService");
ctx = this;
}
#Override
protected void onHandleIntent(Intent intent) {
new LoadDeviceInfo().execute();
}
class LoadDeviceInfo extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(ctx);
pDialog.setMessage("Updating device info...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show(); //Exception here..
}
protected String doInBackground(String... args) {
}
protected void onPostExecute(String file_url) {
pDialog.dismiss();
}
UPDATE:
I am calling the IntentService in the broadcast receiver that has the intent filter of android.intent.action.PACKAGE_REPLACED defined in android manifest. The code ---
public class OnUpgradeBroadcastReceiver extends BroadcastReceiver {
Context activity;
#Override
public void onReceive(final Context context, final Intent intent) {
activity = context;
Intent msgIntent = new Intent(activity, AsyncHandlerService.class);
activity.startService(msgIntent);
}
}
Error Log:
com.testapp.main fatal error : Unable to add window --
token null is not for an application
android.view.WindowManager$BadTokenException: Unable to add window --
token null is not for an application
at android.view.ViewRootImpl.setView(ViewRootImpl.java:588)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:326)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:224)
at android.view.WindowManagerImpl$CompatModeWrapper.
addView(WindowManagerImpl.java:149)
at android.app.Dialog.show(Dialog.java:277)
at com.testapp.main.AsyncHandlerService$LoadDeviceInfo.
onPreExecute(AsyncHandlerService.java:62)
at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:586)
at android.os.AsyncTask.execute(AsyncTask.java:534)

First, IntentService already uses a background thread. You do not need another background thread. Do the work that needs to be done in the background in onHandleIntent().
Second, a Service cannot display a Dialog. Instead, let the UI layer of your app know that the work was done via a message on an event bus (e.g., LocalBroadcastManager, greenrobot's EventBus, Square's Otto). If the UI layer does not handle the event, your service can raise a Notification or otherwise let the user know about the work that was done, if that is needed.

Service isn't a UI thread.
Since you try to display a ProgressDialog from a service context, it can't be completed.
Try this solution:
https://stackoverflow.com/a/4369755/1405268

If for whatever reason you really really really want to use an AsyncTask (e.g. you've set up your framework to use AsyncTask to make calls to some web api) you can always use wait/notify such as:
public class GetCacheIntentService extends DebuggableIntentService implements ApiAsyncTask.Callback {
private static final String ACTION_GET_CACHE = "action.GET_CACHE";
private static final String EXTRA_INT_START = "extras.START";
private static final String EXTRA_INT_LIMIT = "extras.LIMIT";
private static final int API_GET_CACHE = 0;
private final Object mApiCallLock = new Object();
private GetCacheResponse getCacheResponse;
public GetCacheIntentService() {
super("GetCacheIntentService");
setIntentRedelivery(true);
}
public static void startServiceActionGetCache(Context context, int start, int limit) {
Intent intent = new Intent(context, GetCacheIntentService.class);
intent.setAction(ACTION_GET_CACHE);
intent.putExtra(EXTRA_INT_START, start);
intent.putExtra(EXTRA_INT_LIMIT, limit);
context.startService(intent);
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent == null) {
return;
}
String action = intent.getAction();
if (ACTION_GET_CACHE.equals(action)) {
int start = intent.getIntExtra(EXTRA_INT_START, 0);
int limit = intent.getIntExtra(EXTRA_INT_LIMIT, 100);
getCache(start, limit);
}
}
private void getCache(int start, int limit) {
GetCacheTask task = new GetCacheTask(this, API_GET_CACHE);
task.setStart(start);
task.setLimit(limit);
task.execute();
synchronized (mApiCallLock) {
try {
mApiCallLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
processResponse(mGetCacheResponse);
}
public void processResponse(GetCacheResponse response) {
// do something
}
#Override
public void onRequestFailed(int id, ApiResponse apiResponse) {
synchronized (mApiCallLock) {
switch (id) {
case API_GET_CACHE:
break;
}
mApiCallLock.notify();
}
}
#Override
public void onRequestSuccess(int id, ApiResponse response) {
synchronized (mApiCallLock) {
switch (id) {
case API_GET_CACHE:
mGetCacheResponse = (GetCacheResponse) response;
break;
}
mApiCallLock.notify();
}
}
}
this is quite ugly though :(

Not a good practise to call Asynctask from an Intent service. If you need to do spin other thread from IntentService consider using Executor.
ExecutorService es = Executors.newFixedThreadPool(5);
es.execute(new Runnable() {
#Override
public void run() {
}
});
es.execute(new Runnable() {
#Override
public void run() {
}
});
es.shutdown();
es.awaitTermination(1, TimeUnit.HOURS);

It is not a good practice to use AsyncTask inside IntentService sub-classes or even JobIntentService sub-classes. In the case of JobIntentServices it causes crash too.

Related

How to show AlertDialog in AsyncTask without leaking Context?

I have the below code working fine to find and read a record in a Room database via an id. Android Studio required adding a try/catch block which I've included below.
Two questions:
Can I leave the if{} section blank in onPostExecute() if there is no Exception?
How do I show an AlertDialog here without leaking contect and without using a hack via WeakReference?
// AsyncTask for reading an existing CardView from the database.
private static class ReadAsyncTask extends AsyncTask<Integer, Void, Quickcard> {
private QuickcardDao asyncTaskDao;
Exception e;
ReadAsyncTask(QuickcardDao dao) {
asyncTaskDao = dao;
}
#Override
public Quickcard doInBackground(final Integer... params) {
Quickcard result;
try {
result = asyncTaskDao.readCardForUpdate(params[0]);
} catch (Exception e) {
this.e = e;
result = null;
}
return result;
}
#Override
protected void onPostExecute(Quickcard quickcard) {
if (e == null) {
// *** Okay to leave this blank? If not, what should go here?
}
else {
// *** How do I show an AlertDialog here with leaking context?
}
}
}
You cannot use a view object while using a thread that operates in background.. U must implement the dialog in the UI thread. When you are implementing the the asynchronous class, in that method you should show the alert dialog. Hope this helps..
This is what I will do to prevent leaks from happening.
private static class showDialog extends AsyncTask<String, String, String> {
private WeakReference<MainActivity> mainActivityWeakReference;
showDialog(MainActivity mainActivity){
this.mainActivityWeakReference = new WeakReference<>(mainActivity);
}
#Override
protected String doInBackground(String... params) {
//do your long long time consuming tasks here.
return "Done";
}
#Override
protected void onPostExecute(String result) {
// execution of result of Long time consuming operation
//Just building an alert dialog to show.
if (mainActivityWeakReference.get() != null){
final MainActivity activity = mainActivityWeakReference.get();
new AlertDialog.Builder(activity).setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
Toast.makeText(activity, "Yes was clicked", Toast.LENGTH_SHORT).show();
}
}).show();
}
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(String... text) {
}
}

async task does not work properly

Hi i have a function to get users from website database
my function
private void get_users() {
try {
url = "my address";
dbGetData3 = new DbGetData();
new Thread(new Runnable() {
public void run() {
data = dbGetData3.getDataFromDB(url);
runOnUiThread(new Runnable() {
#Override
public void run() {
userha = parseJSON3(data);
}
});
}
}).start();
Toast.makeText(context, "please wait ", Toast.LENGTH_LONG)
.show();
} catch (Exception e) {
toast(9);
}
Now i want add a loading progress bar while fetch data finished.
I use AsyncTask like this:
private class LongOperation extends AsyncTask<String, Void, String> {
protected void onPreExecute() {
progressDialog = new ProgressDialog(Login.this);
progressDialog.setTitle("Processing...");
progressDialog.setMessage("Please wait...");
progressDialog.setCancelable(true);
progressDialog.show();
}
protected String doInBackground(String... params) {
try {
get_users();
} catch (Exception e) {
}
return null;
}
protected void onPostExecute(String result) {
progressDialog.dismiss();
}
}
and i use this code for excute
mytask = new LongOperation();
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB)
mytask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
mytask.execute();
imageView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
onCreate(savedInstanceState);
}
});
but progress dialog dose not show for me (get user worked)
i change my code like this:
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB){
mytask.onPreExecute();
mytask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
else
{
mytask.onPreExecute();
mytask.execute();
}
then my progress dialog allways show
i test other code in stackoverflow like
AsyncTask doInBackground does not run
AsyncTask called from Handler will not execute doInBackground
Android SDK AsyncTask doInBackground not running (subclass)
but that not work for me
please help me tankyou
Consdier using a LoaderManager and an AsyncTaskLoader for this sort of stuff.
AsyncTasks are a pain in the ass as because you have to manage their lifecycle with screen-rotations etc. With a LoaderManager all of that is in the past.
Below is an example of a loader which loads a list of "items".
public class ItemsLoader extends AsyncTaskLoader<List<Item>> {
private static final String TAG = "ItemsLoader";
private List<Item> mItems;
private ItemUpdatedReceiver mObserver;
private int mSomeParam;
public static class ItemUpdatedReceiver extends BroadcastReceiver {
private static final String TAG = "ItemLoader";
final ItemsLoader mLoader;
public ItemUpdatedReceiver(ItemsLoader mLoader) {
this.mLoader = mLoader;
// listen for changes to the account we're using
IntentFilter filter = new IntentFilter(GlobalConstants.ACTION_ITEMS_UPDATED);
LocalBroadcastManager.getInstance(mLoader.getContext()).registerReceiver(this, filter);
}
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (GlobalConstants.ACTION_ITEMS_UPDATED.equals(action)) {
mLoader.onContentChanged();
}
}
}
public void setSomeParam(int someParam){
mSomeParam = someParam;
onContentChanged();
}
public ItemsLoader(Context context, int someParam) {
super(context);
mSomeParam = someParam;
onContentChanged();
}
#Override
public List<Item> loadInBackground() {
// do whatever you need to do here
ArrayList<Item> Items = new ArrayList<>();
return Items;
}
/**
* Called when there is new data to deliever to the client.
*
* #param data
*/
#Override
public void deliverResult(List<Item> data) {
if (isReset()) {
// an async query came in while the loader is stopped, we don't need the result
//release resources if needed
onReleaseResources(data);
}
List<Item> oldItems = mItems;
mItems = data;
if (isStarted()) {
// If the Loader is currently started, we can immediately
// deliver its results.
super.deliverResult(mItems);
}
// At this point we can release the resources associated with
// 'oldApps' if needed; now that the new result is delivered we
// know that it is no longer in use.
if (oldItems != null) {
onReleaseResources(oldItems);
}
}
#Override
protected void onStartLoading() {
super.onStartLoading();
if (mItems != null) {
// If we currently have a result available, deliver it
// immediately.
deliverResult(mItems);
}
// start listening for changes
if (mObserver == null) {
mObserver = new ItemUpdatedReceiver(this);
}
if (takeContentChanged() || mItems == null) {
// If the data has changed since the last time it was loaded
// or is not currently available, start a load.
forceLoad();
}
}
/**
* Handles a request to stop the Loader.
*/
#Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
/**
* Handles a request to cancel a load.
*/
#Override
public void onCanceled(List<Item> items) {
super.onCanceled(items);
// At this point we can release the resources associated with 'profile'
// if needed.
onReleaseResources(items);
}
#Override
protected void onReset() {
super.onReset();
// Ensure the laoder is stopped
onStopLoading();
// At this point we can release the resources if needed.
if (mItems != null) {
onReleaseResources(mItems);
mItems = null;
}
// Stop monitoring for changes.
if (mObserver != null) {
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mObserver);
mObserver = null;
}
}
/**
* Helper function to take care of releasing resources associated
* with an actively loaded data set.
*/
private void onReleaseResources(List<Item> data) {
// For a simple List<> there is nothing to do. For something
// like a Cursor, we would close it here.
}
}
To use this class, in your activity you must extend LoaderManager.LoaderCallbacks> and override the methods:
public Loader<List<Item>> onCreateLoader(int id, Bundle args) {
// This is called when a new Loader needs to be created. This
// sample only has one Loader, so we don't care about the ID.
// start the loading dialog here
return new ItemsLoader(context);
}
public void onLoadFinished(Loader<List<Item>> loader, List<Item>data) {
// do something with your data, hide the progress dialog
}
public void onLoaderReset(Loader<Cursor> loader) {
// set the old data to null
}
To actually start loading:
getLoaderManager().initLoader(LOADER_ID, null, this);

Pass different type as activity

I have several activities that need to perform HTTP requests (send a JSON request a get another JSON object back).
My idea was to share one AsyncTask for all these requests. I am passing the Activity as a parameter so that I can call method once the execution of the request is finished.
I would like to pass one more parameter to my AsyncTask that would be the class of my Activity (MainActivity.class, SecondActivity.class) and then use that information to cast the Activity to the correct type and then later call on the method (would be the same method name for all activities).
I could also create an interface with my call back method, but I am not sure if I that would work neither.
Could this work or is my approach wrong here ?
Thanks for your feed-back.
My code:
public class HTTPReq extends AsyncTask {
private MainActivity callerActivity;
#Override
protected String doInBackground(Object... params) {
String data = (String) params[0];
String cookie = (String) params[1];
callerActivity = (MainActivity) params[2];
...
}
#Override
protected void onPostExecute(String result) {
callerActivity.ProcessHTTPReqAnswer(result);
super.onPostExecute(result);
}
}
Aswins answer isn't terrible but it's still not the most efficient way.
Declare an Interface that has a method for callback. Pass an instance of that interface to your asynctask then have the async task invoke it if its there as per my examples below
Interface:
public interface IMyCallbackInterface {
void onCallback(String result);
}
Async Task:
public MyAsyncTask extends AsyncTask<..., String> {
private IMyCallbackInterface mCallback;
public MyAsyncTask(..., IMyCallbackInterface callback) {
mCallback = callback;
}
protected String doInBackground(Object... params) {
....
}
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (mCallback != null) {
mCallback.onCallback(result);
}
}
Activity:
public MyActivity extends Activity {
private void someMethod(){
new MyAsyncTask(..., new IMyCallbackInterface() {
public void onCallback(String result) {
//TODO use the result to do whatever i need
//I have access to my aactivity methods and member variables here
}
}.execute();
}
}
It is a wrong approach to do it like that. You should use BroadcastReceiver. Once a AsyncTask is done, sent the result out as a Broadcast. Each of the activity will be listen to the results they are interested in. This way no one needs to keep a reference to the activity which is dangerous.
Here is an example.
IntentFilter filter = new IntentFilter();
filter.addAction("result1");
LocalBroadcastManager.getInstance(getSupportActivity()).registerReceiver(new CustomBroadcastReceiver(), filter);
In the AsyncTask, do this
#Override
protected void onPostExecute(String result) {
Intent intent = new Intent("result1").putExtra(
"data", result);
LocalBroadcastManager.getInstance(getSupportActivity()).sendBroadcast(intent);
super.onPostExecute(result);
}
Back in the activity, do this
private class CustomBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if ("result1".equalsIgnoreCase(intent.getAction())) {
String result = bundle.getString("data");
// Process the result here.
}
}
}

multithreading UI : exceptionininitializererror and runtime exception android

I'm trying to make multithreading but I've got this stacktrace on few smartphones (SGS2) :
java.lang.ExceptionInInitializerError
at com.android.bordeaux.code.model.AnnouncersContainer.setLoudArrayFromJSON_online(AnnouncersContainer.java:68)
at com.android.bordeaux.code.SplashscreenActivity_Second$1.run(SplashscreenActivity_Second.java:55)
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:121)
at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
at android.os.AsyncTask.<clinit>(AsyncTask.java:152)
... 2 more
Here is my main activity (splashscreen) wich is making wait during few seconds in order to wait my asynctask finish:
public class SplashscreenActivity_Second extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.splashscreen_second);
// thread
Thread splashThread = new Thread()
{
#Override
public void run()
{
try
{
int waited = 0;
if (isInternetOn())
{
// Here I'm making my asynctask !!
AnnouncersContainer.setLoudArrayFromJSON_online(getApplicationContext());
while (waited < 5000)
{
sleep(50);
waited += 40;
}
}
else
{
AnnouncersContainer.setLoudArrayFromXML_local(getApplicationContext());
while(waited < 5000)
{
sleep(50);
waited += 60;
}
}
}
catch( InterruptedException e )
{
e.printStackTrace();
}
finally
{
Intent intent_to_tabhost = new Intent(SplashscreenActivity_Second.this, MyTabActivity.class);
startActivity(intent_to_tabhost);
finish();
}
}
};
splashThread.start();
}
}
Here is my asynctask :
public class DownloadAnnouncers extends AsyncTask<Void, Integer, Boolean>
{
public static Boolean loadFinished = false;
//JSON variables..
private static String url = null;
Context context;
public DownloadAnnouncers(Context context)
{
this.context = context;
}
#Override
protected void onPreExecute()
{
super.onPreExecute();
}
protected Boolean doInBackground(Void... params)
{
// fine retrieving all my JSON data in a global array..
}
#Override
protected void onPostExecute(Boolean downloadedArray)
{
super.onPostExecute(downloadedArray);
}
}
I know the problem is that I'm making multithreading in the UI but someone can tell me how to delete my looping thread and replacing it just with onPostExecute() method of my Asynctask ?? (it could be better to wait for asynctask finishes rather than making wait..)
Or may be help me to correct this bug with multithreading..
EDIT :
my asynctask :
public class DownloadAnnouncers extends AsyncTask<Void, Integer, Boolean>
{
public static Boolean loadFinished = false;
//JSON variables..
private static String url = null;
Context context;
public DownloadAnnouncers(Context context)
{
this.context = context;
}
#Override
protected void onPreExecute()
{
super.onPreExecute();
}
protected Boolean doInBackground(Void... params)
{
// fine retrieving all my JSON data in a global array..
}
#Override
protected void onPostExecute(Boolean downloadedArray)
{
super.onPostExecute(downloadedArray);
Intent intent_to_tabhost = new Intent(context, MyTabActivity.class);
intent_to_tabhost.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent_to_tabhost);
}
}
But now if I press cancel button I'm returning to my splashscreen activity.. and I cannot do ctx.finish() in onPostExecute method..
You can't create a Handler inside a Thread that has not called Looper.prepare(), just as your Error message says:
Can't create handler inside thread that has not called Looper.prepare()
The Handler is created within the AsyncTask, so it's not something you might see at first.
If you want to keep your code as it is you would fix it by moving the creation of the AsyncTask to outside your custom Thread.
However, there is no need for you to create the thread, you can just create your AsyncTask in the ui thread (It will run on it's own thread so it won't lock your phone while working), and perform any action you want after the task is complete in the onPostExecute-method.
class ExampleAsync extends AsyncTask<Void, Integer, Boolean>
{
public static Boolean loadFinished = false;
//JSON variables..
private static String url = null;
Context context;
public DownloadAnnouncers(Context context){
this.context = context;
}
protected Boolean doInBackground(Void... params){
// fine retrieving all my JSON data in a global array..
}
#Override
protected void onPostExecute(Boolean downloadedArray){
Intent intent_to_tabhost = new Intent(context, MyTabActivity.class);
startActivity(intent_to_tabhost);
}
}
And in your Activity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splashscreen_second);
AsyncTask myTask = new ExampleAsync(this);
myTask.execute();
}
Instead of waiting for the asyncTask , use the onPostExecute , which is called on the UI thread only after the task has finished.
You should also cancel the task if the activity was destroyed (for example if the user has pressed the back button while the splash screen is shown) .

How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class?

I have this two classes. My main Activity and the one that extends the AsyncTask, Now in my main Activity I need to get the result from the OnPostExecute() in the AsyncTask. How can I pass or get the result to my main Activity?
Here is the sample codes.
My main Activity.
public class MainActivity extends Activity{
AasyncTask asyncTask = new AasyncTask();
#Override
public void onCreate(Bundle aBundle) {
super.onCreate(aBundle);
//Calling the AsyncTask class to start to execute.
asyncTask.execute(a.targetServer);
//Creating a TextView.
TextView displayUI = asyncTask.dataDisplay;
displayUI = new TextView(this);
this.setContentView(tTextView);
}
}
This is the AsyncTask class
public class AasyncTask extends AsyncTask<String, Void, String> {
TextView dataDisplay; //store the data
String soapAction = "http://sample.com"; //SOAPAction header line.
String targetServer = "https://sampletargeturl.com"; //Target Server.
//SOAP Request.
String soapRequest = "<sample XML request>";
#Override
protected String doInBackground(String... string) {
String responseStorage = null; //storage of the response
try {
//Uses URL and HttpURLConnection for server connection.
URL targetURL = new URL(targetServer);
HttpURLConnection httpCon = (HttpURLConnection) targetURL.openConnection();
httpCon.setDoOutput(true);
httpCon.setDoInput(true);
httpCon.setUseCaches(false);
httpCon.setChunkedStreamingMode(0);
//properties of SOAPAction header
httpCon.addRequestProperty("SOAPAction", soapAction);
httpCon.addRequestProperty("Content-Type", "text/xml; charset=utf-8");
httpCon.addRequestProperty("Content-Length", "" + soapRequest.length());
httpCon.setRequestMethod(HttpPost.METHOD_NAME);
//sending request to the server.
OutputStream outputStream = httpCon.getOutputStream();
Writer writer = new OutputStreamWriter(outputStream);
writer.write(soapRequest);
writer.flush();
writer.close();
//getting the response from the server
InputStream inputStream = httpCon.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
ByteArrayBuffer byteArrayBuffer = new ByteArrayBuffer(50);
int intResponse = httpCon.getResponseCode();
while ((intResponse = bufferedReader.read()) != -1) {
byteArrayBuffer.append(intResponse);
}
responseStorage = new String(byteArrayBuffer.toByteArray());
} catch (Exception aException) {
responseStorage = aException.getMessage();
}
return responseStorage;
}
protected void onPostExecute(String result) {
aTextView.setText(result);
}
}
Easy:
Create interface class, where String output is optional, or can be whatever variables you want to return.
public interface AsyncResponse {
void processFinish(String output);
}
Go to your AsyncTask class, and declare interface AsyncResponse as a field :
public class MyAsyncTask extends AsyncTask<Void, Void, String> {
public AsyncResponse delegate = null;
#Override
protected void onPostExecute(String result) {
delegate.processFinish(result);
}
}
In your main Activity you need to implements interface AsyncResponse.
public class MainActivity implements AsyncResponse{
MyAsyncTask asyncTask =new MyAsyncTask();
#Override
public void onCreate(Bundle savedInstanceState) {
//this to set delegate/listener back to this class
asyncTask.delegate = this;
//execute the async task
asyncTask.execute();
}
//this override the implemented method from asyncTask
#Override
void processFinish(String output){
//Here you will receive the result fired from async class
//of onPostExecute(result) method.
}
}
UPDATE
I didn't know this is such a favourite to many of you. So here's the simple and convenience way to use interface.
still using same interface. FYI, you may combine this into AsyncTask class.
in AsyncTask class :
public class MyAsyncTask extends AsyncTask<Void, Void, String> {
// you may separate this or combined to caller class.
public interface AsyncResponse {
void processFinish(String output);
}
public AsyncResponse delegate = null;
public MyAsyncTask(AsyncResponse delegate){
this.delegate = delegate;
}
#Override
protected void onPostExecute(String result) {
delegate.processFinish(result);
}
}
do this in your Activity class
public class MainActivity extends Activity {
MyAsyncTask asyncTask = new MyAsyncTask(new AsyncResponse(){
#Override
void processFinish(String output){
//Here you will receive the result fired from async class
//of onPostExecute(result) method.
}
}).execute();
}
Or, implementing the interface on the Activity again
public class MainActivity extends Activity
implements AsyncResponse{
#Override
public void onCreate(Bundle savedInstanceState) {
//execute the async task
new MyAsyncTask(this).execute();
}
//this override the implemented method from AsyncResponse
#Override
void processFinish(String output){
//Here you will receive the result fired from async class
//of onPostExecute(result) method.
}
}
As you can see 2 solutions above, the first and third one, it needs to create method processFinish, the other one, the method is inside the caller parameter. The third is more neat because there is no nested anonymous class.
Tip: Change String output, String response, and String result to different matching types in order to get different objects.
There are a few options:
Nest the AsyncTask class within your Activity class. Assuming you don't use the same task in multiple activities, this is the easiest way. All your code stays the same, you just move the existing task class to be a nested class inside your activity's class.
public class MyActivity extends Activity {
// existing Activity code
...
private class MyAsyncTask extends AsyncTask<String, Void, String> {
// existing AsyncTask code
...
}
}
Create a custom constructor for your AsyncTask that takes a reference to your Activity. You would instantiate the task with something like new MyAsyncTask(this).execute(param1, param2).
public class MyAsyncTask extends AsyncTask<String, Void, String> {
private Activity activity;
public MyAsyncTask(Activity activity) {
this.activity = activity;
}
// existing AsyncTask code
...
}
You can try this code in your Main class.
That worked for me, but i have implemented methods in other way
try {
String receivedData = new AsyncTask().execute("http://yourdomain.com/yourscript.php").get();
}
catch (ExecutionException | InterruptedException ei) {
ei.printStackTrace();
}
I felt the below approach is very easy.
I have declared an interface for callback
public interface AsyncResponse {
void processFinish(Object output);
}
Then created asynchronous Task for responding all type of parallel requests
public class MyAsyncTask extends AsyncTask<Object, Object, Object> {
public AsyncResponse delegate = null;//Call back interface
public MyAsyncTask(AsyncResponse asyncResponse) {
delegate = asyncResponse;//Assigning call back interfacethrough constructor
}
#Override
protected Object doInBackground(Object... params) {
//My Background tasks are written here
return {resutl Object}
}
#Override
protected void onPostExecute(Object result) {
delegate.processFinish(result);
}
}
Then Called the asynchronous task when clicking a button in activity Class.
public class MainActivity extends Activity{
#Override
public void onCreate(Bundle savedInstanceState) {
Button mbtnPress = (Button) findViewById(R.id.btnPress);
mbtnPress.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MyAsyncTask asyncTask =new MyAsyncTask(new AsyncResponse() {
#Override
public void processFinish(Object output) {
Log.d("Response From Asynchronous task:", (String) output);
mbtnPress.setText((String) output);
}
});
asyncTask.execute(new Object[] { "Your request to aynchronous task class is giving here.." });
}
});
}
}
Thanks
This answer might be late but I would like to mention few things when your Activity dependent on AsyncTask. That would help you in prevent crashes and memory management. As already mentioned in above answers go with interface, we also say them callbacks. They will work as an informer, but never ever send strong reference of Activity or interface always use weak reference in those cases.
Please refer to below screenshot to findout how that can cause issues.
As you can see if we started AsyncTask with a strong reference then there is no guarantee that our Activity/Fragment will be alive till we get data, so it would be better to use WeakReference in those cases and that will also help in memory management as we will never hold the strong reference of our Activity then it will be eligible for garbage collection after its distortion.
Check below code snippet to find out how to use awesome WeakReference -
MyTaskInformer.java Interface which will work as an informer.
public interface MyTaskInformer {
void onTaskDone(String output);
}
MySmallAsyncTask.java AsyncTask to do long running task, which will use WeakReference.
public class MySmallAsyncTask extends AsyncTask<String, Void, String> {
// ***** Hold weak reference *****
private WeakReference<MyTaskInformer> mCallBack;
public MySmallAsyncTask(MyTaskInformer callback) {
this.mCallBack = new WeakReference<>(callback);
}
#Override
protected String doInBackground(String... params) {
// Here do whatever your task is like reading/writing file
// or read data from your server or any other heavy task
// Let us suppose here you get response, just return it
final String output = "Any out, mine is just demo output";
// Return it from here to post execute
return output;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
// Here you can't guarantee that Activity/Fragment is alive who started this AsyncTask
// Make sure your caller is active
final MyTaskInformer callBack = mCallBack.get();
if(callBack != null) {
callBack.onTaskDone(s);
}
}
}
MainActivity.java This class is used to start my AsyncTask implement interface on this class and override this mandatory method.
public class MainActivity extends Activity implements MyTaskInformer {
private TextView mMyTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMyTextView = (TextView) findViewById(R.id.tv_text_view);
// Start your AsyncTask and pass reference of MyTaskInformer in constructor
new MySmallAsyncTask(this).execute();
}
#Override
public void onTaskDone(String output) {
// Here you will receive output only if your Activity is alive.
// no need to add checks like if(!isFinishing())
mMyTextView.setText(output);
}
}
You can do it in a few lines, just override onPostExecute when you call your AsyncTask. Here is an example for you:
new AasyncTask()
{
#Override public void onPostExecute(String result)
{
// do whatever you want with result
}
}.execute(a.targetServer);
I hope it helped you, happy codding :)
in your Oncreate():
`
myTask.execute("url");
String result = "";
try {
result = myTask.get().toString();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}`
Why do people make it so hard.
This should be sufficient.
Do not implement the onPostExecute on the async task, rather implement it on the Activity:
public class MainActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState) {
//execute the async task
MyAsyncTask task = new MyAsyncTask(){
protected void onPostExecute(String result) {
//Do your thing
}
}
task.execute("Param");
}
}
You can call the get() method of AsyncTask (or the overloaded get(long, TimeUnit)). This method will block until the AsyncTask has completed its work, at which point it will return you the Result.
It would be wise to be doing other work between the creation/start of your async task and calling the get method, otherwise you aren't utilizing the async task very efficiently.
You can write your own listener. It's same as HelmiB's answer but looks more natural:
Create listener interface:
public interface myAsyncTaskCompletedListener {
void onMyAsynTaskCompleted(int responseCode, String result);
}
Then write your asynchronous task:
public class myAsyncTask extends AsyncTask<String, Void, String> {
private myAsyncTaskCompletedListener listener;
private int responseCode = 0;
public myAsyncTask() {
}
public myAsyncTask(myAsyncTaskCompletedListener listener, int responseCode) {
this.listener = listener;
this.responseCode = responseCode;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
String result;
String param = (params.length == 0) ? null : params[0];
if (param != null) {
// Do some background jobs, like httprequest...
return result;
}
return null;
}
#Override
protected void onPostExecute(String finalResult) {
super.onPostExecute(finalResult);
if (!isCancelled()) {
if (listener != null) {
listener.onMyAsynTaskCompleted(responseCode, finalResult);
}
}
}
}
Finally implement listener in activity:
public class MainActivity extends AppCompatActivity implements myAsyncTaskCompletedListener {
#Override
public void onMyAsynTaskCompleted(int responseCode, String result) {
switch (responseCode) {
case TASK_CODE_ONE:
// Do something for CODE_ONE
break;
case TASK_CODE_TWO:
// Do something for CODE_TWO
break;
default:
// Show some error code
}
}
And this is how you can call asyncTask:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Some other codes...
new myAsyncTask(this,TASK_CODE_ONE).execute("Data for background job");
// And some another codes...
}
Hi you can make something like this:
Create class which implements AsyncTask
// TASK
public class SomeClass extends AsyncTask<Void, Void, String>>
{
private OnTaskExecutionFinished _task_finished_event;
public interface OnTaskExecutionFinished
{
public void OnTaskFihishedEvent(String Reslut);
}
public void setOnTaskFinishedEvent(OnTaskExecutionFinished _event)
{
if(_event != null)
{
this._task_finished_event = _event;
}
}
#Override
protected void onPreExecute()
{
super.onPreExecute();
}
#Override
protected String doInBackground(Void... params)
{
// do your background task here ...
return "Done!";
}
#Override
protected void onPostExecute(String result)
{
super.onPostExecute(result);
if(this._task_finished_event != null)
{
this._task_finished_event.OnTaskFihishedEvent(result);
}
else
{
Log.d("SomeClass", "task_finished even is null");
}
}
}
Add in Main Activity
// MAIN ACTIVITY
public class MyActivity extends ListActivity
{
...
SomeClass _some_class = new SomeClass();
_someclass.setOnTaskFinishedEvent(new _some_class.OnTaskExecutionFinished()
{
#Override
public void OnTaskFihishedEvent(String result)
{
Toast.makeText(getApplicationContext(),
"Phony thread finished: " + result,
Toast.LENGTH_SHORT).show();
}
});
_some_class.execute();
...
}
Create a static member in your Activity class. Then assign the value during the onPostExecute
For example, if the result of your AsyncTask is a String, create a public static string in your Activity
public static String dataFromAsyncTask;
Then, in the onPostExecute of the AsyncTask, simply make a static call to your main class and set the value.
MainActivity.dataFromAsyncTask = "result blah";
I make it work by using threading and handler/message.
Steps as follow:
Declare a progress Dialog
ProgressDialog loadingdialog;
Create a function to close dialog when operation is finished.
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
loadingdialog.dismiss();
}
};
Code your Execution details:
public void startUpload(String filepath) {
loadingdialog = ProgressDialog.show(MainActivity.this, "Uploading", "Uploading Please Wait", true);
final String _path = filepath;
new Thread() {
public void run() {
try {
UploadFile(_path, getHostName(), getPortNo());
handler.sendEmptyMessage(0);
} catch (Exception e) {
Log.e("threadmessage", e.getMessage());
}
}
}.start();
}
You need to use "protocols" to delegate or provide data to the AsynTask.
Delegates and Data Sources
A delegate is an object that acts on behalf of, or in coordination with, another object when that object encounters an event in a program. (Apple definition)
protocols are interfaces that define some methods to delegate some behaviors.
Here is a complete example!!!
try this:
public class SomAsyncTask extends AsyncTask<String, Integer, JSONObject> {
private CallBack callBack;
public interface CallBack {
void async( JSONObject jsonResult );
void sync( JSONObject jsonResult );
void progress( Integer... status );
void cancel();
}
public SomAsyncTask(CallBack callBack) {
this.callBack = callBack;
}
#Override
protected JSONObject doInBackground(String... strings) {
JSONObject dataJson = null;
//TODO query, get some dataJson
if(this.callBack != null)
this.callBack.async( dataJson );// asynchronize with MAIN LOOP THREAD
return dataJson;
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
if(this.callBack != null)
this.callBack.progress(values);// synchronize with MAIN LOOP THREAD
}
#Override
protected void onPostExecute(JSONObject jsonObject) {
super.onPostExecute(jsonObject);
if(this.callBack != null)
this.callBack.sync(jsonObject);// synchronize with MAIN LOOP THREAD
}
#Override
protected void onCancelled() {
super.onCancelled();
if(this.callBack != null)
this.callBack.cancel();
}
}
And usage example:
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Context _localContext = getContext();
SomeAsyncTask.CallBack someCallBack = new SomeAsyncTask.CallBack() {
#Override
public void async(JSONObject jsonResult) {//async thread
//some async process, e.g. send data to server...
}
#Override
public void sync(JSONObject jsonResult) {//sync thread
//get result...
//get some resource of Activity variable...
Resources resources = _localContext.getResources();
}
#Override
public void progress(Integer... status) {//sync thread
//e.g. change status progress bar...
}
#Override
public void cancel() {
}
};
new SomeAsyncTask( someCallBack )
.execute("someParams0", "someParams1", "someParams2");
}
Probably going overboard a bit but i provided call backs for both the execution code and the results. obviously for thread safety you want to be careful what you access in your execution callback.
The AsyncTask implementation:
public class AsyncDbCall<ExecuteType,ResultType> extends AsyncTask<ExecuteType, Void,
ResultType>
{
public interface ExecuteCallback<E, R>
{
public R execute(E executeInput);
}
public interface PostExecuteCallback<R>
{
public void finish(R result);
}
private PostExecuteCallback<ResultType> _resultCallback = null;
private ExecuteCallback<ExecuteType,ResultType> _executeCallback = null;
AsyncDbCall(ExecuteCallback<ExecuteType,ResultType> executeCallback, PostExecuteCallback<ResultType> postExecuteCallback)
{
_resultCallback = postExecuteCallback;
_executeCallback = executeCallback;
}
AsyncDbCall(ExecuteCallback<ExecuteType,ResultType> executeCallback)
{
_executeCallback = executeCallback;
}
#Override
protected ResultType doInBackground(final ExecuteType... params)
{
return _executeCallback.execute(params[0]);
}
#Override
protected void onPostExecute(ResultType result)
{
if(_resultCallback != null)
_resultCallback.finish(result);
}
}
A callback:
AsyncDbCall.ExecuteCallback<Device, Device> updateDeviceCallback = new
AsyncDbCall.ExecuteCallback<Device, Device>()
{
#Override
public Device execute(Device device)
{
deviceDao.updateDevice(device);
return device;
}
};
And finally execution of the async task:
new AsyncDbCall<>(addDeviceCallback, resultCallback).execute(device);
Hope you been through this , if not please read.
https://developer.android.com/reference/android/os/AsyncTask
Depending on the nature of result data, you should choose best possible option you can think of.
It is a great choice to use an Interface
some other options would be..
If the AsyncTask class is defined inside the very class you want to
use the result in.Use a static global variable or get() , use it from
outer class (volatile variable if necessary). but should be aware of the AsyncTask progress or should at least make sure that it have finished the task and result is
available through global variable / get() method. you may use
polling, onProgressUpdate(Progress...), synchronization or interfaces (Which ever suits best for you)
If the Result is compatible to be a sharedPreference entry or it is okay to be saved as a file in the memory you could save it even from
the background task itself and could use the onPostExecute() method
to get notified when the result is available in the memory.
If the string is small enough, and is to be used with start of an
activity. it is possible to use intents (putExtra()) within
onPostExecute() , but remember that static contexts aren't that safe
to deal with.
If possible, you can call a static method from the
onPostExecute() method, with the result being your parameter

Categories

Resources