I'm having a problem refresh the data in list view.
I get the data in the list from a server, and when I want to refresh the data I need to go to the server and receive the new data.
the notifyDataSetChanged() not helping and also the ListView.invalidateViews not helping.
when I rotate the device the list updated.
how can I load the list view in the same way the screen rotation do it?
This is the code on create that fill the list view.
thanks in advance.
query = new ParseQuery(PET_CLASS_NAME);
petListView.addHeaderView((View)getLayoutInflater().inflate(R.layout.header_row, null));
petDetailIntent = new Intent(getApplicationContext(), PetDetailActivity.class);
selectCityIntent = new Intent(this, CitiesActivity.class);
loadingIntent = new Intent(getApplicationContext(), LoadingActivity.class);
startActivityForResult(loadingIntent, LOADING_INTENT_CODE);
/*the user see list of pets that are still missing*/
query.whereEqualTo(PET_FOUNDED, false);
selectedCity = settings.getString("cityQuery", "");
if(selectedCity != ""){
query.whereEqualTo(PET_CITY, selectedCity);
}
query.findInBackground(new FindCallback() {
#Override
public void done(List<ParseObject> list, ParseException e) {
if (e == null) { //objects retrieved well
petList.addAll(list);
//MyAdapter
adapter = new MyAdapter(
getApplicationContext(),
android.R.layout.simple_list_item_1,
R.id.tv_pet_name,
petList);
setListAdapter(adapter);
}
else{
toaster(getResources().getString(R.string.error_message_load_pets));
finish();
}
finishActivity(LOADING_INTENT_CODE);
}
});
Use a AsyncTask for loadData from Server. It will load it faster.
Try this out:
private class YourTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... s) {
//Here you have to make the loading / parsing tasks
//Don't call any UI actions here. For example a Toast.show() this will couse Exceptions
// UI stuff you have to make in onPostExecute method
}
#Override
protected void onPreExecute() {
// This method will called during doInBackground is in process
// Here you can for example show a ProgressDialog
}
#Override
protected void onPostExecute(Long result) {
// onPostExecute is called when doInBackground finished
**// Here you can for example fill your Listview with the content loaded in doInBackground method**
}
}
And than you just have to call this AsyncTask always if you loading content from your server:
new YourTask().execute("");
Try it out!.. Hope this helps..
When you rotate the device, the activity is actually started stopped and started and your initial request will be made again.
You should place your request code into a method and recall it yourself
Similar to what Rawkode mentioned, it doesn't seem like the code that actually does the work of retrieving data from the server is reusable (since it lives in onCreate()). Take a look at this diagram: http://developer.android.com/images/activity_lifecycle.png. As you can can see, the onCreate() method only gets executed once, unless the Activity is re-created (i.e. rotating screen).
Also, from the given code, there doesn't seem to be evidence of a refresh method either. How will users be able to refresh the data? Consider refactoring your code such that the work is done in a method that you can call later on (i.e. refreshData()) and then figure out a way in which you would like your users to refresh. For example, you can use either the ActionBar with a refresh ActionItem, or a menu option or even a button.
Related
Experts,
My goal is simple, input an address, click a button to test a URL, if not get the expected result, a toast info and then do nothing. If get expect result, continue the program.
Since I can not use URL in UI thread, I used AsyncTask, the problem is: though I know the result from AsyncTak, how to inform activity to do or do nothing?
What I want is a statement inside the OnClickListener like this:
if (result is not expected) return; else continue do things.
I cannot write above statement in onPostExecute, it will return onPostExecute(), not onClickLIstener().
Another is: even if I can pass the result to activity(namely to onClickLIstener()), when the result arrives, probably UI thread already run some other codes, but they shouldn't before knowing the result.
In short, I need the URL result to decide how to run remaining codes, therefore cannot use async task, what should I do?
Thanks.
Below is the example code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
btnConfirm.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new XXX().execute(code);
});
}
class XXX extends AsyncTask<String, Void, String> {
protected String doInBackground(String... strArr) {
XXXXX;
}
protected void onPostExecute(String result) {
XXXXX;
}
}
This should be easy. Try this approach:
Since you already have your AsyncTask as an inner class in your activity, you can easily return a result in onPostExecute() then check if request was successful or not.
Now, here is the final part: create a method in your activity like this:
private void executeOnAsyncSuccess(){
//place the code here you want to run
}
Now you can call it inside onPostExecute() easily!
You can also do this using Events but this approach should just work!
I hope this helps!
I just learned that maybe Callable is a good way, use its V get().
I'm working on a web application that will parse the site and load the news dynamically into the CardView. For now it works and does all the needed stuff. But it's not exactly what I want.
Here's a piece of my code to understand what I am talking about:
public class NewsPage extends ActionBarActivity {
List<NewCard> listNC = new ArrayList<NewCard>();
class NewsParser extends AsyncTask<Void,Void,List<NewCard>> {
Document doc;
List<NewCard> nc = new ArrayList<NewCard>();
ProgressDialog progressDialog;
#Override
protected void onPreExecute()
{
// progressDialog= ProgressDialog.show(NewsPage.this, "Parsing the site", "Please wait while the information is loading...", true);
};
#Override
protected List<NewCard> doInBackground(Void... params) {
try {
//some code skipped
nc.add(new NewCard(forHeader.html(), forDesc, URLforImg, forHeader.attr("href")));
}
} catch (IOException e) {
e.printStackTrace();
}
return nc;
}
protected void onPostExecute(String[] s) {
progressDialog.dismiss();//This method is being called out by new <class name>.execute();
//listNC = new ArrayList<NewCard>(nc);
}
}
In here I am retrieving article headlines for further opening.
This is my onCreate() method:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_news_page);
RecyclerView recList = (RecyclerView) findViewById(R.id.cardList);
recList.setHasFixedSize(true);
LinearLayoutManager llm = new LinearLayoutManager(this);
llm.setOrientation(LinearLayoutManager.VERTICAL);
recList.setLayoutManager(llm);
try {
NewsParser np = new NewsParser();
np.execute();
listNC = np.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
NewsAdapter na = new NewsAdapter(listNC);
size = na.sizes;
recList.setAdapter(na);
I'm using my adapter to fill the cards with information and to handle onClick events.
My question is this:
I need to retrieve information from my AsyncTask in order to create a
list of cards (in this case I need an amount of cards) and I am not
sure I can go on without returning values. But it makes my app freeze
and not show any interface until the action is completed. How is it
better to handle? Maybe I need to make it all different? How do I
load news headlines separately (not all together but in order)? And
what kind of loop (I don't know how to call it correctly) do I need
to add news as they load (because my program doesn't work if it
doesn't have the list before doing UI stuff)?
I've tried to tell every detail from my code and if it's needed I might add my Adapter code too.
Your UI is freezing because your get() method in the try block is blocking waiting on the AsyncTask to complete. This defeats the purpose of even using the AsyncTask. Instead, create your Adapter before you kick off the AsyncTask and then in the onPostExecute() set the data for the adapter to be the new result and call the adapter's notifyDataSetChanged() method. This will cause the UI to pick up the changes.
Be careful with your use of AsyncTask or any other threading mechanism. They are not lifecycle aware, so if the onPostExecute() method has any strong references to the Activity or its inner member fields and tries to directly use them it could run into state exceptions.
This is part of my application. (You can run code below as an isolated application) On that website (url), using php language, parse some numbers from other website, and make an array and encode it to JSON array, and show.
But, with the code below (without dismiss function!) ProgressDialog appears after doInBackground.
When I add dismiss function to onPostExecute like below, it never appears. But When I set log for checking dialog window, it says that there was an dialog.
I heard that doInBackground freezes UI, but it freezes before dialog is shown.
Other similar questions have found solution, erasing .get() from mAsyncTask().execute().get(), but I don't have any get() in my code.
Boolean variable loadfinish is for waiting finishing asynctask, to show results from that website after asynctask. If I delete
while(loadFinish == false)
there, it automacally appears and disappears very well, but I can't show result immediately...
Add) I found that it takes several seconds to dialog appear after doInBackground... why?!
Add2) I've tried to move dialog codes before and after new mAsyncTask().execute(), but it doesn't work too...
public class MainActivity extends Activity {
boolean loadFinish;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button start = (Button) findViewById(R.id.start);
//just a button for starting asynctask
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
loadFinish = false;
new mAsyncTask().execute();
// get and make json array to java array
while (loadFinish == false)
;
}
});
// add array to Custom_List_Data, and set custom row_adapter to listView.
// if I delete while(loadFinish == false), array with initial data is added.
}
private class mAsyncTask extends AsyncTask<String, String, String> {
ProgressDialog dialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new ProgressDialog(MainActivity.this);
dialog.setMessage("asdf");
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.show();
}
#Override
protected String doInBackground(String... params) {
String url = "http://songdosiyak.url.ph/MouiRate/etoos/3/main/";
String response_str = "";
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(url);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
try {
response_str = client.execute(request, responseHandler);
} catch (ClientProtocolException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
loadFinish = true;
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
dialog.dismiss();
}
}
}
Sorry for my poor English language skill and thank you for reading!
As Gabe mentioned you don't need the loop, all you need is some more understanding what the async methods should do.
You introduced the result, because you want to display the result. All you have to do is to return your response_str in doInBackground. It will be then available to you as a param to onPostExecute where you can easily display it, or do whatever you need to do with it.
So to summarize:
Remove the loop
Return value response_str or whatever from doInBackground
Display value in onPostExecute
And remove loadFinish variable as its not needed at all
Hope that helps.
Because you're using an AsyncTask totally wrong. You're busy looping waiting for it to finish. NEVER do that- if you're doing that there's no point in using an AsyncTask. At any rate, the reason it won't appear is that the UI doesn't update until the UI thread returns to the event loop inside the Android Framework and runs the drawing code, which happens after onClick returns. So you won't draw until your busy loop exits, which happens after doInBackground finishes.
The solution is to remove the loop waiting for the AsyncTask to finish in your onClick. If you have logic that needs to run after it, put it in onPostExecute.
It may be worth looking into using an async library.
Using a library to help handle async callbacks can be super helpful for this as you can start the spinner, call your api, then stop the spinner in either the onSuccess function, or your success callback method in your class.
This is the one I usually use:
LoopJ's Async HTTP Callback Library
This will handle GET and POST requests with a lot of cool features such as custom timeouts, JSON format, onSuccess() and onFailure() methods, etc. There's a lot of working examples of this library too. I've used it in all my apps and haven't had any problems yet!
Hopefully this helps.
On my android app, I use the Parse.com online database to store my data. In the onCreate() method of my activity, I use the method findInBackground() to asynchronously load data.
The findInBackground() method does not initially reconnect to the activity and continue to run forever. However, if I click on the home button of my phone and then re-load the app, the findInBackGround() method finally reconnects and load the data.
I would like to:
make the findInBackground() method reconnect with the activity without needing to reload the app
show a loading image (animated gif ?) while data is loading.
Would you guys have any advice on my problem ?
Thank you in advance for your help,
Alex
PS: I already tried the find() method of parse. Even if it reconnects automatically with the app, I don't think it's the right way to proceed since it blocks the UI of the caller activity until data is loaded.
==================================================================================
I finally found the answers to my questions:
I put the code to populate the listView INSIDE a method of the findCallBack class. Thus, I make sure I will use the result of the findInBackground() method only AFTER it has finished run. Previously, I had put the code to populate the listView OUTSIDE of the findCallBack class, so even if it came after in my code, it was actually executed before the end of findInBackground(), so didn't work.
For the loading image, I used an answer found on this site, which consists in activitating and stopping a ProgressDialog at the appropriate time (before and after findInBackground()).
startLoading(); //Show the loading image
query.findInBackground(new FindCallback() {
public void done(List<ParseObject> allQuestionsVal, ParseException e) {
if (e == null) {
for(int i = 0; i<=allQuestionsVal.size()-1;i++){
ParseObject questionVal = allQuestionsVal.get(i);
Question question = new Question(questionVal.getObjectId(),
questionVal.getString("FIELD1"),
questionVal.getString("FIELD2"),
allQuestions.add(question);
}
stopLoading(); //Remove the loading image
//Use the result of the Query (allQuestions) to populate listVIew
ListView list = (ListView) findViewById(R.id.all_questions);
AllQuestionsAdapter adapter=new AllQuestionsAdapter(AllQuestions.this, allQuestions);
list.setAdapter(adapter);
}
else {
stopLoading(); //Remove the loading image
}
}
});
protected ProgressDialog proDialog;
protected void startLoading() {
proDialog = new ProgressDialog(this);
proDialog.setMessage("loading...");
proDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
proDialog.setCancelable(false);
proDialog.show();
}
protected void stopLoading() {
proDialog.dismiss();
proDialog = null;
}
PS: any comments are welcomed :)
I am trying to update my list and display the updated list in my activity. Every time I do so I get the following error
The content of the adapter has changed but ListView did not receive a notification.
Make sure the content of your adapter is not modified from a background thread,
but only from the UI thread.
Here is my code, I am using an AsyncTask to achieve this task. I call notifyDataSetChanged() on my adapter but it does not seem to work. What am I doing wrong?
class MyTask extends AsyncTask<Context, Integer, String> {
#Override
protected String doInBackground(Context... params) {
GregorianCalendar currentDateclone = (GregorianCalendar) currentDate.clone();
ListPopulater2.listPopulate(currentDateclone, 7, items, Id);
//method to update list info
}
// -- gets called just before thread begins
#Override
protected void onPreExecute() {
progressdialog = ProgressDialog.show(SectionListExampleActivity.this, "", "Loading..."); //display progress bar
super.onPreExecute();
}
// -- called as soon as doInBackground method completes
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Log.d("postExecute", "here");
adapter.notifyDataSetChanged();
progressdialog.cancel();
}
}
Try moving:
ListPopulater2.listPopulate(currentDateclone, 7, items, Id);
to your onPostExecute.
The reason that this worked is because you need to update the list after you've completed all your background activity, not while you are doing it. You can use the onProgressUpdate, but that is for your progress dialog. Updating you list view should be done after you have all you data, otherwise, you will get the error you did because the UI runs on the main thread, and you are trying to update it with the background thread.
As for the progress dialog, there is a purpose. If you are doing something that is going to take awhile to complete, the dialog will tell the user how close you are to completing the background task.
Hope that makes sense.
When Ever you want to do something which deal with the UI you have to do that task in UI thread.
So for this you can use 2 approach:
use runOnUi() method
Use OnPostExecute() method
And you have to use notifyDatasetchanged() at that place where you are setting adapter in listView.