How and where to call my Task when extending AsyncTask - android

I am having difficulties understanding AsyncTask, even after reading everything about it on Developer.Android. I am looking for some insight in how I should proceed. This is the situation :
I have an Activity which, on an onClick event calls the LoginCheck() method of an underlying LoginController class. The LoginController class then proceeds to fetch whatever information is nescesarry from a UserInfo class or from the Activity(User and Password) and creates an instance of a RestClient which then makes the call to the web service and attempts to log in. RestClient has a private class CallServiceTask that extends AsyncTask.
I have a few design problems here that I hope you can be of assistance with.
Am I doing it right? Is this a proper way to make sure that any calls to the web service are being done asynchronously?
How do use onProgressUpdate or whatever to notify the user that the application is in the process of logging in?
How would I go about getting the data that is saved in DoinBackground() ?
Below you'll find snippets of the project in question :
RestClient
// From the constructor...
rtnData = new Object[]{ new JSONObject() , Boolean.TRUE };
public void ExecuteCall(RequestMethod method) throws Exception
{
Object[] parameters = new Object[]{ new HttpGet() , new String("") };
switch(method) {
case GET:
{
//add parameters
String combinedParams = "";
if(!params.isEmpty()){
combinedParams += "?";
for(NameValuePair p : params)
{
String paramString = p.getName() + "=" + URLEncoder.encode(p.getValue());
if(combinedParams.length() > 1)
{
combinedParams += "&" + paramString;
}
else
{
combinedParams += paramString;
}
}
}
HttpGet request = new HttpGet(url + combinedParams);
//add headers
for(NameValuePair h : headers)
{
request.addHeader(h.getName(), h.getValue());
}
parameters[0] = request;
parameters[1] = url;
new CallServiceTask().execute(request, url);
jsonData = ((JSONObject) rtnData[0]).optJSONObject("data");
connError = (Boolean) rtnData[1];
break;
}
case POST: ....
}
}
private Object[] executeRequest(HttpUriRequest request, String url)
{
HttpClient client = new DefaultHttpClient();
client = getNewHttpClient();
HttpResponse httpResponse;
try {
httpResponse = client.execute(request);
HttpEntity entity = httpResponse.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
String response = convertStreamToString(instream);
try {
rtnData[0] = new JSONObject(response);
rtnData[1] = false;
} catch (JSONException e1) {
rtnData[1] = true;
e1.printStackTrace();
}
// Closing the input stream will trigger connection release
instream.close();
}
} catch (ClientProtocolException e) {
client.getConnectionManager().shutdown();
e.printStackTrace();
} catch (IOException e) {
client.getConnectionManager().shutdown();
e.printStackTrace();
}
return rtnData;
}
CallServiceTask
private class CallServiceTask extends AsyncTask<Object, Void, Object[]>
{
protected Object[] doInBackground(Object... params)
{
HttpUriRequest req = (HttpUriRequest) params[0];
String url = (String) params[1];
return executeRequest(req, url);
}
#Override
protected void onPostExecute(Object[] result)
{
rtnData = result;
}
}

It's absolutely right that any possibly long running operations should be executed in separate threads. And the AsyncTask is a good way to solve this kind of problems, since it also gives you an easy way to synchronize your task with the UI thread. This is the answer to your first question.
Now, concerning the UI thread updating to show your users that your application is not stuck. Since an AsyncTask's onPreExecute() and onPostExecute() methods are running inside the UI thread, you can easily create, run and stop ProgressDialogs or ProgressBars there. If you want to show the current progress of the task, you should call publishProgress(int) method inside the doInBackground(), and then make use of it inside the AsyncTask's onProgressUpdate() method. There you can, for example, update your ProgressDialog.
And to get the result out of your AsyncTask you can either call its get() method (this a synchronous call), or implement some kind of callback interface that will tell the activity that the task has finished.
I hope the answer is clear enough, if no - feel free to ask more questions. Hope this helps.
EDIT
Create an interface called, for example, onFetchFinishedListener with one method - void onFetchFinished(String). Your activity, that starts the AsyncTask, must implement this interface. Now create a constructor inside your AsyncTask that takes an OnFetchFinishedListener object as an argument, and when instantiating the AsyncTask inside your activity send a reference to the Activity as the argument (since it implements OnFetchFinishedListener). Then when your task is finished inside doInBackground() call onFetchFinished() on the activity. Now inside the onFetchFinished(String) method of your Activity you can make use of the String (or another object) that's brought with the callback. Again, hope I was clear enough.

