I have almost finished my project, only one thing remain to improve.
My app is a music quiz, that retrieves all the informations about author, song title, previewUrl ecc. from the Itunes Store using the apposite Search API.
When a user choose a genre to play with, I must say to the user to wait for 4-5 seconds because of the computation that fills the List containing all the informations.
I call the Asynctask that retrieve these informations like this:
JsonCanzoni recuperoCanzoni = new JsonCanzoni(arrayGenere,Canzone.this);
try {
recuperoCanzoni.execute().get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
The class (extends Asynctask) that do these operation is the following:
class JsonCanzoni extends AsyncTask<Void, Void, Void>
{
List<String> canzoni = new ArrayList<String>(5);
ProgressDialog pDialog;
int[] arrayGenere;
Context context;
public JsonCanzoni(int[] arrayGenere,Context context)
{
this.arrayGenere = arrayGenere;
this.context = context;
}
#Override
protected void onPostExecute(Void result)
{
super.onPostExecute(result);
pDialog.dismiss();
}
#Override
protected void onPreExecute()
{
super.onPreExecute();
pDialog = new ProgressDialog(context);
pDialog.setMessage("Preparazione round...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
protected Void doInBackground(Void... params)
{
try
{
int randomLookupId = 0;
JSONObject obj;
JSONArray jsonArray;
for(int i = 0; i < 10; i++)
{
canzoni = new ArrayList<String>();
Log.d("GENERE", arrayGenere.toString());
obj = getJSONObject(scegliClassifica(arrayGenere));
jsonArray = obj.getJSONArray("resultIds");
Log.d("dimensione JsonArray", String.valueOf(jsonArray.length()));
try
{
randomLookupId = new Random().nextInt(jsonArray.length()-1);
}
catch(IllegalArgumentException errore)
{
new AlertDialog.Builder(context)
.setTitle("Connessione non attiva!")
.setMessage("Connessione di rete debole, uscita dal programma!");
}
Log.d("randomLookupID", String.valueOf(randomLookupId));
JSONObject finalObj = getJSONObject("http://itunes.apple.com/lookup?id="+jsonArray.getString(randomLookupId));
Log.d("URL","http://itunes.apple.com/lookup?id="+jsonArray.getString(randomLookupId));
while(finalObj.getJSONArray("results").length() == 0)
{
Log.d("Array VUOTO!!","Non è possibile!!!!");
randomLookupId = new Random().nextInt(jsonArray.length()-1);
Log.d("randomID rigenerato", String.valueOf(randomLookupId));
finalObj = getJSONObject("http://itunes.apple.com/lookup?id="+jsonArray.getString(randomLookupId));
Log.d("URL Rigenerato","http://itunes.apple.com/lookup?id="+jsonArray.getString(randomLookupId));
}
JSONArray finalJsonArray = finalObj.getJSONArray("results");
JSONObject returnObj = finalJsonArray.getJSONObject(0);
Log.d("returnObj.length",String.valueOf(returnObj.length()));
canzoni.add(returnObj.getString("previewUrl"));
canzoni.add(returnObj.getString("artistName"));
canzoni.add(returnObj.getString("trackName"));
canzoni.add(returnObj.getString("artistViewUrl"));
canzoni.add(returnObj.getString("artworkUrl100"));
// GTTapp app=(GTTapp) ((Activity)context).getApplication();
// app.dieciCanzoni;
Canzone.dieciCanzoni.add(i, new ArrayList<String>(canzoni));
}
}
catch (JSONException ignored)
{
ignored.getCause();
}
catch (MalformedURLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
private String scegliClassifica(int[] arrayGenere)
{
int randomArrayPosition = new Random().nextInt(arrayGenere.length);
return "http://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g="+arrayGenere[randomArrayPosition]+"&name=Songs&limit=200";
}
JSONObject getJSONObject(String url) throws IOException, MalformedURLException, JSONException
{
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
InputStream in = conn.getInputStream();
try
{
StringBuilder sb = new StringBuilder();
BufferedReader r = new BufferedReader(new InputStreamReader(new DoneHandlerInputStream(in)));
for (String line = r.readLine(); line != null; line = r.readLine())
{
sb.append(line);
}
return new JSONObject(sb.toString());
}
finally
{
in.close();
}
}
}
THE PROBLEM: Using the .get() method make the app waiting for the entire computation of the AsyncTask, but it block the UI thread too!! So the user will remain with a black screen for 5 secs or more, and that's not a good thing!
If I don't use the .get() method, I receive an IndexOutOfBounds Exception, because I begin to play the music stream but the list is has not been filled yet.
Can you suggest me a workarund for this situation?
Thank you!
remove .get() it will block the UI till completion of the task.
Start any task like (playing video) which is dependent on AsycTask in
#Override
protected void onPostExecute(Void result)
{
super.onPostExecute(result);
pDialog.dismiss();
//You can start music stream here
}
The get() call is blocking. From the docs:
Waits if necessary for the computation to complete, and then retrieves its result.
What you should do is wait asynchronously the computation to finish before you start to play the music.
If you do not want to expose the asynctask outside your class, you can set a callback into your JSonCanzoni class to be called into the onPostExecute method of the asynctask.
Something like
public interface CanzoniDownloadedInterface {
public void onCanzoniDownloaded();
}
public JsonCanzoni(int[] arrayGenere, CanzoniDownloadedInterface callback, Context context){
this.arrayGenere = arrayGenere;
this.context = context;
this.callback = callback;
}
and in your onPostExecute():
#Override
protected void onPostExecute(Void result)
{
super.onPostExecute(result);
this.callback.onCanzoniDownloaded();
pDialog.dismiss();
}
If you let your activity implement the interface, you can pass it to your class.
The onCanzoniDownloaded() implementation is where you need to start playing.
Finally I solved my problem, some advices were good and helped me a lot!
I simply moved the startActivity instruction to onPostExecute of JsonCanzoni AsyncTask, and changed some code to adapt to the new version and it's all right! ;)
Related
I am using AsyncTask to call the web service and render the data I got from web service.
this is working fine but sometimes Progress Dialog doesn't get dismissed and not able to see the reason for this in log also.
Example::
I have a web service which is getting called to get the list view data with indexing(for 1 it will return first 5 data and for 2 it will return second 5 data and so on)
once I click page 1 button it returns data and render the same and when I click the page 2 button it starts loading and doesn't dismiss. neither the data is rendered nor the progress dialog is dismissed.
now i closed the app and relaunched again and this time both the situation worked very well.
Any help would be appreciated
thanks in advance
Code for Asynctask :
public class getList extends AsyncTask<Void, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(getActivity());
pDialog.setCancelable(false);
pDialog.setMessage("Please wait...");
pDialog.setCanceledOnTouchOutside(false);
pDialog.show();
}
#Override
protected String doInBackground(Void... params) {
String text = null;
JSONObject json;
HttpClient httpclient = new DefaultHttpClient();
//Configuration.empcode.trim()
HttpGet httppost = new HttpGet(ListURL+UserCode+"/"+indexNo);
try {
HttpResponse response = httpclient.execute(httppost);
// for JSON:
if (response != null) {
InputStream is = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(
new InputStreamReader(is));
// String result = EntityUtils.toString((HttpEntity)
// response);
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
text = sb.toString();
}
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
} catch (IOException e) {
// TODO Auto-generated catch block
}
return text;
}
#Override
protected void onPostExecute(String result)
{
pDialog.dismiss();
if(result!=null)
{
try
{
JSONObject resultObject = new JSONObject(result);
JSONArray resultArray = resultObject.getJSONArray("Table");
for(int i =0;i<resultArray.length();i++)
{
JSONObject resultObjects = resultArray.getJSONObject(i);
Code = resultObjects.getString("Code");
Title = resultObjects.getString("Title");
status= resultObjects.getString("status");
date= resultObjects.getString("date");
TitleList.add(Title);
CodeList.add(Code);
statusList.add(status);
dateList.add(date);
int count = db.getInProgressCount(CourseCode);
if(count==0)
{
db.addInProgress(new InProgressTable(Code,Title,status,date));
}
else
{
db.updateInProgress(new InProgressTable(Code,Title,status,date));
}
}
adapter = new CustomInProgressList(getActivity(),TitleList,CodeList,statusList,dateList);
//adapter.setCustomButtonListner(Catalog_Activity.this);
list.setAdapter(adapter);
scrollMyListViewToBottom(resultArray.length());
int count = db.getAllInProgressCount();
if (adapter.getCount()<1 && count<1){
list.setVisibility(View.GONE);
noRes.setVisibility(View.VISIBLE);
}else {
list.setVisibility(View.VISIBLE);
noRes.setVisibility(View.GONE);
}
if (resultArray.length()<5);
loadMore.setVisibility(View.GONE);
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
else
{
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Alert");
builder.setMessage("Data is not available, Please try again later");
builder.setPositiveButton("OK", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
dialog.cancel();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
}
}
I have used multiple Asynctask in my application.
Is that a Problem??
ok here is your problem -
pDialog as I understand is declared in activity. Lets see the situation with 2 requests.
when you started first one, and immediately start another - your pDialog is now new dialog (it points to another dialog) and first one exists without point to it, and it's not closed! this is why you have not closed dialog.
this will be caused in situation when:
1) first request started;
2) second request started before first request ended;
you must handle one dialog in all your requests or close dialog before it's reinitialisation.
I am trying to parse some data using JSoup, this is all happening in a asynctask (doInBackground) part of my MainActivity.
Unfortunately all the elements (9) are empty when I execute the app.
When I debug below codeline, I actually get the complete website, it`s all there.
The method readMultipleLinesRespone() is located in another class HttpUtility where I also call my Post and Get requests.
I tested this upfront by saving the website as a file and using JSoups assets ability, it worked perfectly then.
The setupAdapter() method in onPostExecute fills a ExpandableListview with data, should this info be nessecary. If you need more info pls ask.
Can somebody assist and tell me what I am doing wrong?
response1 = util.readMultipleLinesRespone(); <--- debugged and all data (seems) to be there but isn`t.
Edit: If I print response1, there is indeed no data to parse.
Logcat output:
E/Resonse:: [Ljava.lang.String;#3d3410a
Below is the method readMultipleLinesRespone from HttpUtility class:
public String[] readMultipleLinesRespone() throws IOException {
InputStream inputStream = null;
if (httpConn != null) {
inputStream = httpConn.getInputStream();
} else {
throw new IOException("Connection is not established.");
}
BufferedReader reader = new BufferedReader(new InputStreamReader(
inputStream));
List<String> response = new ArrayList<String>();
String line = "";
while ((line = reader.readLine()) != null) {
response.add(line);
}
reader.close();
return (String[]) response.toArray(new String[0]);
}
The asynctask where it`s all hapening:
private class FetchWebsiteData extends AsyncTask<Void, Void, Void> {
ProgressDialog mProgressDialog;
#Override
protected void onPreExecute() {
this.mProgressDialog = new ProgressDialog(getActivity());
mProgressDialog.setMessage("Laden...");
mProgressDialog.setIndeterminate(false);
mProgressDialog.show();
}
#Override
protected Void doInBackground(Void... result) {
try {
util.sendGetRequest("https://mobile.somesite.nl/Data", null);
response1 = util.readMultipleLinesRespone();
} catch (IOException e) {
e.printStackTrace();
}
if (response1.length > 0) {
Document doc = Jsoup.parse(response1.toString());
// Get the html document title
Elements els = doc.select("span[class=item-value pull-right]");
if (els.size() > 0) {
fac_naam = els.get(0).text();
fac_straat = els.get(1).text();
fac_post = els.get(2).text();
con_tel = els.get(3).text();
con_email = els.get(4).text();
betaal_reknr = els.get(5).text();
betaal_houd = els.get(6).text();
zig_gebruiker = els.get(7).text();
zig_wacht = els.get(8).text();
}
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPreExecute();
setupAdapter();
mProgressDialog.dismiss();
}
}
In the meantime I solved the problem.
I did not pass the response string correctly to the asynctask which parses the required elements.
Just required a public string in which the response is being set and passed (not an elegant way but it works):
public static String HttpResponse = "";
In the HttpUtility class:
public String[] readMultipleLinesRespone() throws IOException {
...
TabFragment1.HttpResponse = response.toString();
...
return (String[]) response.toArray(new String[0]);
}
Then pass it to the asynctask:
#Override
protected Void doInBackground(Void... result) {
try {
util.sendGetRequest(LoginActivity.PersData_URL, null);
util.readMultipleLinesRespone();
} catch (IOException e) {
e.printStackTrace();
}
if (HttpResponse.length() > 0) {
Document doc = Jsoup.parse(HttpResponse.toString());
// Get the html document title
Elements els = doc.select("span[class=item-value pull-right]");
...
}
return null;
}
I am currently working with the tab host and fragment. Currently I set fragment a to download json A and fragment B to download json B , the problem is when I switch fragment, the fragment A onPostExecute function will fall into the fragment B one , is there any way to fix this?
Thanks
Tab host:
tabHost = (FragmentTabHost) findViewById(R.id.tabhost);
tabHost.setup(this, getSupportFragmentManager(), R.id.tabcontent);
tabHost.addTab(
tabHost.newTabSpec("Home").setIndicator("",
res.getDrawable(R.drawable.btn_about)), Home.class,
null);
tabHost.addTab(
tabHost.newTabSpec("About").setIndicator("",
res.getDrawable(R.drawable.btn_about)), About.class,
null);
The async task
public class JSONReader {
public static final String TAG = "JSONReader";
public ArrayList<Record> records;
public Record myRecordObj;
public ArrayList<GalleryImage> images;
public String url;
public int failCount = 0; // retry twice
public Context ctx;
public String readCase;
public JSONReader(String _url, Context _ctx , String _readCase) {
url = _url;
ctx = _ctx;
readCase = _readCase;
}
public void getJSON() {
new JSONDownload().execute(url);
}
private class JSONDownload extends AsyncTask<String, Void, JSONObject> {
// TODO Auto-generated method stub
StringBuilder builder = new StringBuilder();
String temp = "";
String json = ""; // json content
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
#Override
protected JSONObject doInBackground(String... params) {
// TODO Auto-generated method stub
try {
Log.d(TAG, "Start reading: " + url);
URL url = new URL(params[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK)
return null;
// return "Server returned HTTP " + connection.getResponseCode()
// + " " + connection.getResponseMessage();
input = connection.getInputStream();
BufferedReader reader = new BufferedReader(
new InputStreamReader(input));
while ((temp = reader.readLine()) != null) {
builder.append(temp);
}
json = builder.toString();
} catch (Exception e) {
return null;
} finally {
try {
if (input != null)
input.close();
if (output != null)
output.close();
} catch (IOException ignored) {
}
if (connection != null)
connection.disconnect();
}
try {
return new JSONObject(json);
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(JSONObject result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
onJSONDownloaded(result);
}
}
public void onJSONDownloaded(JSONObject result) {
// TODO Auto-generated method stub
if (result != null) {
failCount = 0;
if (readCase.equals("leaderBoard")){
records = new ArrayList<Record>();
try {
JSONObject myRecord = result.getJSONObject("myRecord");
if (myRecord != null) {
myRecordObj = new Record(myRecord.getString("pic"),myRecord.getString("name"),myRecord.getString("score"));
}
JSONArray topRecords = result.getJSONArray("topRecord");
for (int i = 0; i < topRecords.length(); i++) {
JSONObject topRecord = topRecords.getJSONObject(i);
String topName = topRecord.getString("name");
String topPic = topRecord.getString("pic");
String topScore = topRecord.getString("score");
records.add(new Record(topPic, topName, topScore));
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
((LeaderBoardDetail)ctx).setData(records,myRecordObj);
} else if (readCase.equals("galleryList")){
images = new ArrayList<GalleryImage>();
try {
JSONArray imageList = result.getJSONArray("images");
for (int i = 0; i < imageList.length(); i++) {
JSONObject image = imageList.getJSONObject(i);
images.add(new GalleryImage(image.getString("url"),image.getString("thumbUrl"),image.getString("category"),image.getString("userPic"),image.getString("name")));
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//exception
if (((FragmentActivity) ctx).getSupportFragmentManager().findFragmentById(R.id.tabcontent).getTag().equals("Gallery")) {
PhotoGallery galleryFragment = (PhotoGallery) ((FragmentActivity) ctx).getSupportFragmentManager().findFragmentById(R.id.tabcontent);
galleryFragment.setData(images);
}
}
} else {
if (failCount <= 1) { // check global_conf twice if fail
failCount++;
Log.d(TAG, "No of retry" + failCount);
new JSONDownload().execute(url); // Retry download json
} else {
failCount = 0;
}
}
}
}
I used it in my app this way which works for me and answer is a bit similar to another answer but few additions and more detail. Hope it help you too.
NOTE: This is just a idea, u need to try, it may vary as per your app architect.
At your activity make the task object global [make sure set task obj null once task is finish]
JSDownload js = null;
public void getJSON() {
if(js != null && js.getStatus() == AsyncTask.Status.RUNNING)
{
js.cancel(true);
if(js.isCancelled())
{
js = new JSONDownload();
js.execute(url);
}
else
{
js = new JSONDownload();
js.execute(url);
}
}
At the Async class side....[make sure u take care null result # onpostExcute]
class JSONDownload extends AsyncTask<String, Void, JSONObject>
{
protected JSONObject doInBackground(String... params) {
// TODO Auto-generated method stub
try {
if(!this.isCancelled())
{
//make http connection ..
URL url = new URL(params[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
//as we are in steps in bg check iscancel .. again
//if its a loop here we call break; and return null once only..
if(this.isCancelled())
return null;
// connection status check and get buffer etc .. code here
if(this.isCancelled())
return null;
//read data
return data;
}
} catch (Exception e) {
return null;
}
}
#Override
protected void onCancelled(){
// If you write your own implementation, do not call super.onCancelled(result).
}
}
Use the global async task variable
LongOperation LongOperationOdeme = new LongOperation();
and set:
LongOperationOdeme.cancel(true);
This will stop any async task running at that moment, it's what the back button does
If you are not looking for a simplest answer but for a maybe more interesting and elegant, have a peek at this article, especially if you find functional programming interesting.
It's easier than it looks, i was almost unfamiliar to FP before this article but it covers common problems related to AsyncTask and asynchronicity in Android in general, so I got the gist and consider to use Observables instead of AsyncTask in the future projects myself. It is RxJava and it can solve your problem gracefully: "The fromFragment call transforms the given source observable in such a way that events will only be emitted to the fragment if it’s still alive and attached to its host activity."
One more citation form the article: "What if the user decides to back out of the Activity that triggered the task, and we are holding on to a stale reference. This not only creates a substantial memory leak, but is also worthless because meanwhile it has been detached from the application window. A problem that everyone is well aware of."
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.
I am trying to pass a string array to my adapter. My problem is i initialized globally and try to create string array in my asynchronous task below. But i am getting as null. Below is my code. Actually in this example they taking it from resource folders bu i want it from my json response. Any help is appreciated.
String[] mString;
public ActionsAdapter(Context context) {
mInflater = LayoutInflater.from(context);
session = new SessionManager(context);
final Resources res = context.getResources();
new ConnectAppMenu(context).execute();
// mTitles = res.getStringArray(R.array.actions_names);
// mUrls = res.getStringArray(R.array.actions_links);
// mIcons = res.obtainTypedArray(R.array.actions_icons);
System.out.println("Menus"+ mString);
}
public class ConnectAppMenu extends AsyncTask<String, Void, String> {
private ProgressDialog dialog;
private final Context context;
public ConnectAppMenu(Context context) {
this.context = context;
}
#Override
protected void onPreExecute() {
// UI work allowed here
dialog = new ProgressDialog(context);
// setup your dialog here
dialog.setMessage("Connecting....");
dialog.setCancelable(false);
dialog.show();
}
#Override
protected String doInBackground(String... params) {
String returnConnect = doConnectAppMenu();
return returnConnect;
}
public String doConnectAppMenu() {
HashMap<String, String> user = session.getUserDetails();
String client_url = user.get(SessionManager.KEY_CLIENT);
// if(connection) {
HttpParams connectionParameters = new BasicHttpParams();
int timeoutConnection = 8000;
HttpConnectionParams.setConnectionTimeout(connectionParameters, timeoutConnection);
int timeoutSocket = 10000;
HttpConnectionParams.setSoTimeout(connectionParameters, timeoutSocket);
HttpClient httpClient = new DefaultHttpClient(connectionParameters);
HttpPost httpPost = new HttpPost(client_url+"/api/common/app_menu");
JSONObject json = new JSONObject();
try{
json.put("data", 1);
json.put("versionid", 1);
StringEntity se = new StringEntity(json.toString());
se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
httpPost.setEntity(se);
//Execute HTTP post request
appmenu_res = httpClient.execute(httpPost);
appmenu_obj = new org.json.JSONObject(org.apache.http.util.EntityUtils.toString(appmenu_res.getEntity()));
appmenu_result = appmenu_obj.toString();
}
catch(JSONException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// }
return appmenu_result;
}
#Override
public void onPostExecute(String result) {
int status_code = appmenu_res.getStatusLine().getStatusCode();
if (status_code == 200) {
dialog.dismiss();
try {
menuObject = new JSONObject(result);
JSONArray names= menuObject.names();
JSONArray values = menuObject.toJSONArray(names);
for (int i = 0; i< values.length(); i++) {
JSONObject json2 = (JSONObject) values.get(i);
int menu_id = json2.getInt("menu_id");
if (menu_id > 0) {
if (json2.has("menu_name")) {
menu_list = json2.get("menu_name").toString();
mString = new String[] { menu_list };
//mUrls = menu_list.length();
}
}
}
System.out.println("Json Menu" + Arrays.toString(mString));
/*Iterator<String> iter = menuObject.keys();
while (iter.hasNext()) {
String key = iter.next();
try {
Object value = menuObject.get(key);
//System.out.println("Hai" +value);
System.out.println("Post Execute" + value);
} catch (JSONException e) {
// Something went wrong!
}
}*/
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//dialog.dismiss();
}
}
}
well first of all if you're looking for the JSON object as a String don't do what you did here:
appmenu_obj = new org.json.JSONObject(org.apache.http.util.EntityUtils.toString(appmenu_res.getEntity()));
I'd suggest doing the following:
String Json = EntityUtils.toString(appmenu_res.getEntity());
return Json;
Now if you want to do the processing of your JSON on the UI thread (as you seem to want to based on the return type being a string) this should work. However this method is not recommended since the Json will need to be processed into objects which will take time and clog the UI thread.
A better solution would be to serialize your Json on the background thread and then pass the serialized object back to the main thread to update the UI.
If you have many types I would suggest using generics. I've already built a Loader which can do what you want if you want here. You will need touse the GSON library and build appropriate seralizers. Also working with the loader class is different to working with the AsyncTaskClass so please read the documentation here
Edit
Ok so what you want to do if you want get the Activity to have a callback from the AsyncTask is to do something along the lines of:
public class MyActivity extends Activity implements AsyncTaskCallback
where AsyncTaskCallback looks something like :
public interface AsyncTaskCallback
{
public processData(Object responseObject);
}
now in your onPostExecute code you'll need to do somehting like:
#Override
protected void onPostExecute(Object r){
if (r != null) {
l.processData(data);
}
}
and add the following function to your async task
public void addAsyncTaskListener (final AsyncTaskListener l){
mCallback = l;
}
and then finally add the listner and process the data as required in the Activity in the function processData function that the interface forces your activity to implement.
Instead of using String[] you can use ArrayList for Setting list in adaptor.