How to make a blocking Android HttpRequest - android

Here is my issue:
I have a list of values which I retrieve from server.
These values fill ListView in the UI.
I cannot continue loading the View and showing it to user until the list is full.
Since Android forces me to make http calls in separate thread, my question is how do I create 1 class that does the httprequests and in the calling class I wait until I get response from the HttpRequest and only then I proceed loading the View?
Right now I have this class that does the requests:
public class WapConnector extends AsyncTask<String, String, String>{
private static final String TAG = "WapConnector";
private String html = "";
private Handler mHandler;
private String server = "http://....whatever";
private String callUrl = "/api/";
private String params = "login?u=Admin&pw=234234&format=json";
private int _callstate = 1;
#Override
protected String doInBackground(String... uri) {
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
String responseString = null;
try {
String fullUrl = "";
Log.i(TAG,fullUrl);
if(params.length() > 0){
fullUrl = server + callUrl + params + "&alf_ticket=" + Globals.getInstance().getTicket() + "&udid=" + Globals.getInstance().udid() + "&phoneNumber=" + Globals.getInstance().phoneNumber();
}
else{
fullUrl = server + callUrl + "?udid=" + Globals.getInstance().udid() + "&alf_ticket=" + Globals.getInstance().getTicket() + "&phoneNumber=" + Globals.getInstance().phoneNumber();
}
Log.i(TAG,fullUrl);
response = httpclient.execute(new HttpGet(fullUrl));
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == HttpStatus.SC_OK){
ByteArrayOutputStream out = new ByteArrayOutputStream();
response.getEntity().writeTo(out);
out.close();
responseString = out.toString();
Log.i(TAG,responseString);
} else{
//Closes the connection.
response.getEntity().getContent().close();
throw new IOException(statusLine.getReasonPhrase());
}
} catch (ClientProtocolException e) {
e.printStackTrace();
//TODO Handle problems..
} catch (IOException e) {
//TODO Handle problems..
e.printStackTrace();
}
return responseString;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Log.i(TAG + "onPostExecute",result);
activity.getClass().handleResponse();
//main load
JSONObject jobj;
JSONObject jvalue;
try {
jobj = new JSONObject(result);
if(_callstate == 1){
jvalue = jobj.getJSONObject("data");
String ticket = jvalue.getString("ticket");
Log.i("loginwap",ticket);
Globals.getInstance().setTicket(ticket);
_callstate = 2;
}
else{
jvalue = jobj.getJSONObject("countries");
JSONArray countries = jvalue.getJSONArray("countries");
}
}
catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
And this is how I make calls from Parent classes:
WapConnector wap = new WapConnector();
wap.setCallUrl("/anyurl/");
wap.callstate(3);
wap.setParams("");
wap.execute("");
Now my issue is that since the request runs in thread, once I call wap.execute(), my Activity continues to load, but I want it to wait until I get response, parse the response and only then continue to load.
thanks everyone for replies.!!!

Pass in a context to your class from the activity you are calling it from. Overload the onPreExecute() to show a ProgressDialog and then overload onPostExecute() to hide the ProgressDialog. This gives you blocking while letting the user you are loading.
There is a kinda hacky way to get more control. If you want to keep the AsyncTask as a separate class but allow it to update UI elements in another Activity, define a Handler in that Activity and then pass it in the constructor of the the AsyncTask. You can then send a message in the onPostExecute() method of your AsyncTask to the handler to tell it to update the UI. You will need to make sure the handler is properly handling the message your AsyncTask is sending back. Could be a little cleaner, but it works and will allow you to reuse an asyncTask that makes a network call across activities.

Related

Checking the AsyncTask status seems not working correctly (log doesn't appear on log cat)

I'm trying to see how works an Asynctask class in android. In particular i want reveal in real time the status of the class for see when it is running and when it has finished. For do this, i have created a class that extend the main activity and another class that is the asynctaks class.
This is my main class:
public class PhotoManagement extends Activity{
private String numberOfSelectedPhotos;
private Bitmap currentImage;
private String initConfiguration = "http://www.something.com";
private String response;
private ArrayList<String> formatPhotoList = new ArrayList<String>(); //create a list that will contains the available format of the photos downloaded from the server
private ArrayList<String> pricePhotoList = new ArrayList<String>(); //create a list that will contains the available price for each format of the photos
DownloadWebPageTask webPage = new DownloadWebPageTask();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
protected void onResume(){
super.onResume();
webPage.execute(initConfiguration);
if(webPage.getStatus() == AsyncTask.Status.PENDING){
Log.i("STATUS","PENDING");
}
if(webPage.getStatus() == AsyncTask.Status.RUNNING){
Log.i("","RUNNING");
}
if(webPage.getStatus() == AsyncTask.Status.FINISHED){
Log.i("","FINISHED");
}
}
}
As you can see i want only see the passages of the status with a simple log.
And here there is the asynctask class.
private class DownloadWebPageTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient(); //create a new http client
HttpGet httpGet = new HttpGet(url); //create a new http request passing a valid url
try {
HttpResponse execute = client.execute(httpGet); //try to execute the http get request
InputStream content = execute.getEntity().getContent(); //prepare the input stream to read the bytes of the request
BufferedReader buffer = new BufferedReader(
new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s; //until is present a line to read, the response variable store the value of the lines
}
} catch (Exception e) {
Log.i("MyApp", "Download Exception : " + e.toString()); //Print the error if something goes wrong
}
}
return response; //return the response
}
#Override
protected void onPostExecute(String result) {
result = doInBackground(initConfiguration); //take the result from the DownloadWebPageTask class
result = result.replace("null", "");
Log.i("RESULT",""+result);
//find the price and format value from the result using XmlPullParser
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput( new StringReader ( result ) );
int attributeNumber = xpp.getAttributeCount();
int eventType = xpp.getEventType();
String currentTag = null;
while(eventType != XmlPullParser.END_DOCUMENT){
if(eventType == XmlPullParser.START_TAG) {
currentTag = xpp.getName();
if (currentTag.equals("product")){
xpp.getAttributeValue(null, "name");
formatPhotoList.add(xpp.getAttributeValue(null, "name"));
Log.i("FORMAT PHOTO",""+xpp.getAttributeValue(null, "name"));
}
}
eventType = xpp.next();
}
} catch (XmlPullParserException e) {
e.printStackTrace();
Log.i("","ERROR XML PULL PARSER");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.i("","ERROR IOEXCEPTION");
}
}
}
}
As you can see i have implemented also the method onPostExecute that should be called when the asynctask method has finished to execute the instructions right?
So at this point i don't understand why my log RUNNING and my log FINISHED never appear on the log cat.
What i'm doing wrong?
I'm tried to follow this topic Android, AsyncTask, check status? but in my case it isn't working.
Thanks
Problem :
You are creating object like
DownloadWebPageTask webPage = new DownloadWebPageTask();
But you are calling asynctask on different object,
new DownloadWebPageTask().execute(initConfiguration);
Solution :
It should be like
webPage.execute(initConfiguration);
#Override
protected void onResume(){
super.onResume();
new DownloadWebPageTask().execute(initConfiguration);
here do like this
#Override
protected void onResume(){
super.onResume();
webPage.execute(initConfiguration);
You didn't implement webPage.execute(), add it
Most probably the task hasn't finished or even started yet. As you probably know the AsyncTask is doing it's (background) work on a different thread, so your onResume is running in parallel with it. You can either use the task's get() method to wait for it to finish and get the result of the doInBackground() method and then query for it's status or notify your activity from the task's onPostExecute() method to let it know (and log) that it has finished. I don't recommend you the first option because it will actually block the UI thread and will make your usage of AsyncTask pointless.

Multiple Async Tasks for post in same activity

i wrote those threads:
How to manage multiple Async Tasks efficiently in Android
Running multiple AsyncTasks at the same time -- not possible?
but didnt find answer for my question, maybe someone can help..
I have android app which makes Login POST and getting json response,
if the Json is OK i need to POST another data to get another response.
i have extends Async Class which doing the post to the URL:
public class AsyncHttpPost extends AsyncTask<String, String, String> {
private HashMap<String, String> mData = null;
public AsyncHttpPost(HashMap<String, String> data) {
mData = data;
}
#Override
protected String doInBackground(String... params) {
byte[] result = null;
String str = "";
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(params[0]);// in this case, params[0] is URL
try {
ArrayList<NameValuePair> nameValuePair = new ArrayList<NameValuePair>();
Iterator<String> it = mData.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
nameValuePair.add(new BasicNameValuePair(key, mData.get(key)));
}
post.setEntity(new UrlEncodedFormEntity(nameValuePair, "UTF-8"));
HttpResponse response = client.execute(post);
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == HttpURLConnection.HTTP_OK){
result = EntityUtils.toByteArray(response.getEntity());
str = new String(result, "UTF-8");
}
}
catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
catch (Exception e) {
return null;
}
return str;
}
#Override
protected void onPostExecute(String result) {
try {
JSONArray Loginjson = new JSONArray(result);
strStt = Loginjson.getJSONObject(0).getJSONObject("fields").getString("status");
if (strStt.equals("ERR")) {
ErrorMsg("Authentication failed");
} else if (strStt.equals("OK")) {
ErrorMsg("Login OK!!!");
ClientPage();
} else {
ErrorMsg("Connection Error");
}
} catch (JSONException e) {
ErrorMsg("Connection Error");
}
}
}
Now - i need to get another POST if the status is Error. do i need to make another Async class? with the same all procedures ? the issue is only the onPostExecute part is different.. actually the "doInBackground" will be always the same..
any idea how can i easily do multiple posts in the same activity?
Firstly, since your doInBackground() code will always stay the same, I recommend you move it into a general utility class.
Beyond that, you can go one of two ways:
Create a new AsyncTask for each type of request that can call your utility class, and have its own onPostExecute()
Create one AsyncTask that has a flag in it, which can be checked in the onPostExecute() method to see what code needs to be executed there. You will have to pass the flag in in the constructor or as a parameter in execute.
You can use a parameter at AsyncHttpPost constructor/execute or global variable to indicate if it is first or second POST (by other words - a flag). Then just create and execute another instance of AsyncHttpPost in onPostExecute (only if parameter/variable is set as "first POST").