Related

Best way to request data from server

I need to fetch some data from my server in order to make my app work. In order to do that, I will be using POST. As far as I know, I have to request that data in a thread which can not be the main thread. I am finding it a little bit difficult to put the data I am receiving in a variable defined in the UI thread. So, my question is, which is the best way to do it?
Is it correct to set the value of a variable defined, for example, in my main activity, with a setter called inside an AsyncTask? Or is there a better option than this?
Thread nt = new Thread(){
#Override
public void run(){
try{
//get data with POST and then something like main.setValue(data);
}catch(Exception e){
e.printStackTrace();
}
}
};
nt.start();
I have read that I may use Interfaces in order to archive that, but it is a concept that I do not understand very well yet. I would like to directly use a method which returns the data, but as far as I know, it is not possible.
EDIT: new code according to NoChinDeluxe answer:
public class LoginHandler {
public static class Login extends AsyncTask<String, String, Integer> {
LoginCallback listener;
#Override
protected Integer doInBackground(String... params) {
URL url;
postDataParams.put("name", params[0]);
HashMap<String, String> postDataParams = new HashMap<String, String>();
postDataParams.put("password", params[1]);
try {
url = new URL("http://mashiron.xyz/_03z/gmpia/proc.php");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(15000);
conn.setConnectTimeout(15000);
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(os, "UTF-8"));
writer.write(HttpHandler.getPostDataString(postDataParams));
writer.flush();
writer.close();
os.close();
System.out.println("Respuesta: "+conn.getResponseCode());
return conn.getResponseCode();
} catch (Exception e) {
e.printStackTrace();
return 404;
}
}
protected void onPostExecute(int result){
System.out.println("Respuesta 2: "+result);
listener.onResultReceived(result);
}
}
public interface LoginCallback {
void onResultReceived(int result);
}
}
EDIT: added exception for NoChinDeluxe:
03-24 17:38:09.072 13312-13312/com.pitazzo.geomoments E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.pitazzo.geomoments, PID: 13312
java.lang.NullPointerException: Attempt to invoke interface method 'void com.pitazzo.geomoments.Handlers.LoginHandler$LoginCallback.onResultReceived(int)' on a null object reference
at com.pitazzo.geomoments.Handlers.LoginHandler$Login.onPostExecute(LoginHandler.java:65)
at com.pitazzo.geomoments.Handlers.LoginHandler$Login.onPostExecute(LoginHandler.java:17)
at android.os.AsyncTask.finish(AsyncTask.java:636)
at android.os.AsyncTask.access$500(AsyncTask.java:177)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:653)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5300)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)
EDIT: more code for NoChainDeluxe
public class LoginActivity extends AppCompatActivity implements LoginHandler.LoginCallback{
EditText name;
EditText password;
Button login;
int code;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login_activity);
/*
if(logueado){
}
*/
name = (EditText) findViewById(R.id.loginuser);
password = (EditText) findViewById(R.id.loginpassword);
login = (Button) findViewById(R.id.loginlogin);
login.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String params[] = {name.getText().toString(), password.getText().toString()};
System.out.println("Params: "+params.toString());
new LoginHandler.Login().execute(params);
System.out.println("Respuesta 4: "+code);
if(code == 200){
Toast toast1 =
Toast.makeText(getApplicationContext(),
"Iniciado sesión", Toast.LENGTH_SHORT);
toast1.show();
}else{
Toast toast1 =
Toast.makeText(getApplicationContext(),
"Nombre de usuario y/o contraseña incorrectos: "+code, Toast.LENGTH_SHORT);
toast1.show();
}
}
});
}
public void onResultReceived(int resultado) {
code = resultado;
System.out.println("Respuesta 3: "+code);
}
}
The best way to achieve this is to use an HttpURLConnection to make your web calls inside an AsyncTask and then pass the result back to your calling Activity through a callback. Here's some code to help you get started:
The first thing you should understand is how to properly use a callback with an AsyncTask. Here is an example AsyncTask that defines a callback interface:
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);
}
}
The way this works is, you define a public interface that you then implement in your Activity. This acts as a "listener" that is waiting for any data that is sent through to it. We define the interface TestTaskCallback because we are going to be sending our data from our AsyncTask to our calling Activity.
Then in the Activity, we need to implement this interface, and pass in a reference to our implementation to the task when we create it. That way, when the task fires, it knows where to send the result, which is back to our Activity. An example implementation might look 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);
}
}
So our Activity implements the interface that we defined inside our AsyncTask, and notice that our AsyncTask takes the reference to this implementation (passed in through the constructor) and sends data to it in the onPostExecute() method. This will allow your result to be sent to the main UI thread so that you can update your Activity appropriately.
The only thing left is to actually make the web calls. I would recommend using an HttpURLConnection for this. You would put this code inside the doInBackground() method of your AsyncTask.
I'll show you an example web service call I have set up. This shows how to make a web service call to retrieve a JSON response. It looks something like this:
//The JSON we will get back as a response from the server
JSONObject jsonResponse = null;
//Http connections and data streams
URL url;
HttpURLConnection httpURLConnection = null;
OutputStreamWriter outputStreamWriter = null;
try {
//open connection to the server
url = new URL("your_url_to_web_service");
httpURLConnection = (HttpURLConnection) url.openConnection();
//set request properties
httpURLConnection.setDoOutput(true); //defaults request method to POST
httpURLConnection.setDoInput(true); //allow input to this HttpURLConnection
httpURLConnection.setRequestProperty("Content-Type", "application/json"); //header params
httpURLConnection.setRequestProperty("Accept", "application/json"); //header params
httpURLConnection.setFixedLengthStreamingMode(jsonToSend.toString().getBytes().length); //header param "content-length"
//open output stream and POST our JSON data to server
outputStreamWriter = new OutputStreamWriter(httpURLConnection.getOutputStream());
outputStreamWriter.write(jsonToSend.toString());
outputStreamWriter.flush(); //flush the stream when we're finished writing to make sure all bytes get to their destination
//prepare input buffer and get the http response from server
StringBuilder stringBuilder = new StringBuilder();
int responseCode = httpURLConnection.getResponseCode();
//Check to make sure we got a valid status response from the server,
//then get the server JSON response if we did.
if(responseCode == HttpURLConnection.HTTP_OK) {
//read in each line of the response to the input buffer
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(),"utf-8"));
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
bufferedReader.close(); //close out the input stream
try {
//Copy the JSON response to a local JSONObject
jsonResponse = new JSONObject(stringBuilder.toString());
} catch (JSONException je) {
je.printStackTrace();
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
if(httpURLConnection != null) {
httpURLConnection.disconnect(); //close out our http connection
}
if(outputStreamWriter != null) {
try {
outputStreamWriter.close(); //close our output stream
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
//Return the JSON response from the server.
return jsonResponse;
This is pretty much all you need to know to do exactly what it is you are trying to do. I realize this is a ton of info to throw at you all at once, but if you take your time and work through it piece by piece, you'll find it's not too difficult after all and is actually a VERY powerful tool that you'll use all the time programming Android apps!
Hope this helps. Feel free to ask questions for any parts you don't fully understand yet!
Better use an AsyncTask to propagate the data to your UI thread, just use onPostExecute() to set the result on your activity's class.
The error you are getting is because of accessing UI elements from background thread.
AsyncTask is a Thread pool based api that runs your task in a seperate thread
,but your UI part runs in a thread usually called UI thread,
to update any changes to ui put the logic onPostExecute()
NOTE: Use okhttp to get consistent http api, it also supports http2.Their github wiki is very helpful, check here for examples.

The method execute() is undefined for the type InvoiceTemplateGet

I use AsyncTask to get result from API. I have several classes which works fine. I've created another AsyncTask class, but I get this error:
The method execute() is undefined for the type InvoiceTemplateGet
On this line:
InvoiceTemplateGet template = new InvoiceTemplateGet(PaymentMethodActivity.this, invoiceNumber);
template.execute();
There is the class InvoiceTemplateGet:
public class InvoiceTemplateGet {
public InvoiceTemplateGet(Context context, String invoiceNumber){
mContext = context;
this.invoiceNumber = invoiceNumber;
load_default_settings();
}
protected CustomAsyncTaskResult<String> doInBackground(String... arg0) {
try{
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(url);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
String response = httpclient.execute(httpget,responseHandler);
return new CustomAsyncTaskResult<String>(response);
}catch (HttpResponseException e){
return new CustomAsyncTaskResult<String>(new ApiException("Invoice", "Invoice was not found."));
}catch (Exception e){
Log.e("Invoice Error", "Error:", e);
return new CustomAsyncTaskResult<String>(new ApiException("Invoice", e.getMessage()));
}
}
protected void onPostExecute(CustomAsyncTaskResult<String> result) {
((PaymentMethodActivity)mContext).getResultFromTemplate(result);
progressDialog.dismiss();
}
}
I have another class which is the same like this one, just url is different. It's executed on the same page like this one, on the same part of code. And it works, so why I'm still getting this error?
I have another class which is the same like this one, just url is
different. It's executed on the same page like this one, on the same
part of code. And it works, so why I'm still getting this error?
your InvoiceTemplateGet hasn't a method called execute(). Looking at your code, it looks to me that you forgot to extend AsyncTask. You could also create your execute() method which instantiate the inner AsyncTask and call instance.execute()

Implementing EndlessAdapter with AsyncTask Passing in Object[]

I have reviewed all of the documentation for CWAC-endlessAdapteras well as the demo projects. I do understand how it works and mostly where everything goes. But I have a several questions on how to handle some things with how I am currently doing it now (I have yet to find any working example of this).
Here is a typical AsyncTask I use (cleaned up a bit):
class ReviewTask extends AsyncTask<String, String, Void> {
#Override
protected Void doInBackground(String... params) {
ArrayList<NameValuePair> param = new ArrayList<NameValuePair>();
param.add(new BasicNameValuePair("username", userName));
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url_select);
try {
httpPost.setEntity(new UrlEncodedFormEntity(param));
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
} catch (Exception e) {
}
try {
BufferedReader br = new BufferedReader(
new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = "";
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
result = sb.toString();
} catch (Exception e) {
}
return null;
}
protected void onPostExecute(Void v) {
String review, newdate, item, rating, cat;
try {
JSONArray jArray = new JSONArray(result);
JSONObject json_data = null;
for (int i = 0; i < jArray.length(); i++) {
json_data = jArray.getJSONObject(i);
newdate = json_data.getString("date");
review = json_data.getString("review");
item = json_data.getString("item");
rating = json_data.getString("rating");
cat = json_data.getString("category");
reviews.add(review);
itemslist.add(item);
datelist.add(newdate);
ratings.add(rating);
cats.add(cat);
}
}
Profile[] p = new Profile[reviews.size()];
int index = 0;
for (String i : reviews) {
p[index] = new Profile(reviews.get(index), datelist.get(index),
itemslist.get(index), ratings.get(index),
cats.get(index));
index++;
}
if (getActivity() != null) {
adapter = new ProfileAdapter(getActivity(), p);
setListAdapter(adapter);
}
}
}
In this task, I get all the data from MySQL Database via php. The SQL query I wrote gathers all data at once. Is this correct to still handle this way?
Also, I call this task in the onCreateView in my ListFragment. But it looks like the task needs to be called in cacheInBackground()?
Lastly, it sounds like I have to set the adapter in onActivityCreated like this:
// from Example
if (adapter==null) {
items=new ArrayList<Integer>();
for (int i=0;i<25;i++) { items.add(i); }
adapter=new DemoAdapter(items);
adapter.setRunInBackground(false);
}
setListAdapter(adapter);
I don't understand or see where there is a constructor for DemoAdapter(items), and based on the fact that I am passing an Array of Objects, would I do something like DemoAdapter(object[])? And it's ok if it is null, because gathering the data actually happens in the adapter, correct?
Last relevant note is, all of my adapters are in a class outside of the Fragment where they are set.
The SQL query I wrote gathers all data at once. Is this correct to still handle this way?
That is up to you. However, doing it this way, you do not need EndlessAdapter, as you already have all your data. The point behind EndlessAdapter is to support situations where you do not "gather all data at once", but rather wish to gather a portion of the data, and gather another portion only when the user scrolls far enough.
Also, I call this task in the onCreateView in my ListFragment. But it looks like the task needs to be called in cacheInBackground()?
That is up to you. If you wish to use your own AsyncTask called whenever you want, that is fine. This is covered in the documentation:
If you would prefer that EndlessAdapter not run its own AsyncTask, then call setRunInBackground(false). In this mode, your cacheInBackground() method will be called on the main application thread. It is up to you to arrange to do the work on your own background thread, then call onDataReady() when you want the adapter to update to reflect the newly added data. Note that appendCachedData() will not be used in this scenario.
I don't understand or see where there is a constructor for DemoAdapter(items)
There isn't one, as the demos did not require one.
based on the fact that I am passing an Array of Objects, would I do something like DemoAdapter(object[])?
That is up to you.
And it's ok if it is null, because gathering the data actually happens in the adapter, correct?
Again, that is up to you.
However, as I pointed out earlier, since you do not need EndlessAdapter, I would recommend that you just stop using it.

Android issues with AsyncTask and InputStream

I've been trying to figure this out on my own for quite a while.. by trial/error as well as research, but I just can't seem to get it figured out. I'm pretty bad with Async and network connections and stuch, so it might be something simple that I'm over looking. Anyway... I'll paste some relevant code samples and explanations.
Quick background of my problem. I'm working with the Rotten Tomatoes API for my app, and am using GSON for the parsing of their data. I was initially targeting 2.3, and this worked fine. Then I decided to have support for ICS, and of course ran into the "no network operation on the UI thread" - so I started to delve into AsyncTask.
Here is my InputStream method:
private InputStream retrieveStream(String url) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet getRequest = new HttpGet(url);
try {
HttpResponse getResponse = client.execute(getRequest);
final int statusCode = getResponse.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w(getClass().getSimpleName(),
"Error " + statusCode + " for URL " + url);
return null;
}
HttpEntity getResponseEntity = getResponse.getEntity();
return getResponseEntity.getContent();
}
catch (IOException e) {
getRequest.abort();
Log.w(getClass().getSimpleName(), "Error for URL " + url, e);
}
return null;
}
Which was working fine in my main activity, and now is giving me issues when trying to 'convert' it into AsyncTask. I've been calling it like this:
InputStream source = retrieveStream( url parameter );
Then I tried moving that method into my AsyncTask class, and calling it like this:
private PerformMovieSearch performSearch = new PerformMovieSearch(this);
InputStream source = performSearch.retrieveStream(movieQueryUrl);
But that doesn't cut it, still get the error about performing network actions on the UI. What I need to figure out is how to call 'retrieveStream' from the AsyncTask I guess. Currently that class looks like this:
package net.neonlotus.ucritic;
[imports]
public class PerformMovieSearch extends AsyncTask<String, Void, String> {
private final Context context;
private ProgressDialog progressDialog;
public PerformMovieSearch(Context context){
this.context = context;
}
#Override
protected String doInBackground(String... urls) {
retrieveStream(urls[0]);
return null;
}
#Override
protected void onPreExecute() {
progressDialog= ProgressDialog.show(context, "Please Wait","Searching movies", true);
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
progressDialog.dismiss();
MyActivity.mListAdapter.notifyDataSetChanged();
}
public InputStream retrieveStream(String url) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet getRequest = new HttpGet(url);
try {
HttpResponse getResponse = client.execute(getRequest);
final int statusCode = getResponse.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w(getClass().getSimpleName(),
"Error " + statusCode + " for URL " + url);
return null;
}
HttpEntity getResponseEntity = getResponse.getEntity();
return getResponseEntity.getContent();
} catch (IOException e) {
getRequest.abort();
Log.w(getClass().getSimpleName(), "Error for URL " + url, e);
}
return null;
}
}
The "doinbackground" is what needs to be changed... but I can't seem to find a straight way to get that working properly. I was executing using
new PerformMovieSearch(this).execute(movieQueryUrl);
I know that is a lot of stuff, potentially confusing... but if anybody knows how to essentially do the retrieveStream method asynchronously, that would be great. Like I said, Ive tried many things, did plenty of research, just could not come up with anything useful.
the point is, you didn't understand how asynctask works!
You MUST read the guide Processes and Threads: http://developer.android.com/guide/components/processes-and-threads.html
But ok, let me try help you.
On doInBackground you are correctly calling the method retrieveStream, but you are doing nothing with the stream. So, you have to process the stream and then, return it. As you said you are expecting an JSON, I'm assuming you will receive a String, so the code of your retrieveStream should like this:
public String retrieveStream(String url) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet getRequest = new HttpGet(url);
try {
HttpResponse getResponse = client.execute(getRequest);
final int statusCode = getResponse.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w(getClass().getSimpleName(),
"Error " + statusCode + " for URL " + url);
return null;
}
HttpEntity getResponseEntity = getResponse.getEntity();
String jsonString = EntityUtils.toString(getResponseEntity);
return jsonString;
} catch (IOException e) {
getRequest.abort();
Log.w(getClass().getSimpleName(), "Error for URL " + url, e);
}
return null;
}
Look that I changed the return type to String. And maybe, you should change the name to retrieveMoviesJSON or something like this.
And you should change your AsyncTask to something like this:
class PerformMovieSearch AsyncTask<String, Void, ArrayList<Movie>>() {
#Override
protected void onPreExecute() {
progressDialog= ProgressDialog.show(context, "Please Wait","Searching movies", true);
}
#Override
protected ArrayList<Movie> doInBackground(String... params) {
String moviesJson = retrieveStream[params[0]];
JSONObject moviesJson = new JSONObject(moviesJson);
ArrayList<Movie> movies = new ArrayList<Movie>();
/*
* Do your code to process the JSON and create an ArrayList of films.
* It's just a suggestion how to store the data.
*/
return movies;
}
protected void onPostExecute(ArrayList<Movie> result) {
progressDialog.dismiss();
//create a method to set an ArrayList in your adapter and set it here.
MyActivity.mListAdapter.setMovies(result);
MyActivity.mListAdapter.notifyDataSetChanged();
}
}
And you can call as the same way you were doing.
Is it clear? Need more explanation?
[]s
Neto
What sort of behavior are you seeing that is unexpected. From scanning your code, it looks like it probably compiles and runs but I would guess that your ListAdapter never gets updated with fresh data (i.e. you're probably trying to display the results in a ListView or GridView but nothing is showing up). Is that correct? Or are you still getting the Network on Main Thread error?
You are retrieving data using your HTTP Client and then not doing anything with it. One way you could solve it is to structure your code such that:
1) Your class that extends AsyncTask has a constructor that takes a ListAdapter object
2) Your main Activity would create an instance of the AsyncTask and pass in a reference to its ListAdapter object
3) Your doInBackground method would handle all the network activity and return the result (the data you pulled from the web service) so that it gets passed down to the onPostExecute method
4) In onPostExecute, you will have the data that was returned from doInBackground, and you'll have the ListAdapter that was provided in the constructor, so parse the data, populate the ListAdapter, and invalidate it so that the list gets redrawn.
Keep in mind that AsyncTask lets you interact with the UI thread in both the onPreExecute and onPostExecute methods, so those are the only places that you can draw to the screen (i.e. populating the adapter and invalidating it so that it will redraw)

