android code doesn't work when I added threads - android

I am writing an android application, I previously had a problem NetworkOnMainThreadException and I solved using threads. I now don't get any error and also I don't get any output.
here is my code: there is no errors in the LogCat
public class Currency_convert extends Activity {
public int to;
public int from;
public String [] val;
public String s;
public Handler handler;
public double am=0.0;
StringBuilder build=null ;
HttpClient client=null;
HttpGet httpGet =null;
HttpResponse response=null;
HttpEntity entity=null;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.currency);
Spinner s1 = (Spinner) findViewById(R.id.spinner11);
Spinner s2 = (Spinner) findViewById(R.id.spinner22);
final EditText e=(EditText) findViewById(R.id.amountt);
// am=Double.parseDouble(e.getText().toString());
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this, R.array.name, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.select_dialog_singlechoice);
val = getResources().getStringArray(R.array.value);
s1.setAdapter(adapter);
s2.setAdapter(adapter);
s1.setOnItemSelectedListener(new spinOne(1));
s2.setOnItemSelectedListener(new spinOne(2));
Button b = (Button) findViewById(R.id.button11);
b.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
TextView t = (TextView) findViewById(R.id.textView44);
if(from == to) {
Toast.makeText(getApplicationContext(), "Invalid", 4000).show();
}
else {
try {
s = getJson("http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.xchange%20where%20pair%20in%20(%22"+val[from]+val[to]+"%22)&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=");
//s=getJson("http://www.google.com/ig/calculator?hl=en&q=1USD=?INR");
JSONObject jObj;
jObj = new JSONObject(s);
String exResult = jObj.getJSONObject("query").getJSONObject("results").getJSONObject("rate").getString("Rate");
am=Double.parseDouble(e.getText().toString());
double totalR=(Double.parseDouble(exResult))*am;
String r=String.valueOf(totalR);
t.setText(r);
// Log.println(priority, tag, msg)
System.out.println("r =" +r);
Log.i("hello", r);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
}
public String getJson(final String url)throws ClientProtocolException, IOException {
// private String getJson(String url)throws ClientProtocolException, IOException e {
build = new StringBuilder();
client = new DefaultHttpClient();
httpGet = new HttpGet(url);
new Thread(new Runnable() {
public void run() {
try {
response = client.execute(httpGet);
entity = response.getEntity();
InputStream content = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(content));
String con;
while ((con = reader.readLine()) != null) {
build.append(con);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
// response = client.execute(httpGet);
// entity = response.getEntity();
// InputStream content = entity.getContent();
// BufferedReader reader = new BufferedReader(new InputStreamReader(content));
// String con;
// while ((con = reader.readLine()) != null) {
// build.append(con);
// }
return build.toString();
//return url;
}
private class SpinOne implements OnItemSelectedListener {
int ide;
SpinOne(int i) {
ide =i;
}
public void onItemSelected(AdapterView<?> parent, View view,
int index, long id) {
if(ide == 1) {
from = index;
}
else if(ide == 2) {
to = index;
}
}
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
}}

The way it is written, getJson() will return immediately without giving time for the thread to run completely, so the returned value will not be what you want. Use an AsyncTask so you can run your thread code in the AsyncTask's doInBackground() method and then pass the result to the onPostExecute() method where you can then perform setText() as you intend.
An alternative is to move the JSON parsing and setText() code into the thread's run() method after the HTTP request is made but since running UI-related code (in this case setText()) in a separate thread is not allowed you can use a Handler to schedule setText() to run in the UI thread.
You can read the basics on AsyncTask and Handler here.

When you spawn a thread, code execution splits into different time frames, so even though global scope is shared, you won't get objects populated in a timely fashion for your UI update task if you don't implement some logic to prevent inconsistencies.
Android provides multiple flow control and inter-thread communication patterns built-in that can help you solve such inconsistencies. One such option involves AsyncTask, in your case you can do the following:
Extended AsyncTask with your UI thread-forbidden tasks inside the doInBackground() method;
Get logic that needs to run on UI thread (such as manipulating Views) inside onPostExecute() handler from the same AsyncTask instance. This handler will only be called after doInBackground returns, so the program knows that the logic to populate the object was triggered.
You can look up a sample of AsyncTask in this answear for a practical approach.
Note: If you want to use parent class members such as findViewByID inside an AsyncTask instance, you will need to manually invoke the parent file scope using the <UIThreadName>.this., e.g. <UIThreadName>.this.findViewByID(id). You can do this freely in onPostExecute which has no restrictions due to running on the UI thread, but you are restricted to not performing UI changes in doInBackground (which doesn't run on the UI thread).

I solved it, I just added t.join after the thread declaration :)

Related

Code doesn't execute HttpResponse for second time when called twice

I'm doing and app who calls the same method two times and the second time I call the method it doesn't execute the line with HttResponse.
Here is the AsyncTask where everything starts:
private class FetchSubjectsTask extends AsyncTask<String, Void, List<Subject>> {
private ProgressDialog pd;
#Override
protected List<Subject> doInBackground(String... params) {
List<Subject> subjects = null;
try {
subjects = api.getMySubjects(params[0]);
} catch (Exception e) {
e.printStackTrace();
}
return subjects;
}
#Override
protected void onPostExecute(List<Subject> result) {
printSubjects(result);
if (pd != null) {
pd.dismiss();
}
}
}
Then I get the subjects through the method getMySubjects which is:
public List<Subject> getMySubjects(String username) {
List<Subject> subjects = new ArrayList<Subject>();
java.lang.reflect.Type arrayListType = new TypeToken<ArrayList<Subject>>() {
}.getType();
String url = BASE_URL_VM + "users/" + username + "/subjects";
HttpClient httpClient = WebServiceUtils.getHttpClient();
try {
System.out.println("inside try");
HttpResponse response = httpClient.execute(new HttpGet(url));
System.out.println("response executed");
HttpEntity entity = response.getEntity();
Reader reader = new InputStreamReader(entity.getContent());
subjects = gson.fromJson(reader, arrayListType);
} catch (Exception e) {
}
System.out.println("Array lenght " +subjects.size());
return subjects;
}
That's the first time HttpResponse executes and I get the "response executed" and "Array lenght 2" which are the number of subjects that user (username) has in the database.
The problem is when in onPostExecute I call the method printSubjects which is:
private void printSubjects(List<Subject> subjects){
adapter = new SubjectAdapter(this,(ArrayList<Subject>)subjects, (String) getIntent().getExtras().get("username"));
setListAdapter(adapter);
adapter.notifyDataSetChanged();
}
This calls the SubjectAdapter which prints the Subjects in a ListView:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder viewHolder = null;
if (convertView == null) {
convertView = inflater.inflate(R.layout.subject_detail, null);
viewHolder = new ViewHolder();
viewHolder.tvsubject = (TextView) convertView
.findViewById(R.id.tvsubject);
boolean match = api.checkMySubjects(username, data.get(position).getId());
Button addButton = (Button) convertView.findViewById(R.id.bAdd);
if(match){
addButton.setText("Delete");
}else{
addButton.setText("Add");
}
String content = data.get(position).getName();
viewHolder.tvsubject.setText(content);
}
return convertView;
}
private static class ViewHolder {
TextView tvsubject;
TextView tvauthor;
}
There I call the method checkMySubjects which calls again getMySubjects to compare.
public boolean checkMySubjects(String username, String id) {
List<Subject> mySubjects = getMySubjects(username);
boolean match = false;
for (Subject s1 : mySubjects) {
if (s1.getId().equals(id)) {
match = true;
}
}
return match;
}
But now the method getMySubjects doesn't arrive until "Response executed" and the Array lenght is 0. It only shows "Inside try".
Why? I'm calling the same method with the same URL but first time I get the 2 subjects in the array and the second time I get nothing because HttResponse doesn't execute.
Thank you!
It's hard to say what's happening, but I'd like to point out what I think it's wrong. First, let's state the fact thatgetMySubjects performs a network operation, now, the first time you call it, it is called from within an AsyncTask on a thread other than the UI thread. This is perfectly fine
Then you call printSubjects in onPostExecute which populates a ListView with the results...
private void printSubjects(List<Subject> subjects){
adapter = new SubjectAdapter(this,(ArrayList<Subject>)subjects, (String) getIntent().getExtras().get("username"));
setListAdapter(adapter);
adapter.notifyDataSetChanged();
}
Now, the problem is in your getView implementation of the adapter. More specifically here...
boolean match = api.checkMySubjects(username, data.get(position).getId());
this is terribly bad because you are making a network connection on the UI thread everytime you inflate a ListView item, so if you had ten items you will be making a network connection ten times (plus everytime you you scroll up and/or down the list).
Moreover, Android complains with a FATAL exception if you attempt to make a network connection on the UI thread. You're not even noticing because you are not doing anything with this exception...
try {
System.out.println("inside try");
HttpResponse response = httpClient.execute(new HttpGet(url));
System.out.println("response executed");
HttpEntity entity = response.getEntity();
Reader reader = new InputStreamReader(entity.getContent());
subjects = gson.fromJson(reader, arrayListType);
} catch (Exception e) {
}
the catch block is empty, if you print it to the LogCat you'll see the details
Suggestion
Don't make a network connection on the UI thread...you can't
On getView instead of making a network connection for every single iteration, eagerly load the data in memory before you set the ListView
Again, the offending line of code is...
boolean match = api.checkMySubjects(username, data.get(position).getId());
in getView

android AsyncTask and UI thread interaction

I'm using the AsyncTask to open a URL, access the server, fetch the content and display them in a list view in the main activity. The content extracted consists of a title of the newspaper and a URL to the website, which will be displayed on a WebView in a second activity, if a "read" button is clicked. I coded out the program straight away and it works, but when I looked back at it, I found something that seems unreasonable, so mainly I want to make clear how the code works. Here is the code for the main activity:
package com.example.newsapp;
public class MainActivity extends Activity {
static final private String LOG_TAG = "main";
private ArrayList<Content> aList;
private class Content{
Content() {};
public String title;
public String url;
}
private class MyAdapter extends ArrayAdapter<Content>{
int resource;
public MyAdapter(Context _context, int _resource, List<Content> titles) {
super(_context, _resource, titles);
resource = _resource;
// this.context = _context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout newView;
final Content content = getItem(position);
// Inflate a new view if necessary.
if (convertView == null) {
newView = new LinearLayout(getContext());
String inflater = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater vi = (LayoutInflater) getContext().getSystemService(inflater);
vi.inflate(resource, newView, true);
} else {
newView = (LinearLayout) convertView;
}
// Fills in the view.
TextView tv = (TextView) newView.findViewById(R.id.listText);
ImageButton b = (ImageButton) newView.findViewById(R.id.listButton);
b.setBackgroundResource(0);
tv.setText(content.title);
Typeface type = Typeface.createFromAsset(getAssets(),"LiberationSerif-BoldItalic.ttf");
tv.setTypeface(type);
// Sets a listener for the button, and a tag for the button as well.
b.setTag(Integer.toString(position));
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Reacts to a button press.
Intent intent = new Intent(MainActivity.this, WebPage.class);
Bundle bundle = new Bundle();
bundle.putString("URL", content.url);
intent.putExtras(bundle);
startActivity(intent);
}
});
return newView;
}
}
class MyAsyncTask extends AsyncTask<String, String, String> {
private ProgressDialog progressDialog = new ProgressDialog(MainActivity.this);
InputStream inputStream = null;
String result = "";
Content content;
protected void onPreExecute() {
super.onPreExecute();
progressDialog.setMessage("Downloading the news...");
progressDialog.show();
progressDialog.setOnCancelListener(new OnCancelListener() {
public void onCancel(DialogInterface arg0) {
MyAsyncTask.this.cancel(true);
}
});
}
#Override
protected String doInBackground(String... params) {
String url_select = params[0];
ArrayList<NameValuePair> param = new ArrayList<NameValuePair>();
try {
// Set up HTTP post
// HttpClient is more then less deprecated. Need to change to URLConnection
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url_select);
httpPost.setEntity(new UrlEncodedFormEntity(param));
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
// Read content & Log
inputStream = httpEntity.getContent();
} catch (UnsupportedEncodingException e1) {
Log.e("UnsupportedEncodingException", e1.toString());
e1.printStackTrace();
} catch (ClientProtocolException e2) {
Log.e("ClientProtocolException", e2.toString());
e2.printStackTrace();
} catch (IllegalStateException e3) {
Log.e("IllegalStateException", e3.toString());
e3.printStackTrace();
} catch (IOException e4) {
Log.e("IOException", e4.toString());
e4.printStackTrace();
}
// Convert response to string using String Builder
try {
BufferedReader bReader = new BufferedReader(new InputStreamReader(inputStream, "iso-8859-1"), 8);
StringBuilder sBuilder = new StringBuilder();
String line = null;
while ((line = bReader.readLine()) != null) {
sBuilder.append(line + "\n");
}
inputStream.close();
result = sBuilder.toString();
} catch (Exception e) {
Log.e("StringBuilding & BufferedReader", "Error converting result " + e.toString());
}
return result;
} // protected Void doInBackground(String... params)
protected void onPostExecute(String result) {
//parse JSON data
try {
super.onPostExecute(result);
Log.i(LOG_TAG, result);
JSONObject object = new JSONObject(result);
JSONArray jArray = object.getJSONArray("sites");
for(int i=0; i < jArray.length(); i++) {
JSONObject jObject = jArray.getJSONObject(i);
content = new Content();
if (jObject.has("title") && jObject.has("url")){
content.title = jObject.getString("title");
content.url = jObject.getString("url");
aList.add(content);
aa.notifyDataSetChanged();
}
} // End Loop
progressDialog.dismiss();
} catch (JSONException e) {
// progressDialog.dismiss();
Log.e("JSONException", "Error: " + e.toString());
}
} // protected void onPostExecute(String result)
}
private MyAdapter aa;
private MyAsyncTask loadTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadTask = new MyAsyncTask();
loadTask.execute("http://luca-ucsc.appspot.com/jsonnews/default/news_sources.json");
aList = new ArrayList<Content>();
aa = new MyAdapter(this, R.layout.list_element, aList);
ListView myListView = (ListView) findViewById(R.id.listView1);
myListView.setAdapter(aa);
aa.notifyDataSetChanged();
}
public void refresh(View v){
if (loadTask.getStatus() == AsyncTask.Status.FINISHED){
aList.clear();
aa.notifyDataSetChanged();
new MyAsyncTask().execute("http://luca-ucsc.appspot.com/jsonnews/default/news_sources.json");
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
So you can see that only after loadTask.execute() in onCreate(), do I create the object for alist and aa, but I'm already using them in onPostExecute() in the AsyncTaks class, so I'm not very clear what happens here, because onPostExecute() and the UI are on the same thread, so the code in onPostExecute() should be executed first.
I thought I should put
aList = new ArrayList<Content>();
aa = new MyAdapter(this, R.layout.list_element, aList);
into onPostExecute(), which is more logical to me, but the app crashes this way. Also I think deleting aa.notifyDataSetChanged(); in onPostExecute() shouldn't be a problem because it's also in the onCreate() method, but this actually causes the list view to be blank, without any content. Actually, putting any of the codes after loadTask.execute() into the if block of the onPostExecute() method causes some problem, or crashes the app. That would be great if somebody can give some insight or hint. Thanks for reading.
onPostExecute is called on the UI thread after the background task completes its work. You cannot guarantee the timing of this call in relation to other calls on the UI thread.
Since you are already implementing getView yourself, I recommend you extend BaseAdapter instead of ArrayAdapter and implement the other few required methods. It's not hard and you can use whatever data structure you want to back the adapter. Assuming you use a List<Content> to back the adapter, you can write a method to swap the list in place like so:
public void swapList(List<Content> newList) {
this.list = newList;
notifyDataSetChanged();
}
In your AsyncTask, you have complete control of the Params, Progress, and Result parameterized types. They don't all have to be String. You can do this instead:
private class myAsyncTask extends AsyncTask<String, Void, List<Content>> {
/* ... */
}
The String for Params is the URL (same as you do now). Void for Progress because you don't publish progress anyway. List<Content> for Result because that's the thing you actually want to end up with after doing your task.
You should do ALL of your work in doInBackground. There is no reason to deserialize a String into a JSONArray and mess around with that in onPostExecute, particularly since that is happening on the main thread. Rewrite doInBackground to return a List<Content>, and all you need in onPostExecute is this:
public void onPostExecute(List<Content> result) {
adapter.swapList(result);
}
Now you can create the adapter once (in onCreate()) and just swap the list whenever it's appropriate.

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

NetworkOnMainThread exception android. fetching server response

I am getting the exception android.os.NetworkOnMainThreadException when I tried to use the following codes:
public class CheckServer extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
Runnable runn = null;
HttpTask.execute(runn);
}
private class HttpTask extends AsyncTask<String, String, String>
{
#Override
protected String doInBackground(String... params) {
// TODO Auto-generated method stub
HttpURLConnection urlConnection = null;
URL theURL = null;
try {
theURL = new URL("http://192.168.2.8/parkme/Client/clientquery.php?ticket=66t");
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
urlConnection = (HttpURLConnection) theURL.openConnection();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String response = null;
try {
response = readInputStream(urlConnection.getInputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return response;
}
private String readInputStream(InputStream is) {
// TODO Auto-generated method stub
String line = "";
StringBuilder total = new StringBuilder();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
try {
while ((line = rd.readLine()) != null) {
total.append(line);
}
} catch (Exception e) {
e.printStackTrace();
}
return total.toString();
}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), result, Toast.LENGTH_LONG).show();
}
}}
If possible can someone tell me how to use it inside an Async Task and get the output? I tried but can't seem to get anywhere.
NetworkOnMainThread Exception occurs because you are running a network related operation on the main UI Thread.This is only thrown for applications targeting the Honeycomb SDK or higher
You should be using asynctask.
http://developer.android.com/reference/android/os/AsyncTask.html
In onCreate()
new TheTask().execute();
You can also pass parameters like url to the constructor of AsyncTask and use the same in doInBackground()
class TheTask extends AsyncTask<Void,Void,Void>
{
protected void onPreExecute()
{ super.onPreExecute();
//display progressdialog.
}
protected void doInBackground(Void ...params)//return result here
{
//http request. do not update ui here
return null;
}
protected void onPostExecute(Void result)//result of doInBackground is passed a parameter
{
super.onPostExecute(result);
//dismiss progressdialog.
//update ui using the result returned form doInbackground()
}
}
When an asynchronous task is executed, the task goes through 4 steps:
onPreExecute(), invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
Ok, lets do it step by step ...
1) create private class extending AsyncTask
private class HttpUrlConnectionTask extends AsyncTask {
2) Override the doInBackground() method, this will do the heavy load
#Override
protected Object doInBackground(Object... params) {
// your HttpUrlConnection code goes here
return response;
3) Once the job is done and returns, the onPostExecute() method will be called. The result parameter contains the return value of doInBackground() - so response.
#Override
protected void onPostExecute(Object result) {
Within this method you can update your UI.
4) Finally lets have a look onto the HttpUrlConnection code
HttpURLConnection urlConnection = null;
URL theURL = new URL(url);
urlConnection = (HttpURLConnection) theURL.openConnection();
String response = readInputStream(urlConnection.getInputStream());
return response;
Hope this helps. Happy coding!
#Raghunandan comes with a really good explanation of how AsyncTask works
Here you go:
public static class InitializeTask extends MyAsyncTask<String, String, String> {
private Activity activity;
private ProgressDialog dialog;
public InitializeTask(Activity activity) {
this.activity = activity;
}
#Override
protected void onPostExecute(String result) {
Toast.makeText(activity, result, Toast.LENGTH_SHORT).show();
}
#Override
protected String doInBackground(String... params) {
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet("http://192.168.2.8/localhost/parkme/Client/clientquery.php?ticket=");
try {
HttpResponse response = httpclient.execute(httpget);
if(response != null) {
String line = "";
InputStream inputstream = response.getEntity().getContent();
return convertStreamToString(inputstream);
} else {
return "Unable to complete your request";
}
} catch (ClientProtocolException e) {
return "Caught ClientProtocolException";
} catch (IOException e) {
return "Caught IOException";
}
}
private String convertStreamToString(InputStream is) {
String line = "";
StringBuilder total = new StringBuilder();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
try {
while ((line = rd.readLine()) != null) {
total.append(line);
}
} catch (Exception e) {
return "Stream Exception";
}
return total.toString();
}
}
A little side note, it is generally considered bad code to catch just Exception, since this will catch anything, and you are not accounting for what it is.
To use the AsyncTask in the Activity do this:
InitializeTask task = new InitializeTask(this)
task.execute()
Exactly as it says, network activity isn't allowed on the thread the activity ran in. Moving your code to an Asynctask is the way to do it properly. Though if you're just trying to get your concept working still you can do this...
//lazy workaround with newer than gingerbread
//normally UI thread can't get Internet.
if(Build.VERSION.SDK_INT >= 9){
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
And then the UI thread actually can. I wouldn't release anything like this however, I haven't even tried infact. It's just my lazy debugging move I use a lot.

NetworkOnMainThread Error

Hi everyone am trying to retrieve product information from my MSQL database. The price and title does work to get however not the image. I keep getting the NetworkOnMainThread error. I know this is because the code is in runOnUiThread thus the main thread. But I tried all possible solutions once I remove runOnUIThread and only have a new runnable the code inside doesn't execute please help? any solution is grateful.
// TODO Auto-generated method stub
Tread loadingThread = new Thread(){
String result = "";
#Override
public void run() {
// TODO Auto-generated method stub
try{
HttpResponse response = httpClient.execute(httpPost);
HttpEntity httpentity=response.getEntity();
InputStream inputStream = httpentity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream,"iso-8859-1"),8);
StringBuilder stringBuilder = new StringBuilder();
String line = null;
while ((line = reader.readLine())!=null){
stringBuilder.append(line+"\n");
}
inputStream.close();
result=stringBuilder.toString();
JSONArray Array = new JSONArray(result);
JSONObject jsonObject=null;
jsonObject = Array.getJSONObject(0);
String productTitle = jsonObject.getString("title");
String productPrice = jsonObject.getString("price");
final String productImage = jsonObject.getString("image_url");
productTextViewPrice.setText(productPrice);
productTextViewTitle.setText(productTitle);
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
// TODO Auto-generated method stub
try {
InputStream is = (InputStream) new URL(productImage).getContent();
Log.i("log_URL","URL is " + productImage);
Drawable proImage = Drawable.createFromStream(is, "src name");
productImageFull.setImageDrawable(proImage);
} catch (Exception e) {
Log.i("log_Result","error getting image " + e.toString());
}
}
});
} catch (Exception e){
}
super.run();
}
};
loadingThread.start();
http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html.
NetworkOnMainThread occurs because you might me doing netowrk related operation on the main UI Thread. You have to make network related operation in the background thread and updata ui on the ui thread.
You can use a asycntask. http://developer.android.com/reference/android/os/AsyncTask.html
class TheTask extends AsyncTask<Void,Void,Void>
{
protected void onPreExecute()
{ super.onPreExecute();
//display progressdialog.
}
protected void doInBackground(Void ...params)
{
//http request. do not update ui here
return null;
}
protected void onPostExecute(Void result)
{
super.onPostExecute(result);
//dismiss progressdialog.
//update ui
}
}
Use async taks if the network operation is for a short period.
Straight from the doc
AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent pacakge such as Executor, ThreadPoolExecutor and FutureTask.
You can consider an alternative to asynctask robospice.https://github.com/octo-online/robospice.
Take a look at AsyncTask() or, better, AsyncTaskLoader(). You have fine Java code in your question, but Android is a little different.

Categories

Resources