I'm trying to run many AsyncTasks to do loadData() on the same WebView. For example, I have 3 threads with 3 contents: "One", "Two", "Three" and a WebView with content "abc". (like the code below)
After 3 tasks finished, I want the WebView has content: "abcOneTwoThree". The idea of this code is that three threads will append its content to WebView at anytime, so the result could be "abcTwoOneThree" or "abcTwoThreeOne", etc ...
I read many concurrency articles but still don't understand how to implement this. This is my code. It just prints "abcThree".
public class UsingSameWebViewActivity extends Activity implements OnClickListener {
private Button button1;
private WebView webView;
private String result;
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
button1 = (Button)findViewById(R.id.button1);
button1.setOnClickListener(this);
webView = (WebView)findViewById(R.id.webView1);
result = "abc";
}
#Override
public void onClick(final View v) {
final String[] contents = {"One", "Two", "Three"};
for(int i = 0; i < 3; ++i) {
final FooTask task = new FooTask(webView, result);
task.execute(contents[i]);
}
}
private class FooTask extends AsyncTask<String, Void, String> {
private final WebView resultView;
private String result;
// This is what I try to make it work right.
private synchronized String getResult() {
return result;
}
public FooTask(final WebView resultView, final String result) {
this.resultView = resultView;
this.result = result;
}
#Override
protected String doInBackground(final String... params) {
// Do a long time work randomly then returns a string.
return params[0];
}
#Override
protected void onPostExecute(final String content) {
result = getResult() + content;
resultView.loadData(result, "text/html", "utf-8");
}
}
}
Remove the private String result; line from the Async Task class.
There is nothing much to do here.. just add this line task.execute(contents[i]);
in postExecute() of AsynTask and make contents[i] as a class variable.. task.execute(contents[i]); call this twice since you want it to do "one" and "two"
In onPostExecute() you want to "return" your result somewhere. This is to say FooTask needs a place to put its result. A likely candidate would be some sort of method FooTask can call on its caller to place the result. If you do this note that the method must be synchronized, otherwise some of the returns may be lost.
Alternately you could give FooTask a Handler that it can send a Message to with the result. In this case, you will not need to synchronize anything since all the Messages will be sent to the main/UI thread which will process them serially.
Related
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragment_home, container, false);
return myFragmentView;
}
I normally have this onCreateView executing and all my code was in it, due to a recommendation I took and inserted the remainder of my code into onViewCreated. I am not complaining but the exact same thing happened. The ASyncTask doesn't execute as I open the fragment activity. Here's my onViewCreated :
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
Requ connReq = new Requ();
connReq.execute(); //go go power rangers
}
It's not that complicated after all but for some reason it doesn't launch my asynctask. It 'shows' the ProgressDialog which begins in onPreExecute and dismisses in onPostExecute. So you could say that it just won't execute my doInBackground What am I doing wrong with this thing? I just want my ASyncTask to execute as I open the fragment and load my data.
I'd really appreciate the help, thanks in advance. I searched all over the place but I really couldn't find a proper solution for this, I thought there'd be one.
PS: the asynctask works just well when I add the execution to an onClickListener
my asynctask:
private class Requ extends AsyncTask<String, String[], String[]> {
final String pdMessage = getString(R.string.pd_wait);
ProgressDialog pd = new ProgressDialog(getActivity());
#Override
protected void onPreExecute () {
pd.setMessage(pdMessage);
pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pd.setCancelable(false);
pd.setIndeterminate(true);
pd.show();
}
#Override
protected String[] doInBackground(String... params) {
String[] connResult;
final String SipUrlStr = getString(R.string.sip_url);
String bsm = "";
String bst= "";
String hs= "";
String as= "";
try {
JSONTokener SipTokener = new JSONTokener(Sources.httpConnGet(SipUrlStr).toString());
JSONArray SipArray=new JSONArray(SipTokener);
for(int i=0; i<(SipArray.length()); i++)
{
JSONObject json_obj_sip = yeniSipArray.getJSONObject(i);
bsm = json_obj_sip.getString("mt");
bst = json_obj_sip.getString("tt");
hs = json_obj_sip.getString("pta");
as = json_obj_sip.getString("pta2");
}
} catch (Exception e) {
bsm = getString(R.string.def_sip);
bst = getString(R.string.def_sip);
hs = getString(R.string.has);
as = getString(R.string.ass);
}
connRes = new String[]{bsm, bst, hs, as};
return connRes;
}
#Override
protected void onPostExecute(String[] connRes) {
super.onPostExecute(connRes);
res[0] = connRes[0];
res[1] = connRes[1];
res[2] = connRes[2];
res[3] = connRes[3];
res[4] = connRes[4];
res[5] = connRes[5];
res[6] = connRes[6];
res[7] = connRes[7];
res[8] = connRes[8];
res[9] = connRes[9];
res[10] = connRes[10];
res[11] = connRes[11];
pd.dismiss();
}
}
Try starting your async task in
onActivityCreated
Function
public void onActivityCreated(Bundle b){
super.onActivityCreated(b);
// Execute here
//Get views
getView().findViewById(<ID>);
}
As it turns out it was about the cycle. Since I was trying to launch AsyncTask on MainThread the code flew by and AsyncTask didn't have enough time to finish its job. And one absolutely shouldn't make the thread wait for AsyncTask. It's against the first rule of AsyncTask. 'not doing that.' Okay, so I moved the execution of AsyncTask to onCreate() that way it will have more time and it won't execute everytime I open the fragment...
#Override
public void onCreate(Bundle savedInstanceState) {
Requ connReq = new Requ();
connReq.execute(); //go go power rangers
super.onCreate(savedInstanceState);
}
then, this is important, I moved all my code into onPostExecute() method of AsyncTask. If you want to change a variable or change a view you should just do it onPostExecute().
I am trying to download a file at android using AsyncTask. Because I want to download many files I want to pass the url of the file by arguments. Also I want to change the UI when a user clicks the button that triggers the AsyncTask. As I figured out, apart from the URL I need to pass and the Activity itself so I can have access to it's views so I can change them. And my problem is this how can make the AsyncTask take multiple and different arguments.
Questions:
1.The only way to do this I think is to pass as Object the first argument so anything can pass, right?
public final Example extends AsyncTask<Objects, String, String>
2.When I call the AsyncTask how do I write the function?
Example a=new Example(??????); //I want to pass both a URL and something to give me access to the UI
a.execute(?????);
3. How can I use the "something" stated above argument to change visibility for example at a view?
Thx In advance for your time
Try this..
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
new Example("URL","something").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new String[]{null});
else
new Example("URL","something").execute(new String[]{null});
and Example AsyncTask Class
public class Example extends AsyncTask<String, Void, JSONObject> {
// variables passed in:
String url;
String something;
// constructor
public Example(String url, String something) {
this.url = url;
this.something = something;
}
#Override
protected void onPreExecute() {
}
#Override
protected JSONObject doInBackground(String... args) {
}
#Override
protected void onPostExecute(JSONObject jObjOut) {
}
}
AsyncTask takes 3 generic types:
1st is the argument which you send to execution;
2nd is for publishing updates on UI
3rd is for returning result
If you want to skip one or all of them use Void class:
example: new AsyncTask();
If you want to use your own constructor in AsyncTask you should define it in your own class that extends AsyncTask, something like this:
import android.app.Activity;
import android.os.AsyncTask;
public class Example extends AsyncTask<Object, String, String>{
private Object data;
private String data1;
private String data2;
private Activity activity;
public Example(Object data, String data1, String data2, Activity activity){
this.data = data;
this.data1 = data1;
this.data2 = data2;
this.activity = activity;
}
#Override
protected String doInBackground(Object... arg0) {
//Do here all your needs except UI updating
//transfer data you need for UI updating like this:
publishProgress("UI update data argument");
return null;
}
#Override
protected void onProgressUpdate(String... arg){
super.onProgressUpdate(arg);
//Update your UI using activity
}
}
To execute your Async task :
new Example(data, data1, data2, activity).execute(object);
You can use a parameterized constructor to achieve the same. But be aware that if you have multiple arguments you would end up creating multiple constructors. Since you need to modify multiple activities in response you need to pass a context as well.
query = UtilityClass.getQueries(UtilityClass.CHECKRIDE, paramsList);
new Example(HomeActivity.this, UtilityClass.CHECKRIDE).execute(query);
This is how you can create a query/url and pass it to the AsyncTask.
A Sample AsyncTask :
public class Example extends AsyncTask<String , Void, String> {
public Example(Context contextVar, int calloutTypeVar){
context = contextVar;
CALLOUTTYPE = calloutTypeVar;
}
#Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(context, "Please wait", "Loading...");
}
#Override
protected String doInBackground(String...sqlQueryList) {
String result = "";
String sqlQuery = sqlQueryList[0];
result = UtilityClass.doHttpCallout(sqlQuery);
return result;
}
// Handle the response from the callout
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
progressDialog.dismiss();
switch (CALLOUTTYPE) {
case UtilityClass.SCHEDULERIDE:
ResponseHandlerClass.scheduleRide(result, context);
break;
}
}
I have implemented a response handler to handle the response from various callout results.
Hope this helps in handling your response from different urls.
The idea behind using AsyncTask is to avoid penalizing the responsiveness of the UI when performing blocking operations such as the file download of your scenario. When you use AsyncTask, the doInBackground method executes in another thread than the UI and the UI can not be modified from it so there is no point in passing any UI related data to it.
In order to modify your UI upon your background work completion, you can use the onPostExecute method. As #Tamilan suggested, you may pass the Activity object to the constructor of your AsyncTask if you want to use it there.
An example task could be as follows. Notice that you may replace String with URL, or even Object if you still want to pass different object types to the doInBackground method. Also, this example does not cover error handling beyond returning a simple boolean.
private class ExampleTask extends AsyncTask<String, Integer, Boolean>
{
private Activity mActivity;
public ExampleTask(Activity activity)
{
mActivity = activity;
}
#Override
protected Boolean doInBackground(String... params) {
// this is executed in a background thread
boolean success = true;
// do your background operations
publishProgress(50);
// more operations
return Boolean.valueOf(success);
}
#Override
protected void onProgressUpdate(Integer... progress) {
updateProgressbar(progress[0]); // update UI
}
#Override
protected void onPostExecute(Boolean result) {
// this is executed on your UI thread
if (!result)
// show error
else
// modify your UI
}
}
In order to execute this task:
ExampleTask task = new ExampleTask(anActivity);
task.execute(new String[] { "oneUrl", "anotherUrl" });
I am trying to send a string from one class to another using AsyncTask. In the code below everything is working with no errors, but I am wanting to get the returned str from newThread.execute() and save it to the string test. I have tried test = newThread.execute(), but I that produces the following error: Type mismatch: cannot convert from AsyncTask to String.
Class1.java
public void changText(View view) {
String test = "";
NewThread newThread = new NewThread();
newThread.execute();
}
Class2.java
public class NewThread extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... params) {
String str = "this is a test";
return str;
}
Any help would be greatly appreciated.
AsyncTask doesn't work like that, AsyncTask must be subclassed to be used.
the propose of an AsyncTask is execute some code in a separate thread (different from UI thread), but the result from that code, when ready, will be delivered in onPostExecute.
So, your code will look like this:
public Class1{
String test = "";
public void changText(View view) {
NewThread newThread = new NewThread();
newThread.execute("input");
}
public class NewThread extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
String str = params[0] + " this is a test";
return str;
}
#Override
protected void onPostExecute(String result) {
test = result;
}
}
}
You need a way to publish the result via some callback mechanism if you put an AsyncTask into it's own file. According to the dependency inversion principle it's better to let the AsyncTask define the callback mechanism instead of making it depend on some activity directly.
The resulting task could then look like this:
public class NewThread extends AsyncTask<String, Integer, String> {
/** A callback interface to be implemented by clients of this class */
public interface NewThreadClient {
void onNewThreadResult(String result);
}
private final NewThreadClient mClient;
public NewThread(NewThreadClient client) {
mClient = client;
}
#Override
protected String doInBackground(String... params) {
String str = "this is a test";
return str;
}
#Override
protected void onPostExecute(String result) {
mClient.onNewThreadResult(result);
}
}
To use it you'll need something that implements the callback. For example an Activity
public class TestActivity extends Activity implements NewThread.NewThreadClient {
private TextView mText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// simple textview actually intended for listviews..
setContentView(android.R.layout.simple_list_item_1);
mText = (TextView) findViewById(android.R.id.text1);
new NewThread(this).execute();
}
#Override
public void onNewThreadResult(String result) {
mText.setText(result);
}
}
The point of AsyncTask is that it does things asynchronously (while your program does other things, the result will be calculated at some point in the future). You can not (there are ways but it makes absolutely no sense) get the result immediately. test = newThread.execute() would require that the result is immediately available. If you start to wait for the result you would block any progress that could happen in the meantime.
Callbacks are the most common way to get a result at a later point in time. AsyncTask has onPostExecute built-in for that purpose (also to deliver the result within the UI thread) and you can use it directly if you make your AsyncTasks an inner class. Add another layer of callbacks and you can easily use them across classes.
See if you intend to do what i have done in following code
package com.example.myfirstapp;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
public class MyActivity extends Activity {
private String test;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
NewThread newThread = new NewThread();
newThread.execute();
}
class NewThread extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... params) {
String str = "this is a test";
return str;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
test=result;
// update the UI like view.setText(test);
}
}
}
Try this:
String test = newThread.execute().get();
The value returned from newThread.execute() is not the results of the computation; it's the AsyncTask itself. To publish your results, write a method in NewThread :
void onPostExecute(ArrayList<HashMap<String,String>> result) {
returnString = result; // or something similar
// then update the UI to reflect the results
}
As in Doc AsyncTask. execute (Params... params)
Return instance of AsyncTask.
but you are trying to assign AsyncTask instance to String. to get result back from Asynctask as String you should call execute().get() method on main thread as:
NewThread newThread = new NewThread();
String test= newThread.execute().get(); //<< get String from doInBackground
but this will stop execution of main thread until doInBackground method execution not completed.
if you want to get result from doInBackground without stopping execution of main thread then use onPostExecute for updating UI because this method called on Main UI Thread when doInBackground execution complete :
#Override
protected void onPostExecute(String result) {
test = result; //<< get result here
}
I've got an Activity where before showing the Text/EditText fields, I want to make a call to the server to get the details and then setText of the fields based on the data gotten back from the server.
Below is what I'm doing but the fields don't seem to have the data fetched from the server. I think because I am calling an AsyncTask which gets run in the background and in the mean time the fields are shown to the user.
Question
How does android deal with this? What pattern should I be using?
This activity gets called from MainActivity.java like so:
Intent act = new Intent(getApplicationContext(), MySecondActivity.class);
create.putExtra("theId", "138");
startActivity(create);
in MySecondActivity.java i do the following:
public class MySecondActivity extends SherlockActivity {
private EditText fieldOne;
private EditText fieldTwo;
private MyObj obj = new MyObj();
private int id;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.shared_activity);
fieldOne = (EditText)findViewById(R.id.field_one);
fieldTwo = (EditText)findViewById(R.id.field_two);
id = Integer.parseInt(getIntent().getStringExtra("theId"));
new FetchDetail().execute();
//If I put the below two lines inside the AsyncTask then I get an error:
//"Only the original thread that created a view hierarchy can touch its views."
fieldOne.setText(obj.getOne()); //
fieldTwo.setText(obj.getTwo()); //
}
class FetchDetail extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... strings) {
final RestAdapter restAdapter = new
RestAdapter.Builder().setServer("http://10.0.2.2:8080").build();
final MyTaskService apiManager = restAdapter.create(MyTaskService.class);
final MyObj obj = apiManager.getDetails(id);
return null;
}
}
}
If I put the below two lines inside the AsyncTask then I get an error
Have these in onPostExcute
fieldOne.setText(obj.getOne());
fieldTwo.setText(obj.getTwo());
Do your background computation in doInbackground. Return result in doInbackground. The result of doInbackground computation is a pram to onPostExecute.
So you can update ui in onPostExecute which is invoked on the ui thread
Example:
protected String doInBackground(String... params)
{
// background computation
return "hello"; // return string
}
#Override
protected void onPostExecute(String result) // string
{
super.onPostExecute(result);
fieldOne.setText(result); // hello is set to field One
}
For more info read the topic under The4Steps in the docs
http://developer.android.com/reference/android/os/AsyncTask.html
AsyncTask has 3 methods to override:
1: onPreExecute
Executes on UI thread. So do what you want to do on UI before service call here(Ex: show a progress dialog).
2: doInBackground
Executes in background so perform long running task like fetching data from server.
3: onPostExecute
Executes on UI thread and gets called once doInBackground is completed you can process the result here and update the UI
Ex:
public class RestServiceTask extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
}
#Override
protected void onPostExecute(String result) {
}
}
I have a PreferenceActivity that gets its data from a web service(Call forward Numbers, Voicemail status etc)
The class looks like this :
public class SettingsActivity extends PreferenceActivity
{
UserController userControl;
ListPreference lp;
public SharedPreferences prefs;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
userControl = new UserController(getParent());
addPreferencesFromResource(R.layout.settings);
new PullNumbersTask().execute();
}
private class PullNumbersTask extends AsyncTask<Void, Void, String[]>
{
private ProgressDialog Dialog;
private String[] numbers;
private boolean vmStatus;
private String[] cfInfo;
public PullNumbersTask()
{
Dialog = new ProgressDialog(getParent());
Dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
}
protected void onPreExecute()
{
Dialog.setMessage("Henter brugerindstillinger..");
Dialog.show();
}
#Override
protected String[] doInBackground(Void... arg0)
{
numbers = userControl.GetNumbers(); // Returns a String array containing available numbers
Dialog.setProgress(30);
vmStatus = userControl.GetVoicemailStatus(); // Returns a boolean containing voicemail status(enabled/disabled)
Dialog.setProgress(80);
cfInfo = userControl.GetCallForwardInfo(); // Returns a String array containing Call forward info.
Dialog.setProgress(100);
return null;
}
protected void onPostExecute(String[] result)
{
lp = (ListPreference) findPreference("shownumber_list");
lp.setEntries(result);
lp.setEntryValues(result);
Dialog.dismiss();
}
}
I decided that I want a single AsyncTask call to perform all my web service calls - But how do I Set the data of my preferences onPostExecute?
Instead of using a String[] as return value from the doInBackground() method, define a class inside your AyncTask with the fields you need to be passed to the onPostExecute() method.
Moreover you should avoid updating the progress dialog directly from the doInBackground() as it will not be performed in the UI thread. The AsynClass provides the possibility to pass a parameter to a onProgressUpdate() method to reflect changes in the progress of background execution.
More details here: http://developer.android.com/reference/android/os/AsyncTask.html
What doInBackground returns will passed as argument to onPostExecute.
So get your preferences from Web Services in doInBackground and just return it as string Array.
onPostExecute will have that String Array as argument. Apply preferences then.