Send HttpPost with Async and get string result

I am relatively a new Android developer and I am not able to understand how to do this. I have been looking through all the forums, I made some advance but still here I am.
So, what I want to do is a common function that send a POST request to a webpage (it only sends one POST argument) and returns the result as a string.
I have the main thread here
public class AppActivity extends Activity {
HTTPPostData PostData = new HTTPPostData("id");
PostData.execute();
txtLabel.setText(PostData.Result);
}
and I have my HTTPPostData asynchronous class
public class HTTPPostData extends AsyncTask<String, Long, Object> {
String Value = null;
String Result = null;
public HTTPPostData(String query) {
Value = query;
}
#Override
protected String doInBackground(String... params) {
byte[] Bresult = null;
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("http://www.mypage.com/script.php");
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
nameValuePairs.add(new BasicNameValuePair("cmd", Value));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));
HttpResponse response = client.execute(post);
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == HttpURLConnection.HTTP_OK){
Bresult = EntityUtils.toByteArray(response.getEntity());
Result = new String(Bresult, "UTF-8");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (Exception e) {
}
return Result;
}
}
I want to use this function several times (inside the same Activity or share it with other Activities of the same application). I am a little bit messed up at this moment so I need your help. What I understand is that I am asking for the result before the doInBackground() is done, and I get an empty result.
Thanks in advance for your help
Regarding this:
HTTPPostData PostData = new HTTPPostData("id");
PostData.execute();
txtLabel.setText(PostData.Result);
Your problem is that you're treating asynctask like it's just a regular function. It's good that you move webpage loading off the main thread, but if you depend on the result for the very next instruction, then it's not doing you much good, you're still blocking the main program waiting for the result. You need to think of AsyncTask like a 'fire and forget' operation, in which you don't know when, if ever, it will come back.
The better thing to do here would be something like:
HTTPPostData PostData = new HTTPPostData("id");
PostData.execute();
txtLabel.setText("Loading...");
and then in the asynctask:
protected void onPostExecute(String result) {
txtLabel.setText(result);
}
This lets your main thread get on with doing it's business without knowing the result of the asynctask, and then as soon as the data is available the asynctask will populate the text label with the result.

Categories

Resources