App needs to get JSON and display it. How to do it using async thread?

As mentioned I get the above error which I know is because my application is doing networking in UI thread. I went through a lot of stackoverflow questions which advise to use AsyncTask for this purpose. From what I understand asynctask is asynchronous and will run independently in the background. But I need to fetch the data from http and display on the main thread. So basically my UI thread should be blocked till I have the JSON fetched so that I can display it.
My questions are
1) Since I need to run http networking in another thread how do I do it?
2) Do I use an async thread?
3) How do I block my UI thread for the async thread to fetch the result?
4) How do I pass the result from async thread back to UI thread?
This is the current JSON parser class that I use.
public class JSONParser {
static InputStream is = null;
static JSONObject jObj = null;
static String json = "";
// constructor
public JSONParser() {
}
public JSONArray getJSONfromURL(String url) {
// initialize
InputStream is = null;
String result = "";
JSONArray jArray = null;
// http post
try {
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
HttpResponse response = httpclient.execute(httpGet);
HttpEntity entity = response.getEntity();
is = entity.getContent();
} catch (Exception e) {
Log.e("log_tag", "Error in http connection " + e.toString());
return null;
}
// convert response to string
try{
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
result = sb.toString();
Log.e("log_tag", "JSON data" + result);
} catch (Exception e) {
Log.e("log_tag", "Error converting result " + e.toString());
return null;
}
// try parse the string to a JSON object
try {
jArray = new JSONArray(result);
} catch (JSONException e) {
Log.e("log_tag", "Error parsing data " + e.toString());
return null;
}
return jArray;
}
}
And this is my MainActivity where I call JSONparser to fetch some data that I need to display
JSONArray json = jParser.getJSONfromURL(temp);
if (json == null) {
return -1;
}
for (int i = 0; i < json.length(); i++) {
try {
JSONObject c = json.getJSONObject(i);
// Getting Array of Contacts
// Storing each json item in variable
asr_iq = c.getString("lMAsr");
sunrise_iq = c.getString("lMSunrise");
fajr_iq = c.getString("lMFajr");
isha_iq = c.getString("lMIsha");
dhuhr_iq = c.getString("lMDhuhr");
maghrib_iq = c.getString("lMMaghrib");
} catch (JSONException e) {
e.printStackTrace();
}
}
Load your asynctask on the UI thread.
If you cannot do any network related operation on the UI Thread Honeycomb and later. You will get a NetworkOnMainThread Exception.
new MyTask(url).execute();// can pass parameter to class constructor
// can also pass url to doInBackground.
Async task
class MyTask extends AsyncTask<Void,Void,Void>
{
String url;
public MyTask(String url)
{
this.url =url
}
#Override
protected Void doInBackground(Void... params) {
// all your network related operation
// invoked on the background thread
// all code from getJSONfromURL(param)
// do not update ui here
return null;
}
#Override
protected void onPostExecute(Void result) { // invoked on the ui thread
// TODO Auto-generated method stub
super.onPostExecute(result);
// dismiss progress dialog
// update ui here
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
// display progress dialog
}
#Override
protected void onProgressUpdate(Void... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
}
}
Detailed information # http://developer.android.com/reference/android/os/AsyncTask.html
Edit:
Use a Handler. Return result in doInBaCkground().
Example in onPostExecute()
Message msg=new Message();
msg.obj=result.getProperty(0).toString();
mHandler.sendMessage(msg);
In your activity onCreate()
Handler mHandler = new Handler() {
#Override public void handleMessage(Message msg) {
//ArrayList s=(ArrayList)msg.obj;
SoapObject s =(SoapObject) msg.obj;
tv.setText("Result = "+s.toString());
}
};
You can also use runonuithread to update ui from doInBackGround()
runOnUiThread(new Runnable() //run on ui thread
{
public void run()
{
_tv.setText("update from doinbackground");
}
});
Using Core Java,
Have your getJson execution logic in a Runnable/Callable(Java concurrency class), submit it via executors so that its an Asynch call.
Then with in your Runnable/Callable once json is retrived call the class which will have logic to display the json, this clas can be designed as a listener and you may publish an even after getting json response

