I want to do background tasks in Android to send a request to an API, but I can't get it to work the way I want.
These are my scripts:
Activity class
public class SampleActivity extends Activity {
private ApiRequest ar;
private String parameters;
...
private void callApi() {
this.ApiRequest = new ApiRequest(this.parameters);
}
}
ApiRequest class
public class ApiRequest {
private String response;
public ApiRequest(parameters) {
new BackgroundTask().execute(parameters);
}
protected class BackgroundTask extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... args) {
// Do stuff here
}
#Override
protected void onPostExecute(String response) {
this.response = response;
}
}
Somehow, I can't seem to update the response string from the onPostExecute method. I know onPostExecute is supposed to update the UI thread, but I want to update the object first, which essentially runs in the UI thread (I think). How is this done? I can't find anything about it really.
#Override
protected void onPostExecute(String response) {
this.response = response;
}
In this scope, this refers to the instance of BackgroundTask and NOT to ApiRequest. I'm surprised your code even compiles.
Change it to ApiRequest.this.response = response.
Related
What is the proper way in the following code (it's a bit complicated structure to me) to get url from the method gotUrl() to the doInBackground() method of AsyncTask in order to use it in onPostExecute(), after the doInBackground() method has completed its task?
public class PlayerActivity extends CustomActivity implements
ProblemListener{
public class PlayChannel extends
AsyncTask<CustomChangeChannel, String, String> {
#Override
protected String doInBackground(CustomChangeChannel... params) {
initOctoshapeSystem();
return url;
}
#Override
protected void onPostExecute(String url){
}
}
public void initOctoshapeSystem() {
os = OctoStatic.create(this, this, null);
os.setOctoshapeSystemListener(new OctoshapeSystemListener() {
#Override
public void onConnect() {
mStreamPlayer = setupStream(OCTOLINK);
mStreamPlayer.requestPlay();
}
});
}
public StreamPlayer setupStream(final String stream) {
StreamPlayer sp = os.createStreamPlayer(stream);
sp.setStatusChangedListener(new StatusChangedListener() {
#Override
public void statusChanged(byte oldStatus,
final byte newStatus) {
runOnUiThread(new Runnable() {
#Override
public void run() {
//todo
}
});
}
});
sp.setListener(new StreamPlayerListener() {
#Override
public void gotUrl(String url) {
//String to be passed
}
});
return sp;
}
}
AsyncTask<Param1, Param2, Param3>
Param 1 is the param that you pass into your doInBackground method.
Param 2 is what you want to get while the AsyncTask working.
Param 3 is what you want to get as result.
You can declare all them as Void.
AsyncTask<Void, Void, Void>
In your case you want to pass String URL to your doInBackground, so:
AsyncTask<String, Void, Void>
Pass your URL String when you call the execute.
mAsyncTask.execute("your url");
Then get it in the doInBackground:
protected Void doInBackground(String... params) {
String yourURL = params[0];
return null;
}
change this
public class PlayChannel extends
AsyncTask<CustomChangeChannel, String, String>
to this
public class PlayChannel extends
AsyncTask<String, String, String>
and then use
PlayChannel channel = new PlayChannel(url);
I am currently working on project. It involves reading data from cloud server continuously. I am using ubidots server. Currently i have created class that extends to asynctask class like this
public class ApiUbidots extends AsyncTask<Integer, Void, Void> {
private final String API_KEY = "1XXXXXXXXX";
private static final String tempID = "56XXXXXXXX";
#Override
protected Void doInBackground(Integer... params) {
final ApiClient apiClient = new ApiClient(API_KEY);
Variable tempVariable = apiClient.getVariable(tempID);
Value[] tempValues = tempVariable.getValues();
Double vlStr = tempValues[0].getValue();
String tempValue = String.valueOf(vlStr);
Log.i(TAG, "TEMPERATURE VALUE IS ====" + tempValue);
tempTextView.setText(tempValue);
return null;
}
}
now i am trying to set the values i got from server to display on textview but i cannot set in this class.
I need to find a way where the textview have to be changed whenever the data variable changes
Can anyone please help me how to proceed to get it working.
Thank you!
If you have this class defined as a subclass, all you need to do is update your TextView in the onPostExecute() method of your AsyncTask. If this task is a class in a separate file, you would define a callback to send data back to the calling Activity, then update your TextView with the data you receive in the callback. Here's some example code:
Your AsyncTask would look something like this. Notice it defines a public interface that acts as a callback for the results of the task.
import android.os.AsyncTask;
public class TestTask extends AsyncTask<String, Void, String> {
TestTaskCallback listener;
public TestTask(TestTaskCallback listener) {
this.listener = listener;
}
protected String doInBackground(String... args) {
String input = args[0];
String output = "simulated return value";
return output;
}
protected void onPostExecute(String result) {
listener.onResultReceived(result);
}
public interface TestTaskCallback {
void onResultReceived(String result);
}
}
Then your calling Activity would implement the callback, fire the Task, then wait for the result, like this:
public class TestActivity extends AppCompatActivity implements TestTask.TestTaskCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
new TestTask(this).execute("Some input");
}
public void onResultReceived(String result) {
Log.d("TEST TASK RESULT", result);
}
}
Once the result comes in, you can use it in your Activity to update your TextView. And as I mentioned above, this is all way easier if you just subclass the Task right in the Activity itself. That way, you'll just have access to your TextViews right from the Task. No need to mess with callbacks at that point.
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 want to use same AsyncTask in more than 2 activities. It is not practical solution to write same code in every activity. My question is,
How can I create class with AsyncTask GLOBALLY and use it any where?
My second IMPORTANT question is:
How can I get return value from onPostExecution() to every activity?
To run the asynctask from anywhere you could use otto:
If you are using android studio you add it the dependency or eclipse you download it as a jar : refer to this link : http://square.github.io/otto/
First you declare the singltone:
public class MyBus {
private static final Bus BUS = new Bus();
public static Bus getInstance() {
return BUS;
}
}
Then you create a separate asynctask class :
public class MyAsyncTask extends AsyncTask<Void, Void, String> {
#Override protected String doInBackground(Void... params) {
Random random = new Random();
final long sleep = random.nextInt(10);
try {
Thread.sleep(sleep * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Slept for " + sleep + " seconds";
}
#Override protected void onPostExecute(String result) {
MyBus.getInstance().post(new AsyncTaskResultEvent(result));
}
}
Then from inside the activity : you register the Bus and call new MyAsyncTask().execute();
Do not forget to unregister the bus on destroy:
Refer to this tutorial for more help: http://simonvt.net/2014/04/17/asynctask-is-bad-and-you-should-feel-bad/
public class MyAsyncTask extends AsyncTask<Void, Void, String> {
private OnResultReceived mListner;
public MyAsyncTask(OnResultReceived listner){
this.mListner=listner;
}
#Override protected String doInBackground(Void... params) {
//DO YOUR STUFF
String data="Test";
return data;
}
#Override protected void onPostExecute(String result) {
if(mListner!=null)mListner.onResult(result);
}
public interface OnResultReceived{
public void onResult(String result);
}
}
in Activity
new MyAsyncTask(new OnResultReceived{
public void onResult(String data){
//Your Result from AsyncTask
}
}).execute();
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