During my implantation I need to throw several exceptions from a class, and handle them outside.
Inside the class I made, I also implemented AsyncTask private class, and from this class , as well, I need to throw the exceptions.
I realized that I cannot throw any exception from AsyncTask class, but only to handle it. This is not what I need.
Is there some kind of solution, so I'll be able to throw any exception I want from inside the AsyncTask?
I do something like below.
- Write your own implementation of MyListener class.Pass it in the constructor of MyAsyncTask class.
- Check the return value of doInBackground method,and call relevant method.
public interface MyListener {
public void onSuccess();
public abstract void onFail();
}
public class MyAsyncTask extends AsyncTask<String, Void, String>{
private MyListener listener;
public MyAsyncTask(MyListener listener){
this.listener = listener;
}
protected String doInBackground(String... params) {
return aValue;
}
protected void onPostExecute(String aValue) {
//Check aValue,if OK
listener.onSuccess();
//else
listener.onFail();
}
}
Related
On android calling a method that calls listener throws exception "Only the original thread that created a view hierarchy can"
here is my code:
public class MyClassAsync extends AsyncTask<String, String, ProfileInfo> {
private Context mContext;
private IGetTelegramUserInfoAsync mListener;
protected ProfileInfo doInBackground(String... params) {
// .... some code
mListener.GetResult(profileInfo)
// ...
helperMethod();
}
private void helperMethod(){
mListener.GetResult(profileInfo); //exception place
}
You might do it by calling a listener
Define a listener like this:
public interface YourListener {
public void gotResultOfYourAsync();
}
Call it in this way or implement in in your Activity or Fragment :
public class Something {
private YourListener yourListener;
public void setTheListener(YourListener listener) {
yourListener = listener;
}
//inside of your Async task you can call this
yourListener.gotResultOfYourAsync();
it is a little complicated but you can ask your questions
This is what i have so far:
I have 3 activities
In every activity is a connection to a Database to send and
recieve data
Every input (String) and Output (JSONObject) works the same
At first i implemented an asynctask in every activity to send and recieve the data
The result is handeld in the activity that started the task
To reduce the code i transfered the asynctask to an extra class
Every activity implements an interface "AsyncResponse"
My Problem is:
With the implementation i use delegate to set a reference to the calling activity. I cant find a way to change the delegation. If i want to create a new asynctask in my second activity and try to delegate it, it shows an incompatible types error.
So is there a way that i can send the asyncresults back to a specific calling activity?
Example for the implementation
public class MainActivity extends AppCompatActivity implements AsyncResponse
public void startAsync(String[] stringArray)
{
AsyncTaskRequest objMyTask = new AsyncTaskRequest(this);
// objMyTask.delegate = this; // *.delegate in another Task in not possible
objMyTask.execute(stringArray);
}
AsyncResponse Interface
public interface AsyncResponse
{
void taskDone(JSONObject x);
}
Example for the AsyncTask
public class AsyncTaskRequest extends android.os.AsyncTask<String,
Void, JSONObject>
{
//MainActivity delegate = null;
private AsyncResponse delegate;
public AsyncTaskRequest(AsyncResponse delegation)
{
delegate=delegation;
}
protected JSONObject doInBackground(String... postData)
{.......}
#Override
protected void onPostExecute(JSONObject x)
{
delegate.taskDone(x);
}
}
You can use a listener inside you ASyncTask
In your ASyncTask:
public class AsyncTaskRequest extends android.os.AsyncTask<String,
Void, JSONObject>
{
private OnTaskCompleted listener;
public interface OnTaskCompleted{
void onTaskCompleted(Boolean output);
}
private AsyncResponse delegate;
public AsyncTaskRequest(AsyncResponse delegation)
{
delegate=delegation;
}
protected JSONObject doInBackground(String... postData)
{.......}
#Override
protected void onPostExecute(JSONObject x)
{
delegate.taskDone(x);
if (listener != null)
listener.onTaskCompleted(result);
}
}
and in your java file call this function:
public OnTaskCompleted listener =new OnTaskCompleted() {
public void onTaskCompleted(Boolean output) {
//your code here
}
};
I have developed a class that manages all my API calls to my server (via AsyncTask)
problem is, that I want after the doInBackground(), in the onPostExecute() to pass externally a callback function that will be executed in the onPostExecute().
In that way, I can keep my communication class generic, and the Activity will send it a callback to activate and update the UI.
Any idea how do I do that?
thanks!
although answer is accepted, just adding another, real anonymous implementation. hope this help others.
your interface : you can implement this inside AsyncTask class.
public interface ImageLoaderListener{
void imageDownloaderCallBack(Bitmap bmp);
}
AsyncTask class Constructor :
// declare interface variable
private ImageLoaderListener listener;
private String link;
public ImageDownloader(String link, ImageLoaderListener listener){
this.link = link;
this.listener = listener;
}
onPostExecution :
#Override
protected void onPostExecute(Void result){
listener.imageDownloaderCallBack(bitmap);
// your code, i was returning bitmap
}
implementation in Activity class :
ImageDownloader imageDownloader = new ImageDownloader(url, new ImageLoaderListener(){
#Override
public void imageDownloaderCallBack(Bitmap bmp) {
// update Ui elements
}
});
imageDownloader.execute();
Also, you should remember that if any Ui elements need to be updated based on imageDownloaderCallBack return values, you should write that code inside function itself.
Here you go mate:
public class ApiMethods {
public interface OnCommandFinished {
public void onApiSuccess(String result);
public void onApiError(String error);
}
public void like(PARAMS .... , OnCommandFinished respondTo){
new runRequestTask(respondTo).execute(uri, params);
}
private class runRequestTask extends AsyncTask<Object, Void, String>{
private final OnAtomicCommandFinished mRespondTo;
public runRequestTask(OnCommandFinished respondTo){
mRespondTo = respondTo;
}
#Override
protected void onPostExecute(String result) {
// IF SUCCESS
mRespondTo.onAtomicSuccess(result);
// IF ERROR
mRespondTo.onApiError("404....");
}
}
}
To run the code, you simply call like(...) with a class that implements the OnCommandFinished
I am trying to design a helper class that implements methods using AsyncTask.
public interface ResultCallback
{
public String processResult();
}
public class ServerAdapter
{
// Required processResult to call this method. Kind of lousy but I do not know
// how to throw exception from onPostExcecute in AsyncTask.
public String getResult() throws AirplaneModeException, NoNetworkException
{
// code to get return value from Dowork throw exceptions on errors
}
public void getLicense(ResultCallback licenseCallback)
{
...// Set url, outmessage
new Dowork(url, outMessage, licenseCallback).execute();
}
public void queryServer(int queryId, ArrayList<String> args, ResultCallback queryCallback)
{
...// Set url, outmessage
new Dowork(url, outmessage, queryCallback);
}
private class Dowork extends AsyncTask<Void, Void, String>
{
...
private ResultCallback rc;
public Dowork(String url, String outMessage, ResultCallback rc)
{
// code here
}
protected String doInBackground(Void... params)
{
try
{
// code here
}
catch (AirplaneModeException e)
{
return "AirplaneModeException";
}
catch ...
}
protected void onPostExecute(String result)
{
this.result = result;
cb.processResult();
}
}
}
// Client class
public class myclass extends Activity
{
MyServerAdapter myAdapter;
public void onCreate(Bundle savedInstanceState)
{
...
myAdapter = new ServerAdapter();
myAdapter.getLicence(new MyLicenseCallback);
myAdapter.queryServer(id, args, new MyQueryCallback);
...
}
public class MyLicenseCallback extends ResultCallback implements processResult
{
try
{
String result = myAdapter.getResult;
...
}
catch
...
}
...
}
I am new to Java and Android and have a couple of questions:
1- Would several ServerAdapter method calls cause synchronize problem? For example while code for MyLicense callback is running, if onPostExecute calls MyQueryCallback, do I have to handle it or Java handles it?
2- How to get exception thrown in Dowork thrown in the callback instead of work around like in the code above?
Android guarantees you that methods in your activity and AsyncTask.onPostExecute runs in the same main UI thread.
You could save the exception in the task instance variable the same way as you do for result (return, say null as the result in this case). Check if exception present or not later to handle the error situation.
only for turkish speakers :( http://aaarkonusurum.blogspot.com/2011/10/asynctask-classtan-donen-parametreyi.html
I use an AsyncTask to perform a long process.
I don't want to place my long process code directly inside doInBackground. Instead my long process code is located in another class, that I call in doInBackground.
I would like to be able to call publishProgress from inside the longProcess function.
In C++ I would pass a callback pointer to publishProgress to my longProcess function.
How do I do that in java ?
EDIT:
My long process code:
public class MyLongProcessClass
{
public static void mylongProcess(File filetoRead)
{
// some code...
// here I would like to call publishProgress
// some code...
}
}
My AsyncTask code:
private class ReadFileTask extends AsyncTask<File, Void, Boolean>
{
ProgressDialog taskProgress;
#Override
protected Boolean doInBackground(File... configFile)
{
MyLongProcessClass.mylongProcess(configFile[0]);
return true;
}
}
EDIT #2
The long process method could also be non-static and called like this:
MyLongProcessClass fileReader = new MyLongProcessClass();
fileReader.mylongProcess(configFile[0]);
But that does not change my problem.
The difficulty is that publishProgress is protected final so even if you pass this into your static method call you still can't call publishProgress directly.
I've not tried this myself, but how about:
public class LongOperation extends AsyncTask<String, Integer, String> {
...
#Override
protected String doInBackground(String... params) {
SomeClass.doStuff(this);
return null;
}
...
public void doProgress(int value){
publishProgress(value);
}
}
...
public class SomeClass {
public static void doStuff(LongOperation task){
// do stuff
task.doProgress(1);
// more stuff etc
}
}
If this works please let me know! Note that calling doProgress from anywhere other than a method that has been invoked from doInBackground will almost certainly cause an error.
Feels pretty dirty to me, anyone else have a better way?
A solution could be placing a simple public class inside the AsyncTask (make sure the task you define is also public) which has a public method that calls publishProgress(val). Passing that class should be available from any other package or class.
public abstract class MyClass {
public MyClass() {
// code...
}
// more code from your class...
public class Task extends AsyncTask<String, Integer, Integer> {
private Progress progress;
protected Task() {
this.progress = new Progress(this);
}
// ...
#Override
protected Integer doInBackground(String... params) {
// ...
SomeClass.doStuff(progress);
// ...
}
// ...
#Override
protected void onProgressUpdate(Integer... progress) {
// your code to update progress
}
public class Progress {
private Task task;
public Progress(Task task) {
this.task = task;
}
public void publish(int val) {
task.publishProgress(val);
}
}
}
}
and then in the other class:
public class SomeClass {
public static void doStuff(Progress progress){
// do stuff
progress.publish(20);
// more stuff etc
}
}
This worked for me.
Split up the longProcess() function into smaller functions.
Sample code:
#Override
protected Boolean doInBackground(Void... params) {
YourClass.yourStaticMethodOne();
publishProgress(1);
YourClass.yourStaticMethodTwo();
publishProgress(2);
YourClass.yourStaticMethodThree();
publishProgress(3);
// And so on...
return true;
}
If this works please let me know! Note that calling doProgress from anywhere other than a method that has been invoked from doInBackground will almost certainly cause an error.
Yes, it works. I extended it so that you don't need to pass the AsyncTask as a parameter to your method. This is particularly useful if (like me) you've already written all your methods before deciding that actually you do need to publish some progress, or in my case, update the UI from an AsyncTask:
public abstract class ModifiedAsyncTask<A,B,C> extends AsyncTask<A,B,C>{
private static final HashMap<Thread,ModifiedAsyncTask<?,?,?>> threads
= new HashMap<Thread,ModifiedAsyncTask<?,?,?>>();
#Override
protected C doInBackground(A... params) {
threads.put(Thread.currentThread(), this);
return null;
}
public static <T> void publishProgressCustom(T... t) throws ClassCastException{
ModifiedAsyncTask<?, T, ?> task = null;
try{
task = (ModifiedAsyncTask<?, T, ?>) threads.get(Thread.currentThread());
}catch(ClassCastException e){
throw e;
}
if(task!=null)
task.publishProgress(t);
}
}
public class testThreadsActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void Button1Clicked(View v){
MyThread mthread = new MyThread();
mthread.execute((Void[])null);
}
private class MyThread extends ModifiedAsyncTask<Void, Long, Void>{
#Override
protected Void doInBackground(Void... params) {
super.doInBackground(params);
while(true){
myMethod(System.currentTimeMillis());
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
return null;
}
}
}
protected void onProgressUpdate(Long... progress) {
//Update UI
((TextView) findViewById(R.id.textView2)).setText("The Time is:" + progress[0]);
}
}
private void myMethod(long l){
// do something
// request UI update
ModifiedAsyncTask.publishProgressCustom(new Long[]{l});
}
}
Feels pretty dirty to me, anyone else have a better way?
My way is probably worse. I'm calling a static method for doProgress (which I called publishProgressCustom). It can be called from anywhere without producing an error (as if the thread has no corresponding AsyncTask in the hashMap, it won't call publishProgress). The down side is that you have to add the Thread-AsyncTask mapping yourself after the thread has started. (You can't override AsyncTask.execute() sadly as this is final). I've done it here by overriding doInBackground() in the super class, so that anyone extending it just has to put super.doInBackground() as the first line in their own doInBackground().
I don't know enough about Threads and AsyncTask to know what happens to the HashMap references once the Thread and/or AsyncTask comes to an end. I suspect bad things happen, so I wouldn't suggest anyone try my solution as part of their own unless they know better
When you say "my long process code is located in another class that I call in doInBackground", do you mean "located in another method that I call in doInBackground"?
If so, you could make that method a private method of your AsynTask class. Then you could call publishProgress inside the method whenever needed.