In my application i take an image and data from server. When internet connection is there image loaded properly. When internet connection slow down an application keeps on running and after sometime it stops suddenly.
This is AsyncTask to get image and data from server:
public void getPendingList() {
new AsyncTask<Void, Void, String>() {
protected void onPreExecute() {
progressDialog = new ProgressDialog(getActivity());
progressDialog.setTitle("Loading....");
progressDialog.setMessage("Please Wait...");
progressDialog.setCancelable(true);
progressDialog.show();
}
protected String doInBackground(Void... params) {
prepareList();
getRegistrationDetails();
getStateList();
for (int i = 0; i < districts.size(); i++) {
JSONObject jsonObject;
try {
jsonObject = new JSONObject(districts.get(i));
String val1 = jsonObject.getString("OptionalParameter");
int val2 = jsonObject.getInt("ItemID");
String val3 = jsonObject.getString("Item_Description");
double val4 = jsonObject.getDouble("Item_Price");
String val5 = jsonObject.getString("Item_Code");
String val6 = jsonObject.getString("Item_Name");
String val7 = jsonObject.getString("ImageFinal");
String ItemCode = jsonObject.getString("Item_Code");
val7.replace("/", "");
listmodel.add(new Item_Master(val2, val3, val4, val6, val7, ItemCode));
listCountry.add("\u20B9" + val4);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return "response";
}
protected void onPostExecute(String result) {
if (result != null) {
if (!result.equals("NO_NETWORK")) {
mAdapter = new GridviewAdapter_Item_Master(FaramentView.getContext(), listmodel);
gridview.setAdapter(mAdapter);
}
dismissDialog();
}
}.execute(null, null);
}
}
After getting this data, I set GridView adapter in this data and image are set. I use Picasso library to download image and set with following code:
Picasso.with(context).load(list.get(position).getImagePath()).centerCrop()
.resize(150, 150).error(R.drawable.ic_launcher).into(view.imgViewFlag);
How to load image even in slow internet connection?
You get an ANR probably and that means you catch a UI Timeout, that because you trying to update an application component of UI in and AsyncTask (however keep in mind to manage background network processing in doInBackground() method); to update a UI application component you can use Handlers or updating it by runOnUiThread()
Related
Progress dialog should appear before display Alert dialog in Android app . I am using android studio.
Alert dialog content will be from Async task in separate class file. So excuting Progress dialog from async task.
But i am not able to see progress dialog screen before AlertDialog opens.
here is my async task code below.
public class ResidentsPaymentInfoHttpResponse extends AsyncTask<String,
Void, List<paymentInfo>> {
ProgressDialog pDialog;
private Context MSAContext;
public ResidentsPaymentInfoHttpResponse(Context context) {
MSAContext = context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = ProgressDialog.show(MSAContext,"Autenticando", "Contactando o
servidor, por favor, aguarde alguns instantes.", true, false);
}
#Override
protected List<UserPaymentInfo> doInBackground(String... params){
String flatNo = params[0];
String urls = "https://script.google.com/macros/s/;"
List<UserPaymentInfo> residentsMonthlyPayments = new ArrayList<>();
try {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(urls)
.build();
Response responses = null;
try
{
responses = client.newCall(request).execute();
String jsonData = responses.body().string();
JSONObject jobject = new JSONObject(jsonData);
JSONArray jarray = jobject.getJSONArray("ResidentsInfo");
int limit = jarray.length();
for(int i=0;i<limit; i++)
{
JSONObject object = jarray.getJSONObject(i);
if(object.getString("FlatNo").equals(flatNo) &&
object.getString("PaymentStatus").equals("notpaid")) {
UserPaymentInfo residentMaintePayment = new
UserPaymentInfo();
UserInfo residentInfo = new UserInfo();
residentInfo.setUserFlatNo(object.getString("FlatNo"));
residentsMonthlyPayments.add(residentMaintePayment);
}
}
}
catch (IOException e)
{
// e.printStackTrace();
}
pDialog.dismiss();
}
catch (Exception ex)
{
// ex.printStackTrace();
}
return residentsMonthlyPayments;
}
protected void onPostExecute(List<UserPaymentInfo> rusult){
super.onPostExecute(rusult);
pDialog.dismiss();
}
}
Am i missing something???
You should not update UI elements (which belong to main/UI thread) inside doInBackground(). May be removing pDialog.dismiss(); from end lines of doInBackground() change the situation.
Check below link.
How to show progress dialog in Android?
you are not calling show() method on progress dialog. You should do it inside preExecute then dismiss it in postExecute method of async task.
Also as said by VSB you should not update UI elements from doInBackground method.
I am running the commands like so:
new GetGameScoresFromFuhantikAPI()
And my method for this is ->
private class GetGameScoresFromFuhantikAPI extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
MethodContants.showLog(TAG, "Loading FUHNATIK API", true);
}
#Override
protected Void doInBackground(Void... arg0) {
HttpHandler sh = new HttpHandler();
// Making a request to url and getting response
String url = API_URL + jsonFile;
// String url = "http://www.nfl.com/liveupdate/game-center/" + list.get(i) + "/" + list.get(i) + "_gtd.json";
String jsonStr = sh.makeServiceCall(url);
Log.e(TAG, "Response from FUHNATIK API: " + url);
if (jsonStr != null) {
try {
//JSONObject object = new JSONObject(json);
JSONObject object = new JSONObject(jsonStr);
currentWeek = object.getString("pypwk");
currentWeekDB = object.getString("mdb");
JSONArray array = (JSONArray) object.get("g");
scheduleModelList = new ArrayList<>();
for (int i = 0; i < array.length(); i++) {
//TODO IF WE DONT PLAY THURSDAY GAMES PUT LIST.ADD IN HERE
// if (!array.getJSONObject(i).getString("-d").equals("Thu")){
//
// }
scheduleModelList.add(new ScheduleModel(array.getJSONObject(i).getString("-v"),
array.getJSONObject(i).getString("-h"),
array.getJSONObject(i).getString("-t"),
array.getJSONObject(i).getString("-d"),
array.getJSONObject(i).getString("-eid").substring(0, 8),
array.getJSONObject(i).getString("-t") + array.getJSONObject(i).getString("-q"),
array.getJSONObject(i).getString("-vnn"),
array.getJSONObject(i).getString("-hnn"),
"...select a team...",
array.getJSONObject(i).getString("-eid"),
array.getJSONObject(i).getString("-vs"),
array.getJSONObject(i).getString("-hs"),
array.getJSONObject(i).getString("-w")));
}
} catch (final JSONException e) {
Log.e(TAG, "FUHNATIK API: Json parsing error: " + e.getMessage());
}
} else {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
Log.e(TAG, "FUHNATIK API: Couldn't get json from server.");
Toast.makeText(getContext(), "Getting from ESPN", Toast.LENGTH_SHORT).show();
//new GetGameScoresFromESPN().execute();
}
});
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
final ListViewAdapterResults adapter = new ListViewAdapterResults(listView.getContext(), scheduleModelList);
listView.setAdapter(adapter);
MethodContants.showLog(TAG, "DONE WITH LOADING FUHNATIK API", false);
}
}
I can't seem to figure out why the code never get ran. I ran through the debugger but I really can't pinpoint where this is failing out. Any help on this would be appreciated.
Eventually if the json file is not at this URL, I will be getting the json from NFL. However, Without this working, the ESPN won't work either, and I really can not figure out where the error is on my end. I have to assume this will be a pretty easy fix.
Again, as said before, any help would be very appreciated!!
In the above line of code you call the Class but you forgot to execute your asynctask. So no Overriden methods are called. Try this:
new GetGameScoresFromFuhantikAPI().execute();
If you want to pass something as argument, give parameters separated by coma like this:
new GetGameScoresFromFuhantikAPI().execute(arg0, arg1);
The app i'm developing downloads a JSON file from remote address at every startup and then it parses the JSON Object and copies data to SQLite on the phone.
This operation is the cause for which the app hangs for some seconds on every startup showing blank screen (or sometime blank and then black screen), in fact if i tried to disable this part of code the app starts quickly, with no hang.
So, how could i do it better?
Here is the code (DataHandler class) related to file download, parsing and writing to local SQLite db:
public class DataHandler {
public DataHandler() {
}
public int storeData(Database db, int num) throws JSONException {
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet("http://www.example.com/data.json");
request.addHeader("Cache-Control", "no-cache");
long id = -1;
try {
HttpResponse response = client.execute(request);
HttpEntity entity = response.getEntity();
InputStreamReader in = new InputStreamReader(entity.getContent());
BufferedReader reader = new BufferedReader(in);
StringBuilder stringBuilder = new StringBuilder();
String line = "";
while ((line=reader.readLine()) != null) {
stringBuilder.append(line);
}
JSONArray jsonArray = new JSONArray(stringBuilder.toString());
SQLiteDatabase dbWrite = db.getWritableDatabase();
ContentValues values = new ContentValues();
if (jsonArray.length() == num && num != 0)
return num;
SQLiteDatabase dbread = db.getReadableDatabase();
dbread.delete("mytable", "1", null);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jObj = (JSONObject) jsonArray.getJSONObject(i);
values.put("_id", jObj.optString("id").toString());
values.put("city", jObj.optString("city").toString());
values.put("country",jObj.optString("country").toString());
values.put("addr", jObj.optString("addr").toString());
values.put("title", jObj.optString("title").toString());
values.put("lon", jObj.optString("lon").toString());
values.put("email", jObj.optString("email").toString());
values.put("phone", jObj.optString("phone").toString());
values.put("web", jObj.optString("web").toString());
values.put("lat", jObj.optString("lat").toString());
values.put("desc", jObj.optString("desc").toString());
values.put("icon", jObj.optString("icon").toString());
values.put("category", jObj.optString("category").toString());
id = dbWrite.insert("merchants", null, values);
}
num = jsonArray.length();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if (id > 0)
return num;
else
return -1;
}
}
You should probably to the download and parsing in the background and display some kind of splashscreen with progress information in the meantime.
To avoid an annoying splash screen, you could also cache the data and display your app normally on startup, and only refresh the data once the bakground update is finished.
There are several options to do the download and parse operations in the background :
use an AsyncTask
use a service
I cannot say what's the best solution in your specific case, but I would recommend reading the Processes and Threads and service documentation.
Her goes your Async Task Class
class AsyncClass extends AsyncTask<String,Void,String>
{
int result;
Context context;
ProgressDialog bar;
AsynclassListener<String> listener;
public AsyncClass(Context context, AsynclassListener listener) {//add more parameter as your method body has (i.e Database db, int num) . Don't forget to initialize them.
this.context=context;
this.listener=listener;
bar = new ProgressDialog(context);
bar.setIndeterminate(false);
//make your progressBar here I have just given a simple example for above PB there are more parameters to set.
}
protected String doInBackground(String... Param){
try{
result = storeData();//call your method here
}catch(Exception e){
// Do something when crash
}
return ""+result;
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
bar.show();// By the time your data fetching and parsing will go on you this progress bar will be visible.
}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
bar.dismiss();//As soon as the work is complete the this method is called.
listener.onTaskComplete(""+result);
/**
* In your case you can later typecast back in integer once you recieve the result.
* this listener will post the result to your main activity.
*/
}
}
Here is your Interface
public interface AsynclassListener<T>{
public void onTaskComplete(T result);
}
Now Let your Activity (Splash Class) implement the interface
This will implement the method as :
#Override
public void onTaskComplete(String result) {
// here the asynclass will post the result as 1 or -1 whatever you want.
//After that you may proceed with your next part i.e switching to next activity or so.
}
Edit: I forgot to mention about how this will be called :
new AsyncClass(getApplicationContext(), this).execute("");// here you have to enter the database and other parameter values that will be required to run the method. Change it accordingly.
As you can see here in your method you are fetching the data from net and parsing also :
There is again a second approach in which you can call the network cal in a separate thread and later the parsing can be done further on UIthread.
Also read about the Async Task Class so as to know about the arguments and the working of class.
I have implemented an AsyncTask to get values of a web service and store them into an array, but something I am doing wrong because it says that "Invalid index 0, size is 0". The object "dia" is not well created. Here is my code:
private class GetValue extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// Showing progress dialog
pDialog = new ProgressDialog(getActivity());
pDialog.setMessage("Please wait...");
pDialog.setCancelable(false);
pDialog.show();
}
#Override
protected Void doInBackground(Void... arg0) {
// Creating service handler class instance
ServiceHandler sh = new ServiceHandler();
// Making a request to url and getting response
String jsonStr = sh.makeServiceCall(url, ServiceHandler.GET);
Log.d("Response: ", "> " + jsonStr);
metereologia = new ArrayList<DiaTemperatura>();
if (jsonStr != null) {
try {
JSONObject jsonObj = new JSONObject(jsonStr);
// Getting JSON Array node
eventos = jsonObj.getJSONArray("list");
// looping through All Contacts
for (int i = 0; i < eventos.length(); i++) {
JSONObject c = eventos.getJSONObject(i);
JSONObject temp = c.getJSONObject(TAG_TEMP);
String max = temp.getString(TAG_MAX);
String min = temp.getString(TAG_MIN);
String humedad = c.getString(TAG_HUMIDITY);
JSONObject weather = c.getJSONObject(TAG_WEATHER);
//String main = weather.getString(TAG_MAIN);
//String description = weather.getString(TAG_DESCRIPTION);
DiaTemperatura dia= new DiaTemperatura();
dia.setMyText(max);
metereologia.add(dia);
}
} catch (JSONException e) {
e.printStackTrace();
}
} else {
Log.e("ServiceHandler", "Couldn't get any data from the url");
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// Dismiss the progress dialog
if (pDialog.isShowing())
pDialog.dismiss();
TextView mitext = (TextView) getView().findViewById(R.id.temperatura);
mitext.setText(metereologia.get(0).getMyText());
}
}
It looks like you must be declaring metereologia outside your AsyncTask, then initialising and populating it in the task. This is not quite the correct way to use it. Your AsyncTask should return the result of its computation. You'll need to declare your task as:
private class GetValue extends AsyncTask<Void, Void, List<DiaTemperatura>> {
...
#Override
protected List<DiaTemperatura> doInBackground(Void... arg0) {
List<DiaTemperatura> metereologia = new ArrayList<DiaTemperatura>();
...
return metereologia;
}
and thus onPostExecute becomes:
#Override
protected void onPostExecute(List<DiaTemperatura> metereologia) {
I think that's right, it's off the top of my head...
Your error must be in the line mitext.setText(metereologia.get(0).getMyText()); Its will go for finding the value at the index 0 in your metereologia which its is not getting.
You can not directly set the value of your whole arraylist in such a way. You need to loop for the value whichever you want to set in your TextView.
There is nothing in the metereologia so when you try to get it with (metereologia.get(0).getMyText(), it results in an error, "Invalid index 0, size is 0".
1) For doing check work -
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// Dismiss the progress dialog
if (pDialog.isShowing())
pDialog.dismiss();
TextView mitext = (TextView) getView().findViewById(R.id.temperatura);
String content = "";
if(metereologia.size() == 0)
{
//a check that your metereologia size is 0.
}
for(int i=0;i<metereologia.size();i++)
content = content + metereologia.get(i).getMyText();
mitext.setText(content);
}
}
2) To get the value right-
More convenient way is to return the object metereologia from background and pass it to postExecute method and then process.This is explained by #dave.c.
protected void onPostExecute(List<DiaTemperatura> metereologia) {
super.onPostExecute(result);
// Dismiss the progress dialog
if (pDialog.isShowing())
pDialog.dismiss();
TextView mitext = (TextView) getView().findViewById(R.id.temperatura);
String content = "";
if(metereologia.size() == 0)
{
//a check that your metereologia size is 0.
}
for(int i=0;i<metereologia.size();i++)
content = content + metereologia.get(i).getMyText();
mitext.setText(content);
}
}
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! ;)