setText from a parsed JSON object with AsyncTask [duplicate] - android

This question already has answers here:
AsyncTask Android example
(21 answers)
Closed 9 years ago.
Im making an android program that parses JSON texts from a source code of a webpage in the internet. It is working in android 2.2 but I need it now to be on android 3.0, which needs to be on the AsyncTask. I have a background about AsyncTask but I'm so confused where to put this and that. Thanks in advance everyone :)
Here is my method in the MainActivity class:
private void jsonStuffs() {
//JSON PARSER & HOME PAGE TEXTVIEWS
client = new DefaultHttpClient();
GetMethodEx test = new GetMethodEx();
String returned;
try {
returned = test.getInternetData();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try{
String jsonStr = test.getInternetData(); //go to GetMethodEx
JSONObject obj = new JSONObject(jsonStr);
//////////////////////find temperature in the JSON in the webpage
String temperature = obj.getString("temperature");
TextView tvTemp = (TextView)findViewById(R.id.textView);
tvTemp.setText(temperature);
}
//catch (JSONException e) {
// e.printStackTrace();
//}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The GetMethodEx class is this (this will find the link of the webpage then convert it's source code to text format):
public class GetMethodEx extends Activity {
public String getInternetData() throws Exception{
BufferedReader in = null;
String data = null;
//
try{
HttpClient client = new DefaultHttpClient();
URI website = new URI("http://nhjkv.comuf.com/json_only.php");
HttpGet request = new HttpGet();
request.setURI(website);
HttpResponse response = client.execute(request);
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String l = "";
String nl = System.getProperty("line.separator");
while ((l = in.readLine()) !=null){
sb.append(l + nl);
}
in.close();
data = sb.toString();
return data;
}finally {
if (in !=null){
try{
in.close();
return data;
} catch (Exception e){
e.printStackTrace();
}
}
}
}
}

You can do something like this (this code is just for illustration, change it as needed)
class MyAsyncTask extends AsyncTask<String, Void, JSONObject> {
protected void onPreExecute() {
// You can set your activity to show busy indicator
//setProgressBarIndeterminateVisibility(true);
}
protected JSONObject doInBackground(String... args) {
return jsonStuffs();
}
protected void onPostExecute(final JSONObject jsonObj) {
String temperature = jsonObj.getString("temperature");
TextView tvTemp = (TextView)findViewById(R.id.textView);
tvTemp.setText(temperature);
// Stop busy indicator
//setProgressBarIndeterminateVisibility(false);
}
To call this task use new MyAsyncTask().execute(); (you can pass String parameters to execute if needed)
You can change your jsonStuffs() to return JSONObject
e.g.
private JSONObject jsonStuffs() {
// ...
String jsonStr = test.getInternetData(); //go to GetMethodEx
return new JSONObject(jsonStr);
// ...
}

It is working in android 2.2 but I need it now to be on android 3.0,
which needs to be on the AsyncTask.
=> Yes it gives NetworkOnMainThreadException in 3.0 if you make web call without implementing inside Thread such as AsyncTask.
I have a background about AsyncTask but I'm so confused where to put
this and that.
=> Simply include web call logic inside doInBackground() method of the AsyncTask, in your case call getInternetData() inside doInBackground().
FYI, you can't update UI straight way while doing long running task inside the doInBackground(). Yes if you want to update UI then do follow any of the below:
Update UI from the onPostExecute() method.
or implement runOnUiThread() inside the doInBackround()

Related

AsyncTask give lag for the task

My project is to get data from database to my listview in my project. It get data but when I close and run the application more than one time it gives lag(the data is hidden but when I scroll the list view it show out)
my code is
private class SendfeedbackJob extends AsyncTask<String, Void, String> {
String page="";
protected String doInBackground(String...params) {
// do above Server call here
BufferedReader in = null;
try {
HttpClient client = new DefaultHttpClient();
HttpPost request = new HttpPost(
"http://192.168.43.16/marche/category_display.php");
HttpResponse response = client.execute(request);
in = new BufferedReader(
new InputStreamReader(
response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String line = "";
String NL = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
sb.append(line + NL);
}
in.close();
page = sb.toString();
String [] s= page.split(System.getProperty("line.separator"));
for(int i=0;i<s.length;i++){
Cat_Name[i]=s[i];
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return page;
}
#Override
protected void onPostExecute(String message) {
//process message
Log.d("MyAsyncTask", "Received result: " + message);
}
}
and the on the oncreate method
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
SendfeedbackJob pro=new SendfeedbackJob();
pro.execute();
}
The data is hidden. because, obviously you are not waiting until doInBackground to finish processing before you refresh the adapter (Cats array is still empty). when you scroll down few seconds later the list view will ask the adapter for the data in the bottom cells and scrolling up before the list view asks for the top cells and they just get displayed.
You must set your adapter or calling notifyDataSetChanged in
onPostExecute method.
Call notifydatasetchanged method in the UI thread after fetching all the data
While fetching the data show progress bar to avoid some bad UI experience if the process takes a lot of time

How to implement long-running network uploads in Android not using AsyncTask and not using libraries

What is the native Android way to implement long running network operations (like uploading a bunch of photos) without having to use libraries like RoboSpice?
I've read numerous topics on stackoverflow suggesting that asynctask is not suitable for long running operations as it is closely tied to an activity's lifecycle, might lead to memory leaks and since android 3.2 there is only one thread for all asynctasks for an app. (not sure about this last one)
How do I replace my asynctask with something else?
Now, I've heard of handlers, executors, services and what not, but how exactly do I implement them in my code and which one to choose?
Here is an example of the asynctask I use
I have removed a lot of code, just so you can see the basic structure
public class UploadPhotosToServer extends AsyncTask<String, Void, Boolean> {
#Override
protected Boolean doInBackground(String... args) {
HashMap<String, String> params = new HashMap<String, String>();
try {
if(uploadImageToServer(id, path, params)) {
success = true;
} else {
success = false;
}
} catch (Exception e) {
e.printStackTrace();
success = false;
}
return success;
}
public boolean uploadImageToServer(int imageId, String imagePath, HashMap<String, String> params) throws Exception {
try {
JSONObject json = jsonParser.uploadImageToServer(imagePath, params);
JSONObject message = json.getJSONObject("message");
String serverResponse = message.getString("success");
if (serverResponse.contentEquals("true") {
return true;
} else {
return false;
}
} catch (JSONException e) {
e.printStackTrace();
return false;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
and here is jsonParser.uploadImageToServer
public JSONObject uploadImageToServer(String imagePath, HashMap<String, String> params) throws Exception {
HttpResponse response;
MultipartEntityBuilder multipartEntity;
HttpPost postRequest;
HttpContext localContext;
Bitmap bitmap;
try {
// Set the http handlers
httpClient = new DefaultHttpClient();
localContext = new BasicHttpContext();
postRequest = new HttpPost(SERVER + "images");
// Send the package
multipartEntity = MultipartEntityBuilder.create();
multipartEntity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
multipartEntity.addPart("file", new FileBody(new File(imagePath)));
for (Map.Entry<String, String> entry : params.entrySet()) {
multipartEntity.addTextBody(entry.getKey(), entry.getValue());
}
postRequest.setEntity(multipartEntity.build());
// Get the response. we will deal with it in onPostExecute.
response = httpClient.execute(postRequest, localContext);
HttpEntity httpEntity = response.getEntity();
inputStream = httpEntity.getContent();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
json = sb.toString();
inputStream.close();
reader.close();
} catch (ClientProtocolException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
// Try parsing the string to a JSON object
try {
jsonObject = new JSONObject(json);
} catch (JSONException e) {
e.printStackTrace();
}
// Return JSON String
return jsonObject;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
I think for a set of uploads I would consider implementing an IntentService. As explained at the link it will process a list of intents in a worker thread until that list is exhausted at which point the service will shutdown again.
The implementation of an IntentService is very simple. An example based on the example you give above;
public class ImageUploadIntentService extends IntentService {
public ImageUploadIntentService() {
super("ImageUploadIntentService");
}
#Override
public void onCreate() {
// Not a required implementation but you might want to setup any dependencies
// here that can be reused with each intent that the service is about to
// receive.
super.onCreate();
}
#Override
public void onHandleIntent(Intent intent) {
// Process your intent, this presumably will include data such as the local
// path of the image that you want to upload.
try {
uploadImageToServer(intent.getExtra("image_to_upload"), params);
} catch (Exception e) {
// Oh :( Consider updating any internal state here so we know the state
// of play for later
}
}
public JSONObject uploadImageToServer(String imagePath, HashMap<String, String> params) throws Exception {
// All of your upload code
}
}
Then to call the service it is as simple as;
Intent intent = new Intent(this, ImageUploadIntentService.class)
.putExtra("image_to_upload", mImagePath);
startService(intent);
This does leave us with the issue of indicating the progress of your upload queue. We can solve this by using a ResultReceiver. A result receiver is Parcelable so we can send it with the intent in order to listen out for results we might be interested in. You can handle the ResultReceiver with either an Activity and suitable piece of progress dialog, or if you want a persistent notification with a progress bar then you could use a Service to host the receiver.
It is a little more involved than using an AsyncTask, but it does give you a little more flexibility and is not as attached to the Activity lifecycle. Another gotcha with the IntentService it will still only make you one worker thread so image uploads could not happen concurrently. But I might consider breaking your Bitmap JPEG compression to it's own IntentService then you could have the compression happening on the next image in the queue while the first is being uploaded.

Android - communicate with the backend

I'm learning android by working on a simple project. I have the layout completed and I'm at a point where I need to communicate with the back-end. I've worked with PHP/JSON a lot before and I know exactly what I need to do on the back-end. I have the following two questions,
1 - What kind of adapter I should be using when dealing with JSON? please note that the back-end will be sending 10 records at a time, and the user will scroll up to get the next 10 so the dataset will be changing as the user scrolls the view
2 - I'll be using HTTP to get the JSON data mentioned in point 1, is there a preferred method in android to be used for communication with the back-end?
Please note that I don't want to Parse or any other cloud solutions.
1. You will have to have a something which will communicate with the server for that just copy this code :-
public class ConnectionClass
{
Context context;
public ConnectionClass(Context ctx) {
this.context=ctx;
}
public String connectToServer(String urlLink)
{
try
{
HttpClient client = new DefaultHttpClient();
HttpPost http_get = new HttpPost(urlLink);
HttpResponse responses;
responses = client.execute(http_get);
if (responses != null)
{
InputStream in = responses.getEntity().getContent();
String a = convertStreamToString(in);
return a;
}
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try
{
while ((line = reader.readLine()) != null)
{
sb.append(line);
}
}
catch (Exception e)
{
//Toast.makeText(context, e.toString()+" io2", Toast.LENGTH_LONG).show();
}
finally
{
try
{
is.close();
}
catch (Exception e)
{
}
}
return sb.toString();
}
}
2. To use that and keeping in mind dat newer version of android does not allow executing network operations on mainthread i will give a simple example to run on onCreate() of the activity using AsyncTask this is something like Ajax in web .
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
context=this;
ConnectionClass cc=new ConnectionClass(context);
new AsyncTask<String, Void, String>()
{
#Override
protected String doInBackground(String... arg) {
String data=cc.connectToServer(arg[0]);
return data;
}
protected void onPostExecute(String result)
{
super.onPostExecute(result);
try
{
JSONObject jobj=new JSONObject(result);
String idval=jobj.getString("id");
Toast.makeToast(context,idval,2000).show();
} catch (Exception e)
{
e.printStackTrace();
}
}
}.execute("http://mydomain.com/fetchjson.php");
}
Android has built-in JSON parsing capability and an Http client. Take a look at this stackoverflow post, which has step-by-step instructions for making the Http request and parsing the returned JSON data:
How to parse JSON in Android
However, this post uses the older DefaultHttpClient. This is only recommended for Froyo and below. For newer code, Google recommends that you use HttpURLConnection instead (on Gingerbread and higher API systems). Their function is very similar, here is the reference for Android's HttpURLConnection:
HttpURLConnection | Android Developers

Retrieving data from a website not working (Android)

I use the following class to retrieve data from a website:
public class GetMethodEx {
public String getInternetData() throws Exception {
BufferedReader in = null;
String data = null;
try {
HttpClient client = new DefaultHttpClient();
URI website = new URI("http://www.google.com");
HttpGet request = new HttpGet();
request.setURI(website);
HttpResponse response = client.execute(request);
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String l = "";
String nl = System.getProperty("line.separator");
while ((l = in.readLine()) != null) {
sb.append(l + nl);
}
in.close();
data = sb.toString();
return data;
} finally {
if (in != null) {
try {
in.close();
return data;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
And the following class uses the above class to print the retrieved data on the screen:
public class HttpExample extends Activity {
TextView httpStuff;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.httpex);
httpStuff = (TextView) findViewById(R.id.tvHttp);
GetMethodEx test = new GetMethodEx();
String returnedData = null;
try {
returnedData = test.getInternetData();
httpStuff.setText(returnedData);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I have set the "httpStuff" TextView to "loading..." in the "httpex" xml. Now the problem I am facing is that when I run the app, it is stuck at this "loading..." forever. Any ideas why?
Thanks.
PS: I have added the permission "android.permission.INTERNET" in the manifest.
EDIT: Actually I have a duplicate question which has the correct solution. Anyway, thanks!
Make sure to check LogCat to look for potential error messages. I'm guessing you didn't request the Internet permission in your AndroidManifest.xml.
Add
<uses-permission android:name="android.permission.INTERNET" />
outside the application tag in your AndroidManifest.xml
Edit:
Also, you should avoid running network requests on the UI thread. On later versions of android (Honeycombe and later I believe) you'll get a NetworkOnMainThreadException, which could also cause the issue you're facing.
Try using an AsyncTask to run this request. See the answer here:
How to fix android.os.NetworkOnMainThreadException?

How to Get Specific Information From the Internet In Android App

im pretty new In Android App development, I need some help.
Im creating this simple dictionary application that prompts the user to enter a word and after a button press it will take that word to the internet, probably wikipedia.org and return that information to the User.
I used XML to develop the app textfield and button. And created a piece of text (ansa) which will be set to whatever the answer is using the OnClickListener,
I do not want to set up a webview
I just want the text to be set to the dictionary answer.
Here's what i have been able to do so far. There is this class to get data from google.
public class GetMethod {
public String getInternetData() throws Exception{
BufferedReader in = null;
String data = null;
try{
HttpClient client = new DefaultHttpClient();
URI website = new URI("http://www.google.com");
HttpGet request = new HttpGet();
request.setURI(website);
HttpResponse response = client.execute(request);
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String l = "";
String nl = System.getProperty("line.separator");
while((l = in.readLine()) !=null){
sb.append(l + nl);
}
in.close();
data = sb.toString();
return data;
}finally{
if (in !=null){
try{
in.close();
return data;
}catch(Exception e){
e.printStackTrace();
}
}
}
}
And Another class where the XML is implemented
public class Dictionary extends Activity {
TextView ansa;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dictionary);
Button Search = (Button) findViewById(R.id.search);
ansa = (TextView) findViewById(R.id.ansa);
final GetMethod test = new GetMethod();
Search.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
String returned;
try {
returned = test.getInternetData();
ansa.setText(returned);
} catch (Exception e) {
ansa.setText("Failed");
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
When it executes I get the whole website's HTML
So I need help on how to take the user's word to the wiki website, and get only the text of the ansa, probably parse and store it to some string.
Thank You Alot.
You can use an API like Google Dictionary or dictionary.com.
But you will have to implement the HTTP client and parse the response. And then show the desired data .

Categories

Resources