Passing functions into a global AsyncTask Android

I'm trying to create a global actions file in which i can call certain functions globally anywhere within the app. so far i have got it working with functions etc but now what i'm wanting to do is put a standard AsyncTask into my global actions and pass it functions/voids from my Activity so i'd want to pass it a function to run in background and a function to run once finished. does anyone know how do this? and also advise me on running multiple functions on a background thread do i create one AsyncTask and feed in multiple functions or do i create multiple AsyncTasks?
heres an example of what i have managed to do globally so far and how i'm currently implementing my Asynctask. Just to reiterate i'm trying to move the asynctask into a global actions and make it as reusuable as possible
in my Global Actions im creating a function that formulates a URL and sends post variables to that url which then feedsback a JSON response. then in my Activity i have created a function to both call that request and then Log the response
My Global Actions
public final static JSONObject startAPICallRequest(Context activityContext, String requestReference, String callLocation, Map<String, String> postVarsMap, Map<String, String> getVarsMap){
long unixTimeStamp = System.currentTimeMillis() / 1000L;
StringBuilder extraGetVarsString = new StringBuilder();
if(getVarsMap != null){
Map<String, String> map = (Map)getVarsMap;
for (Entry<String, String> entry : map.entrySet()) {
extraGetVarsString.append("&" + entry.getKey() + "=" + entry.getValue());
extraGetVarsString.toString();
}
}
String appVersion = null;
try {
appVersion = activityContext.getPackageManager().getPackageInfo(activityContext.getPackageName(), 0).versionName;
} catch (NameNotFoundException e) {
e.printStackTrace();
appVersion = activityContext.getResources().getString(R.string.appVersion);
}
String getVarsString = "?timestamp=" + unixTimeStamp + "&app_version=" + appVersion + extraGetVarsString;
String apiLocation = activityContext.getResources().getString(R.string.apiLocation);
String fullAPIURL = apiLocation + callLocation + getVarsString;
Log.v("globals", "fullAPIURL=" + fullAPIURL);
String api_key = activityContext.getResources().getString(R.string.apiKey);
String api_user = activityContext.getResources().getString(R.string.apiUser);
String request_token = returnSHAFromString(api_key, fullAPIURL);
String device_id = returnStringFromPreference(activityContext,"device_id");
String user_token = returnStringFromPreference(activityContext,"user_token");
List<NameValuePair> postVarsList = new ArrayList<NameValuePair>();
postVarsList.add(new BasicNameValuePair("request_token", request_token));
postVarsList.add(new BasicNameValuePair("api_user", api_user));
postVarsList.add(new BasicNameValuePair("device_id", device_id));
postVarsList.add(new BasicNameValuePair("user_token", user_token));
if(postVarsMap != null){
Map<String, String> map = (Map)postVarsMap;
for (Entry<String, String> entry : map.entrySet()) {
postVarsList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
}
JSONObject responseJSON = null;
try {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(fullAPIURL);
post.setEntity (new UrlEncodedFormEntity(postVarsList));
HttpResponse response = client.execute(post);
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
String jsonResponse = reader.readLine();
Log.v("globals", "postList =" + postVarsList );
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return responseJSON;
}
MY Activity
public void apiCall(){
responseJSON = GlobalActions.startAPICallRequest(this, "login", "my-network/", null, null);
}
public class PostTask extends AsyncTask<Void, String, Boolean> {
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(Void... params) {
apiCall();
boolean result = false;
publishProgress("progress");
return result;
}
protected void onProgressUpdate(String... progress) {
StringBuilder str = new StringBuilder();
for (int i = 1; i < progress.length; i++) {
str.append(progress[i] + " ");
}
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
checkLoginData();
}
}
public void checkLoginData(){
Log.v("IntroLoader", "responseJSON = " + responseJSON);
Intent register = new Intent(getApplicationContext(), LoginForm.class);
startActivity(register);
}
Using AsyncTask for calling REST API methods is not really correct approach. Your code has 2 problems:
There is no guarantee that your API call will be finished when Activity is closed because process can be killed
You have memory leak because PostTask can hold Activity reference even while Activity can be already destroyed
Consider using IntentService for making background requests and e. g. ResultReceiver for handling results in your Activity.
It looks like you need a Handler and a Looper. You will be able to post() and postDelayed(). http://developer.android.com/reference/android/os/Handler.html
See also:
Is AsyncTask really conceptually flawed or am I just missing something?
I'm no Java expert but I don't think you pass functions around in Java. To simplify the matter, what you want to do is call a function in your Activity class when AsyncTask is complete?

How to call a URL in background using Android?

I am looking to insert userdata to database by calling URL link to webservice on server:
ex:
this is the link:
http://mydomain.com/AndroidWebService.asmx/nInsertInfo?id=12&lat=23.2222&log=12322
So I want to call this url in hidden mode.
Use android android AsyncTask to post data. It work in android background when application is open.
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
Like
AsyncTask
AsyncTask
AsyncTask
Thanks.
Thanks all for your valuable solutions.
i have did it by creating WebView
WebView myWebView = (WebView) findViewById(R.id.view1);
myWebView.loadUrl(urll);
then i can manage my WebView as i want: hide it, alignment as error or result returns.
Maybe this example will help you :
public class URLConnectionTask <Result> extends AsyncTask<URL, Void, InputStream> {
#Override
protected InputStream doInBackground(URL... params) {
InputStream is;
HttpUriRequest request;
URI uri;
HttpResponse response;
if (params.length == 0)
return null;
is = null;CredentialsProvider credProvider = new BasicCredentialsProvider();
if (userName != null && userName.length() > 0 && password != null && password.length() > 0)
credProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
new UsernamePasswordCredentials(userName, password));
//
DefaultHttpClient http = new DefaultHttpClient();
http.setCredentialsProvider(credProvider);
//
uri = URI.create(params[0].toString());
if (isPost)
request = new HttpPost(uri);
else
request = new HttpGet(uri);
try {
response = http.execute(request);
is = response.getEntity().getContent();
//Log.d(TAG, "doInBackground() response: "+EntityUtils.toString(response.getEntity()));
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if (processingHandler != null && is != null)
processingResult = processingHandler.processResponse(is);// processingHandler is an instance which implements ProcessingHandler interface (ex. VizMarket). processResponse() is implemented on this class.
return is;
}
#Override
protected void onPostExecute (InputStream result) {
input = result;
if (result == null)
return;
//instruction for inserting data on db ....
try {
result.close();
} catch (IOException e) {
}
}
}
You should call URL in AsyncTask. For instance: Return data from AsyncTask class
U have to use a thread to fetch data from server and insert into to DB or in android you can use AsyncTask.
You can have a search :ClickableSpan
And put your insert code into the OnClick body~
Just like:
String yourTextStr;
SpannableString sp = new SpannableString(yourTextStr);
int start;//the start of your url in the text;
int end ;//the end of your url in the text;
sp.setSpan(new ClickableSpan() {
#Override
public void onClick(View widget) {
//Your Insert Code
}
}, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

Categories

Resources