Android issues with AsyncTask and InputStream - android

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)

Related

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()

Android application force Close on lowsy Internet connection

I have the following code for to perform xml download via asynctask for android application targeting for android version>3. The code work pretty good if the network/internet connection is good. However, if internet connection is not good, the application will force close. I have tried throw in different kind of error catching but still unable to solve the force close on lowsy internet connection.
Anyone has any suggestion that I can try
private class DownloadWebPageXML extends AsyncTask<String, Void, InputStream> {
#Override
protected InputStream doInBackground(String... urls) {
Log.d("mylogitem", "AsyncTask started!");
InputStream content = null;
String myurl = urls[0];
AndroidHttpClient client = AndroidHttpClient.newInstance("Android");
HttpGet httpGet = new HttpGet(myurl);
try {
HttpResponse execute = client.execute(httpGet);
content = execute.getEntity().getContent();
} catch (Exception e) {
xmldownloaderror = e.getMessage();
Log.d("mylogitem", e.getMessage());
} finally {
Log.d("mylogitem", "Closing AndroidHttpClient");
client.close();
}
return content;
}
#Override
protected void onPostExecute(InputStream result) {
//do xml reader on inputstream
}
}
add a null check on variable execute, in between these two lines
HttpResponse execute = client.execute(httpGet);
if(execute == null){ return null;} // null check to see if execute is null
content = execute.getEntity().getContent();
another thing in onPostExecute, first line should check if InputStream result is null!
#Override
protected void onPostExecute(InputStream result) {
if(result == null){
Log.d("TEMP_LOG",Content is null);
return;
}
//do xml reader on inputstream
}
check and post your findings
hmm... I recommend to set connection times.
HttpClient client = new DefaultHttpClient();
HttpResponse response;
BufferedReader bufferedReader = null;
HttpParams params = client.getParams();
HttpConnectionParams.setConnectionTimeout(params, 20000);
HttpConnectionParams.setSoTimeout(params, 20000);
I have found the root cause. It is not in the dobackground.
In my case, lousy connection will sometime return not xml data type but rather loading error,
and this is passed as the inputstream to my xmlparser in postexecute.
I did not put in much error catcher in my xmlparser. xmlparser is expecting xml document but received non-xml content, thus throwing null in which i did not cover with error catcher.
Thank you for the suggestion. I have place it in my code as well.

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.

How and where to call my Task when extending AsyncTask

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.

handle exceptions

I write a client for web service. Like, did request -> got JSON answer.
But if user not authorized I got "bad" JSON answer and NullPointerException. Further, the logic is create ListAdapter for a ListView from JSON answer. But if JSON null then app will crash.
I want do like this for handle exception:
Get Adapter:
public mListAdapter getData(String api){
mListAdapter result = null;
MyData[][] mData = null;
try{
Gson gson = new Gson();
Reader r = new InputStreamReader(getJSONData(api));
// getJSONData, here i can get Exception and return null, but i read what control of logic via exception is bad practice
}catch(Exception ex){
ex.printStackTrace();
Log.i("NullPointerException", "error");
return result;
}
result = new mListAdapter(title, mData);
return result;
}
getJSONData:
public InputStream getJSONData(String url) throws NullPointerException{
InputStream data = null;
try {
HttpGet httpget = new HttpGet(url);
HttpResponse response = httpclient.execute(httpget);
data = response.getEntity().getContent();
//if (response.getEntity().getContent().getStatus()==404) return null, for example
} catch (Exception e) {
e.printStackTrace();
return null;
}
return data;
}
And set Adapter to ListView:
if (adapter!=null) IWatchList.setAdapter(adapter); else IWatchList.setEmptyView(new TextView(this));
I don't like this method, because:
- I came up it.
- First two methods universal, therefore each adapter need describe like third method, this is not comfortably. On the other hand how else to define the adapter is empty or not! Only if check it.
Please, your pros and cons, proposal and tips how better and why.

Categories

Resources