I have a custom List which I want to refresh when a action bar button is clicked.
This List is within a Fragment.
I want to show a ProgressBar until the List is refreshed.
Currently Iam doing this:-
private class RefreshList extends AsyncTask<Void, Void, Void>
{
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
if(refDialog!=null)
{
refDialog.dismiss();
}
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
if(refDialog!=null)
{
refDialog =null;
}
refDialog = WaitProgressFragment.newInstance();
refDialog.show(getFragmentManager(), "Wait");
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
//stagAdaper.notifyDataSetChanged();
itemsAdapter.notifyDataSetChanged();
return null;
}
}
But I get this error
Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
How can I refresh the List while showing the progress dialog?
Put
itemsAdapter.notifyDataSetChanged();
Inside onPostExecute.
notifyDataSetChanged is an UI operation and doInBackground does not work on UI thread, whereas onPostExecute does.
You have to move the portion of the background task to the UI thread,so notify itemsAdapter in onPostExecute method as
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
itemsAdapter.notifyDataSetChanged()
if(refDialog!=null)
{
refDialog.dismiss();
}
}
Related
I create the content of a ListView in the background and when each item is added I update the ListView adapter.Usually it works ok but some times I get this error. And strangely enough it happens 10 times more often in my Galaxy s4 mini than in my HTC Sensation. I don't understand why this happens since I clearly notify the adapter through the UI thread. Any thoughts ?
java.lang.IllegalStateException: 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. Make sure your adapter calls
notifyDataSetChanged() when its content changes. [in ListView(2131100779, class
util.TouchInterceptor) with Adapter(class com.bill.deuterh.ListActivity$ListAdapter)]
AsyncTask:
private class AsyncCaller extends AsyncTask<Void,Void,Void>{
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
ListActivity.this.runOnUiThread(new Runnable(){
#Override
public void run() {
findViewById(R.id.progress_bar).setVisibility(View.GONE);
}
});
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
for (int i=0;i<table.length;i++){
if(isCancelled()){break;}
myList.add(createObject(table[i])));
ListActivity.this.runOnUiThread(new Runnable(){
#Override
public void run() {
ListAdapter.notifyDataSetChanged();
}
});
}
return null;
}
}
(If it matters, I cast the Listview as TouchInterceptor which is a modified google class for supporting the rearrangement of the listview items with drag and drop.)
Try this: If everything else has correct set up. Then this code will Show every update from your doInBackground immediatly in the listview = good user experience!
private class AsyncCaller extends AsyncTask<Void,Void,Void>{
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
findViewById(R.id.progress_bar).setVisibility(View.GONE);
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
for (int i=0;i<table.length;i++){
if(isCancelled()){break;}
myList.add(createObject(table[i])));
publishProgress();
}
return null;
}
protected void onProgressUpdate(Void.. values) {
ListAdapter.notifyDataSetChanged();
}
}
OnPreExecute, onPostExecute and onProgressUpdate are already running on the UIThread. Maybe you don't execute the asynctask the right way. That's why no data has been updated?
This should be run only once at the end of onpostexecute without the need of runonuithread.
ListAdapter.notifyDataSetChanged();
remove this:
ListActivity.this.runOnUiThread(new Runnable(){
#Override
public void run() {
ListAdapter.notifyDataSetChanged();
}
});
and put this:
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
findViewById(R.id.progress_bar).setVisibility(View.GONE);
ListAdapter.notifyDataSetChanged();
}
Don't write any code in doInBackground(Void... params) which relates or update the UI. For updation on UI Async's onPostExecute(Void result) method is used.
So remove the adatper's notification from doInbackGround(Void... params){}
I am showing some animation and making network request at the same time. Both are working fine independently. But when I try to place a progress dialog in asynctask the animation is not started until progress dialog until the onPostExecute(). My guess is that as the animation and progressdialog both run on the UI thread so only one can run at a time. Is there a way to show progress dialog and run animation at the same time both on the UI thread?
Here's my code:
public class DailyTarrotActivity extends FragmentActivity {
ImageView imageViewAnimation;
AnimationDrawable spinAnimation;
AnimatorSet set = new AnimatorSet();
FlipImageView imageViewCard;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_daily_tarrot);
imageViewAnimation = (ImageView) findViewById(R.id.imageViewAnimation);
imageViewAnimation.setBackgroundResource(R.drawable.spin_animation);
imageViewCard = (FlipImageView) findViewById(R.id.imageViewCard);
spinAnimation = (AnimationDrawable) imageViewAnimation.getBackground();
new DailyTarrotAsyncTask().execute();
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
// TODO Auto-generated method stub
super.onWindowFocusChanged(hasFocus);
Log.d("start", "focuschange");
if (hasFocus) {
spinAnimation.start();
}
}
public class DailyTarrotAsyncTask extends AsyncTask<Void, Void, Void> {
ProgressDialog pd;
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
pd = new ProgressDialog(DailyTarrotActivity.this);
pd.setCancelable(false);
pd.show();
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
Thread thread = new Thread();
try {//just to mimic downloading behaviour
thread.sleep(10000);//animation starts only after 10 secs
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
pd.dismiss();
Toast.makeText(DailyTarrotActivity.this, "async task finished",
Toast.LENGTH_SHORT).show();
}
}
}
In my application when i click on Button it sometimes shows the progressdialog and sometimes not show the progressdialog on click of button.
Asynchronous Task code is:
public class LoadData extends AsyncTask<Void, Void, Void>
{
ProgressDialog pd;
#Override
protected void onPreExecute()
{
pd = ProgressDialog.show(MainActivity.this, "", "Loading...");
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
// TODO Auto-generated method stub
LoadActivities(); // function to load data from url
}
});
return null;
}
#Override
protected void onPostExecute(Void unused)
{
pd.dismiss();
}
}
and on button click event call this as:
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
new LoadMoreData().execute(null);
}
});
the wrong think you are doing is that in doInBackground you use runOnUiThreade . just remove that from your code . It solves your problem.
never use any thread in doInBackground.
Why you have taken run method again in doInBackground, doInBackground method performs computation on a background thread, so no need to take runOnUiThread
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
// TODO Auto-generated method stub
LoadActivities(); // function to load data from url
}
});
Just write
protected Boolean doInBackground(final String... args) {
try {
LoadActivities();
return true;
} catch (Exception e) {
Log.e("tag", "error", e);
return false;
}
}
And also change new LoadMoreData().execute(); don't write null
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
new LoadMoreData().execute();
}});
Nirali's answer seems correct, just to make further explaination and some edits.
Progress Dialog will be shown by the time doInBackground method returns value. and in your code it just create another thread, and completes execution, so to display progress dialog by the time LoadActivities exectues, execute this statement in the same thread doInBackground executes, so change to following:
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
MainActivity.this.runOnUiThread(new Runnable() {
LoadActivities(); // function to load data from url
return null;
}
I want to use progress bar while downloading from server,Actually i was using progressDialog but it will be good look if i use progressBar instead of progressDialog.I have following code for Progress dialog .
public class FeaturedData extends AsyncTask<Void, Void, Void> {
Home home;
ProgressDialog dialog = null;
public FeaturedData(Home home) {
// TODO Auto-generated constructor stub
this.home = home;
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
//calling here method
return null;
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
dialog.dismiss();
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
dialog = ProgressDialog.show(home, "", "", true);
}
As per your below comment:
Actually i want to do it programatically don't want to declare in xml.
=> i would suggest you to take it inside the XMl layout.
Inside the onPreExecute(), make it visible using progressBar.setVisibility(View.VISIBLE)
and inside the onPostExecute(), make it GONE by using progressBar.setVisibility(View.GONE)
hi guy
m using a asynctask for running a progressbar. i am using it for showing my songs duration.i want that when i press stop Button, the asynctask should be stop and progressbar should reach on initial position.
public class BackgroundAsyncTask extends
AsyncTask<Void, Integer, Void> {
int myProgress;
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
Toast.makeText(AudioPlayer2.this,
"onPostExecute", Toast.LENGTH_LONG).show();
seekbar.setClickable(true);
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
Toast.makeText(AudioPlayer2.this,
"onPreExecute", Toast.LENGTH_LONG).show();
myProgress = 0;
//seekbar.setProgress(myProgress);
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
while(myProgress<100){
myProgress++;
//seekbar.setProgress(myProgress);
publishProgress(myProgress);
Log.d("AAAAAAAAAAAAAAAAAAAAAAAAAAAAA", bundleDuration);
SystemClock.sleep(2000) ;
}
return null;
}
#Override
protected void onCancelled() {
super.onCancelled();
// myProgress=0;
// seekbar.
publishProgress(0);
seekbar.setProgress(0);
}
#Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
seekbar.setProgress(values[0]);
}
}
//=====================================
for starting and stopping m using this code
public void onClick(View src) {
switch (src.getId()) {
case R.id.buttonStart:
new BackgroundAsyncTask().execute();
break;
case R.id.buttonStop:
backgrondasynctask.cancel(true);
break;
I think you use wrong method for this example. You can easily implement progress bar. Here is a nice article,http://blog.sptechnolab.com/2011/01/17/android/simple-progress-bar-in-android-using-thread/ contains example to implement progress bar. Through this example you can easily start, stop and play the progress bar.