I am trying to pass a Runnable to an AsyncTask and then set the results of doInBackgroud to it and run it.
I am trying the following code with no success.
// MyActivity.java
public void click(View v) {
if(v.getId() == R.id.button) {
new AsyncHTTP(myAsyncClassCallback()).execute();
}
}
public Runnable myAsyncClassCallback() {
return new StringRunnable() {
#Override
public void run() {
Log.v(DEBUG_TAG,result.toString());
}
};
}
// StringRunnable.java
public class StringRunnable implements Runnable {
volatile String result;
public void setResult(String res) {
this.result = res;
}
#Override
public void run() {
// do something with result
}
}
// MyAsyncClass.java
public class MyAsyncClass extends AsyncTask<String, Integer, String>{
private Runnable myCallback;
public MyAsyncClass(Runnable runnable){
this.myCallback = runnable;
}
#Override
protected String doInBackground(){
// works normally
return someString;
}
#Override
protected void onPostExecute(String result) {
myCallback.setResult(result); // <--- This is my question
myCallback.run();
super.onPostExecute(result);
}
}
So I get the message:
Cannot resolve method setResult
How can I fix this? Is this some access issue?
You declared myCallback a Runnable, but Runnable does not contain a definition for setResult(String result). Your extended class, however, does. Which means you should cast the Runnable to a StringRunnable, which it actually is
((StringRunnable)myCallback).setResult(result);
Or you should declare your myCallback as a StringRunnable
private StringRunnable myCallback;
EDIT: as Unihedron pointed out, the last options means you have to change your Constructor as well
private StringRunnable myCallback;
public MyAsyncClass(StringRunnable runnable){
this.myCallback = runnable;
}
I should note, however, that it is, in your case, unnecessary to use two non-UI-threads. AsyncTask is a Thread as well
instead of
private Runnable myCallback;
use
private StringRunnable myCallback;
You'll have to cast Runnable to StringRunnable like this:
((StringRunnable)myCallback).setResult(result);
Related
since im new in android development, and i need to provide an asynctask class for my http request. i have a lot of http request function type in one activity, and i want to make it dynamic. so i wanted to create only one AsyncTask function that can run all my function.
so this is the example
private class WebServiceCall extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
pBar.setVisibility(View.VISIBLE);
pBar.setIndeterminate(false);
pBar.setClickable(false);
}
#Override
protected Void doInBackground(Void... params) {
// a function that i passed
Function01();
return null;
}
#Override
protected void onPostExecute(Void result) {
try{
some code
}
}
catch(Exception e)
{
e.printStackTrace();
}
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
pBar.setClickable(true);
pBar.setVisibility(View.GONE);
}
}
and i just call like this
Oncreate(
new WebServiceCall().execute(function01());
)
any help and code sample would be appreciate,
thanks
I don't know what you mean by a function as a parameter to another function!
but you can use Interfaces for this purpose.
for example:
create an Call Back interface that can be called in onPostExecute()
public interface ResponseCallback {
void onRespond();
}
and before calling asynckTask define it like this:
ResponseCallback callback = new ResponseCallback() {
#Override
public void onRespond() {
//code to be done after calling it from onPostExecute
}
};
and pass callback to the constructor of of the asynckTask and call it in onPostExecute
of course you can modify the signature of the interface to what ever you want.
Send class object with your function and call function from object in AsyncTask.
public class A
{
//your function
int function()
{
return...;
}
}
private class WebServiceCall extends AsyncTask<Void, Void, Void> {
A myobj;
WebServiceCall(A mycustomslass)
{
myobj = mycustomclass;
}
#Override
protected void onPreExecute() {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
pBar.setVisibility(View.VISIBLE);
pBar.setIndeterminate(false);
pBar.setClickable(false);
}
#Override
protected Void doInBackground(Void... params) {
// a function that i passed
int cur = myobj.function();//this your function
return null;
}
#Override
protected void onPostExecute(Void result) {
try{
some code
}
}
catch(Exception e)
{
e.printStackTrace();
}
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
pBar.setClickable(true);
pBar.setVisibility(View.GONE);
}
}
and you can call like
Oncreate(
new WebServiceCall(new A()).execute();
)
This doesn't address your question directly, but I urge you to investigate both the fairly-well advertised problems with using AsyncTask for anything that's likely to take more than a few milliseconds, and the several really good HTTP / REST frameworks for Android, e.g. Retrofit.
When a background task returns a value how can it be accesses from another class. Just using this as example code, but what I want is the background task to do something and return a value.
protected String doInBackground(String... params) {
publishProgress("Sleeping..."); // Calls onProgressUpdate()
try {
// Do your long operations here and return the result
int time = Integer.parseInt(params[0]);
// Sleeping for given time period
Thread.sleep(time);
resp = "Slept for " + time + " milliseconds";
} catch (InterruptedException e) {
e.printStackTrace();
resp = e.getMessage();
} catch (Exception e) {
e.printStackTrace();
resp = e.getMessage();
}
**return resp;**
}
For this you need to extend asynktask class like
extends AsyncTask<String, String, String>
#Override
protected void onPostExecute(String result) {
//heare result is value you return from doInBackground() method
//this is work on UI thread
}
Classs look like
public class AsyncTaskGetResult extends AsyncTask<String, String, String> {
PrintListner mPrintListner ;
private AsyncTaskGetResult (PrintListner mPrintListner) {
this.mPrintListner = mPrintListner;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
return result;
}
#Override
protected void onPostExecute(String result) {
//heare result is value you return from doInBackground() method
//this is work on UI thread
this.mPrintListner.getResult(result);
}
}
public interface PrintListner {
public void getResult(String receiptItem);
}
If you need to access it in another class you can write listner for that and implement in you activity
public class MyActivity extends Activity implements PrintListner{
#Override
public void getResult(String receiptItem){
//Do whatever you want
}
}
and call it like new AsyncTaskGetResult(this).execute(yourString);
AsyncTask:
public class YourBackgroundTask extends AsyncTask<String, Void, String> {
private Callback callback;
public YourBackgroundTask(Callback callback){
this.callback = callback;
}
protected void doInBackground(String... strings) {
// do what you have to do
return result;
}
protected void onPostExecute(String result) {
this.callback.onDone(result);
}
public Interface Callback{
void onDone(String result);
}
}
and call it like this:
new YourBackgroundTask(yourCallback).execute(yourString);
You have a little misunderstanding. Background tasks do NOT return a value. They just do something. If you want to get a value out of some computation done in background you can make the background task so that when it finishes, it notifies some object about the resulting value.
The previous behavior can be done through the observer pattern in which an object is used to observe events from another object. In this case you want to define an observer (often called listener) and pass it to your background task.
Your listener interface may look like this:
interface ValueListener {
public void onValueComputed(int computedValue);
}
Then an implementing class looks like this:
class ValueListenerImpl implements MyListener {
#Override
public void onValueComputed(int computedValue) {
//do something...
}
}
(or you can make an anonymous class)
Your background task:
class MyAsyncTask extends AsyncTask<Void, Void, Integer> {
ValueListener listener;
public MyAsyncTask(ValueListener valueListener) {
this.listener = valueListener;
}
#Override
public Integer doInBackground(Void.. params) {
//do something...
return someValue;
}
#Override
public onPostExecute(Integer.. values) {
listener.onValueComputed(values[0]);
}
}
Finally, in your main thread you do:
...
this.valueListener = new ValueListenerImpl();
new MyAsyncTask(this.valueListener).execute();
...
I have 2 Classes: a Main Class handling the UI and a second Class for retrieving Data from SQL Server by using PHP.
From the first class a mehtod in the second class is called with passing and retrieving variables.
Actually it is working fine without AsyncTask.
But since I want to use the code on devices running Android 3.0 and above, I need to change the method to be an AsyncTask. Else I get this error: "android.os.networkonmainthreadexception"
the actual working code Looks like this:
Main class:
...
String inputString="1";
String outputString;
outputString = Class2.SomeMethodInClass2(inputString);
....
Class2:
public class Class2 {
public static String SomeMethodInClass2(String input) {
String Output;
...
//Do some php-sql stuff based on "input"-variable
//and return the "output"-variable
...
return output;
}
}
This code works perfectly on Android 2.0 but I need to change it to AsyncTask, because Andoid 3.0 and above is giving me: "android.os.networkonmainthreadexception"
I have read a lot of threads about AsyncTask, but I can not get it to work with Input and Output in my code.
Eclipse allways tells me there is something wrong with my code.
How do I have to change my code, to be a working async Task? (please explain using my above code sample)
--edit: if there is an easier way to get rid of "android.os.networkonmainthreadexception" on 3.0 an above than AsyncTask, this would be fine too! --
Have a Callback in SecondClass
Extend your SecondClass with Asynctask
Implement preExecute,doinbackground, postExecute methods
Do your stuff in doinbackground
return result in doinbackground
In postExecute pass result to the Callback
Implement SecondClass.Callback in FirstClass
start SecondClass (execute) and pass a Callback reference from FirstClass
In Callback just handle your next operations with the result
EDIT :
public class SecondClass extends AsyncTask<String, Void, String> {
public interface Callback {
public void update(String result);
}
Callback mCallback;
public SecondClass(Callback callback) {
super();
mCallback = callback;
}
#Override
protected String doInBackground(String... params) {
String result = null;
//do your stuff and save result
return result;
}
#Override
protected void onPostExecute(String result) {
if(mCallback != null)
mCallback.update(result)
super.onPostExecute(e);
}
}
public class FirstClass implements SecondClass.Callback{
#Override
public void update(String result){
//do your stuff with result
}
return_type someMethod(){
SecondClass sc = new SecondClass(this) ;
sc.execute(someurl);
}
}
thanks for your Posts!
But i found an alternative way that seems much easier and better to me than doing async Task.
i added to my main class:
public class MainClass extends Activity implements OnTouchListener {
...
BackgroundOperations1 ourBackgroundOperations; //<===new
...
#Override
protected void onCreate(Bundle savedInstanceState) {
...
ourBackgroundOperations = new BackgroundOperations1(); //<===new
...
}
#Override
protected void onPause() {
....
ourBackgroundOperations.pause(); // <===new
}
#Override
protected void onResume() {
....
ourBackgroundOperations.resume(); // <===new
}
//whole new class inside of "MainClass"
//runs a different thread, i believe...?
public class BackgroundOperations1 implements Runnable {
Thread ourThread = null;
boolean isRunning = false;
public void pause() {
isRunning = false;
while (true) {
try {
ourThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
}
public void resume() {
isRunning = true;
ourThread = new Thread(this);
ourThread.start();
}
#Override
public void run() {
while (isRunning) {
if (dothis==true){
//here i call my mehtod from class2, whenever "dothis" is set to true (somewhere in my onTouch or where ever i want)
String inputString="1";
String outputString;
outputString = Class2.SomeMethodInClass2(inputString);
}
}
}
}
}
this works on Android 4.0 and i think it is the best way to do what i want. and to me it seems a lot clearer then AsyncTask, because i can call my methods an pass varaibles in a simple way.
or is there a reason to not do it like this?
I cant figure out why the variable "vysledek" stays unchanged after calling the void "Send" from activity. I probably doesnt fully understand the way AsyncTask works. Thanks for help.
public class Tools{
public String vysledek;
public void Send() {
Poslat Poslat = new Poslat();
Poslat.execute();
}
private class Poslat extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
vysledek = "something I want it to be";
}
#Override
protected void onPostExecute(String result){
vysledek = "something I want it to be 2";
}
}
I want that the Activity that called "Send" have the variable already. So i guess it has to wait for it to finish. I tried to do the waiting like this:
while (Tools.vysledek.equals(""))
{ }
But that causes crash.
Timing. The asnc task happens on another thread. But when the OS switches to that thread is up to the OS. It should happen quickly (next few hundred ms), but it won't necessarily be immediate, so if you immediately check for it you may or may not see it changed. The correct place to put code that requires the async task to have run is in onPostExecute.
You should assign it after the asynctask finishes
public class Tools{
public String vysledek;
public void Send() {
Poslat Poslat = new Poslat();
Poslat.execute(vysledek);
}
private class Poslat extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
}
#Override
protected void onPostExecute(String result){
vysledek = "I should be here";
}
}
Ok, there isn't synchronous call in GWT.
But if i have something like this:
class XXX {
Config c=new Config();
c.doSomething();
}
and the class Config
public class Config {
private static HashMap<String,String> map;
public Config(){
final ServerProxyAsync serverProxy= GWT.create(ServerProxy.class);
serverProxy.getParameters(new AsyncCallback<HashMap<String,String>>() {
#Override
public void onFailure(Throwable caught) {
System.out.println("getParameters: FAILED!");
map=null;
}
#Override
public void onSuccess(HashMap<String, String> result) {
System.out.println("getParameters: OK!");
map=result;
// RETURN NOW!!!!
}
});
}
if the asynchronous call doesn't terminate I can't do doSomething(), because sometime the method is invoked before the map is initialized.
Is there a way?
How about doSomething() in onSuccess() ?
You can't use synchronous call in GWT.Even though you made it somehowits not a good practise
When you need this you have to do the stuff in the onSuccess(); of your RPC call .
So, the best idea is to simply use the asynchronous method and continue execution via the callbacks provided.You will end up with a much better user experience, and a more professional appearing
application.
Just extends your Config class to take a Runnable or a Callback. Something like this:
public class Config {
private static HashMap<String,String> map;
private final Runnable callback;
public Config(Runnable callback){
this.run = run;
final ServerProxyAsync serverProxy= GWT.create(ServerProxy.class);
serverProxy.getParameters(new AsyncCallback<HashMap<String,String>>() {
#Override
public void onFailure(Throwable caught) {
System.out.println("getParameters: FAILED!");
map=null;
}
#Override
public void onSuccess(HashMap<String, String> result) {
System.out.println("getParameters: OK!");
map=result;
callback.run();
}
});
}
}
Then you can use it like this:
class XXX {
final Runnable callback = new Runnable() {
#Override
public void run() {
dosomething1();
}
};
Config c=new Config(callback);
}