ProgressBar - Not Updating in AsyncTask - java

Hi just had a quick question about why my progressbar isn't updating. I will add comments in the below to demonstrate what is working and what isn't.
To my knowledge it should be working since it updates in an asynctask.
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
if (!(data.get(position) instanceof TemporarySongInfomation)) {
SongViewHolder holder;
view = inflater.inflate(R.layout.music_list_format, null);
holder = new SongViewHolder();
holder.timesplayed = (TextView) view.findViewById(R.id.textView7);
holder.artist = (TextView) view.findViewById(R.id.textView6);
holder.title = (TextView) view.findViewById(R.id.textView5);
holder.imagebutton = (ImageButton) view.findViewById(R.id.playbutton);
holder.source = (TextView) view.findViewById(R.id.textView8);
tempValue = (SongInfomation) data.get(position);
String songName = tempValue.getName();
holder.imagebutton.setBackgroundResource(R.drawable.playbutton1);
holder.source.setText(tempValue.getVideoid());
holder.title.setText(songName.length() > 45 ? songName.substring(0, 38) + "..." : songName);
holder.timesplayed.setText("" + tempValue.getTimesplayed());
holder.artist.setText(tempValue.getArtist());
swipeDetector = new SwipeDetector();
view.setOnClickListener(new SongListOnItemClickListener(position));
view.setOnTouchListener(swipeDetector);
holder.imagebutton.setOnClickListener(new OnPlayButtonClickListener(position));
} else {
TemporarySongViewHolder holder;
view = inflater.inflate(R.layout.music_list_process_format, null);
holder = new TemporarySongViewHolder();
holder.artist = (TextView) view.findViewById(R.id.artisttemp);
holder.bar = (ProgressBar) view.findViewById(R.id.ppbar);
holder.title = (TextView) view.findViewById(R.id.titletemp);
holder.source = (TextView) view.findViewById(R.id.sourcetemp);
tempValue1 = (TemporarySongInfomation) data.get(position);
String songName = tempValue1.getName();
holder.source.setText(tempValue1.getVideoid());
holder.title.setText(songName.length() > 45 ? songName.substring(0, 38) + "..." : songName);
holder.artist.setText(tempValue1.getArtist());
holder.bar.setMax(100);
// the below line starts the task!
new UpdateProgressBar(holder.bar, tempValue1).execute();
}
return view;
}
private class UpdateProgressBar extends AsyncTask<Void, Void, Void> {
private TemporarySongInfomation songinfo;
private ProgressBar progress;
UpdateProgressBar(ProgressBar bar, TemporarySongInfomation tp) {
progress = bar;
songinfo = tp;
}
#Override
protected Void doInBackground(Void... params) {
while (!songinfo.isCompleted()) {
System.out.println("going " + (int) songinfo.getProgress());
// the above line prints different values for songinfo.getProgress()
progress.setProgress((int) songinfo.getProgress());
publishProgress();
System.out.println("Progress "+progress.getProgress());
// the above line only prints "Progress 0"
// and obviously the ui doesnt update.
try {
Thread.sleep(500);
} catch (Exception e) {
}
}
return null;
}
}

publishProgress(Progress...) calls onProgressUpdate(Progress...)
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.
so basically you need to update the UI thread from onProgressUpdate method.
Here an example:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}

This part is wrong
progress.setProgress((int) songinfo.getProgress());
publishProgress();
You need to update the progress bar from the UI thread. So to update progress, you must override onProgressUpdate, which is run on the UI thread, and update your progress bar from there.
in doInBackground, do this
publishProgress((int) songinfo.getProgress()); // this calls onProgressUpdate on the UI thread
then, in onProgressUpdate, do this
progress.setProgress(values[0]); // called on UI thread
You will also need to change your AsyncTask class definition
private class UpdateProgressBar extends AsyncTask<Void, Integer, Void> { // Integer progress type

Related

Android ListViewItem update Progressbar in row

I'm using ListView with custom list rows,where every ListItem has ProgressBar in it.
When the user click the ImageView,the app starts an AsyncTask to download a file from a remote server,and update the progress in progress bar.
I'm using Parallel async tasks,which mean app can launch multiple downloads and update them in the ProgressBar of each row.
This is the code
static class ViewHolder {
protected TextView title;
protected TextView size;
protected TextView version;
protected ImageView appIcon;
protected ProgressBar progressBar;
}
public class UpdateAdapter extends ArrayAdapter<UpdateItem> {
public UpdateAdapter(Context context, ArrayList<UpdateItem> users) {
super(context, 0, users);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
UpdateItem updateItem = getItem(position);
View v = convertView;
ViewHolder viewHolder;
LayoutInflater mInflater = LayoutInflater.from(getContext());
if (convertView == null) { // if convertView is null
convertView = mInflater.inflate(R.layout.row, null);
viewHolder = new ViewHolder();
viewHolder.title = (TextView) convertView.findViewById(R.id.apptitlelabel);
viewHolder.version = (TextView) convertView.findViewById(R.id.versionlabel);
viewHolder.size = (TextView) convertView.findViewById(R.id.sizelabel);
viewHolder.appIcon = (ImageView) convertView.findViewById(R.id.appicon);
viewHolder.progressBar = (ProgressBar) convertView.findViewById(R.id.downloadProgressBar);
convertView.setTag(viewHolder);
} else
viewHolder = (ViewHolder) v.getTag();
viewHolder.progressBar.setProgress(0);
View finalConvertView = convertView;
viewHolder.appIcon.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DownloadFileFromURL task = new DownloadFileFromURL();
task.position = position;
task.v = finalConvertView;
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, updateItem.downloadlink);
}
});
return convertView;
}
class DownloadFileFromURL extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Bar Dialog
**/
int position;
View v;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
/**
* Downloading file in background thread
**/
#Override
protected String doInBackground(String... f_url) {
int count;
try {
URL url = new URL(f_url[0]);
URLConnection conection = url.openConnection();
conection.connect();
// this will be useful so that you can show a tipical 0-100%
// progress bar
int lenghtOfFile = conection.getContentLength();
// download the file
InputStream input = new BufferedInputStream(url.openStream(),
8192);
// Output stream
String fileExtenstion = MimeTypeMap.getFileExtensionFromUrl(url.getPath());
String fname = URLUtil.guessFileName(url.getPath(), null, fileExtenstion);
OutputStream output = new FileOutputStream(Environment
.getExternalStorageDirectory().toString() + "/" + fname);
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
// publishing the progress....
// After this onProgressUpdate will be called
publishProgress("" + (int) ((total * 100) / lenghtOfFile));
// writing data to file
output.write(data, 0, count);
}
// flushing output
output.flush();
// closing streams
output.close();
input.close();
} catch (Exception e) {
Log.e("Error: ", e.getMessage());
}
return null;
}
/**
* Updating progress bar
**/
protected void onProgressUpdate(String... progress) {
// setting progress percentage
// Log.w(TAG, progress[0]);
updateStatus(position, Integer.parseInt(progress[0]));
}
/**
* After completing background task Dismiss the progress dialog
**/
#Override
protected void onPostExecute(String file_url) {
// dismiss the dialog after the file was downloaded
Log.w(TAG, "onPostExecute: ");
removeListItem(v, position);
}
}
public void updateStatus(int index, int Status) {
int in = index - updateLv.getFirstVisiblePosition();
View v = updateLv.getChildAt(in);
ProgressBar progress = (ProgressBar) v.findViewById(R.id.downloadProgressBar);
progress.setProgress(Status);
}
The problem is ,when the user starts two downloads(say hit the first the second imageviews),and the first task has been completed,and the first row getting removed from the list,in onPostExecute,now,the second row turns into the first row,but the task updates the current second row(which was the third before the first item removed...)
I know it happens because I pass into updateStatus,the position of the item to be updated,but in the meantime the ListView Changes and removes items(because their download has been completed),but I have no current solution for this...
I even tried passing a ProgressBar object reference to updateStatus method ,instead of using item position,and I thought it would solve the problem...but no luck :)

How do I go about applying data I get from doInBackground() to apply to my RecyclerView?

I have viewed over 50 pages to find solution for my extremely simple app, but none seems to work for me. Please help.
Problem: I have a refresh button in the menu in MainActivity. When this is pressed, I want to execute my AsyncTask, then update ALL items in my RecyclerView.
Situation.
My app fetches data from API by OpenWeatherMap.org, then displays the data.
I have a MainActivity class (And my recyclerView resides in here.)
For recyclerView, I'm using RecyclerView.Adapter with GridViewManager.
I have a separate AsyncTask class.
So, what I have tried and did not work:
Method 1. Normal way. When refresh button selected, call my AsyncTask. In my PostExecute(), I am calling setter in the MainActivity
public void setWeatherData(String[] weatherData) {this.weatherData = weatherData;}
to assign the result array from doInBackGround method.
Then in MainActivity,
myAsyncTask.execute("43017,us");
recyclerView.recyclerView.getAdapter().notifyDataSetChanged();
But this causes notifyDataSetChanged(); to be called BEFORE member vairable array in MainActivity is updated from onPostExecute().
Method 2. Trying to update UI entirely from onPostExecute method in MyAsyncTask.class.
Well I know onPostExecute, even when it is written in different class, runs on the UI thread. So within the method, I did something like
MainActivity mainActivity = new MainActivity();
RecyclerView recyclerView = mainActivity.findViewById(R.id.recyclerView);
RecyclerView.Adapter adapter = recyclerView.getAdapter();
adapter.notifyDataSetChanged();
In this method, with logging, I've confirmed that onPostExecute successfully updates the member variable in the MainActivity, it's just that notifyDataSetChanged gets called TOO early, specifically before onPostExecute is complete in the background.
I hope to get an answer for this and was clear enough about my situation. I will post my MainActivity, Adapter and AsyncTask codes down below.
MainActivity.java:
public class MainActivity extends AppCompatActivity {
private String weatherData[] = {
"Today - Sunny",
"Tomorrow - Cloudy",
"Tuesday - Rainy",
"Wednesday - Sunny",
"Thursday - Sunny",
"Friday - Sunny",
"Saturday - Cloudy",
"Sunday - Rainy :/"
};
private RecyclerView recyclerView;
private mAdapter adapter;
private static final int SPAN_COUNT = 1;
private MyAsyncTask myAsyncTask = new MyAsyncTask();
private Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView)findViewById(R.id.recyclerview_weatherData);
setLayout(getApplicationContext());
adapter = new mAdapter(weatherData);
recyclerView.setAdapter(adapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id){
case R.id.action_refresh:
Log.v("Menu", "Refresh button selected.");
//for now, take some random ZIP code
myAsyncTask.execute("43017,us");
recyclerView.getAdapter().notifyDataSetChanged();
adapter.refreshContents(weatherData);
for (int i = 0; i<weatherData.length; i++) {
Log.v("Refresh button", weatherData[i].toString());
}
}
return true;
}
public void setLayout(Context context) {
int scrollPosition = 0;
//make a GridLayoutManager with 2 columns
LinearLayoutManager mLayoutManager = new LinearLayoutManager(context);
//set the mLayoutManager to the one that I just created
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.scrollToPosition(scrollPosition);
recyclerView.setLayoutManager(new GridLayoutManager(context, SPAN_COUNT));
//set the offset decoration definition to my layout
int middle_spacing = 30;
boolean includeEdge = true;
recyclerView.addItemDecoration(new ItemOffsetDecoration(SPAN_COUNT, middle_spacing, includeEdge));
}
public void setWeatherData(String[] weatherData) {
this.weatherData = weatherData;
}
public String[] getWeatherData() { return weatherData; }
}
MyAsyncTask.java:
public class MyAsyncTask extends AsyncTask<String,Void,String[]> {
public final static String OPEN_WEATHER_MAP_API_KEY = "bc607b72747aa672bf2ac9a5f3a5fc84";
String forecastJsonStr = null;
private String format = "json";
private String units = "metric";
private int numDays = 7;
private String data[] =null;
private RecyclerView recyclerView;
private MainActivity mainActivity;
private RecyclerView.Adapter adapter;
#Override
protected String[] doInBackground(String... params) {
if (params.length == 0) {
Log.v("AsyncTask", "No parameter is taken.");
return null;
}
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
try {
final String FORECAST_BASE_URL = "http://api.openweathermap.org/data/2.5/forecast/daily?";
final String QUERY_PARAM = "q";
final String FORMAT_PARAM = "mode";
final String UNITS_PARAM = "units";
final String DAYS_PARAM = "cnt";
final String APPID_PARAM = "APPID";
Uri builtUri = Uri.parse(FORECAST_BASE_URL).buildUpon()
.appendQueryParameter(QUERY_PARAM, params[0])
.appendQueryParameter(FORMAT_PARAM, format)
.appendQueryParameter(UNITS_PARAM, units)
.appendQueryParameter(DAYS_PARAM, Integer.toString(numDays))
.appendQueryParameter(APPID_PARAM, OPEN_WEATHER_MAP_API_KEY)
.build();
URL url = new URL(builtUri.toString());
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
return null;
}
//put the buffer in String var forecastJsonStr
forecastJsonStr = buffer.toString();
Log.v("AsyncTask", forecastJsonStr.toString());
} catch (IOException e) {
return null;
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("Async", "Reader is null, something wrong.");
}
}
}
//Then put the string contents into an array
try {
ParseWeatherData parser = new ParseWeatherData();
data = parser.getWeatherDataFromJson(forecastJsonStr, numDays);
return data;
} catch (JSONException e) {
e.printStackTrace();
}
return data;
}
#Override
protected void onPostExecute(final String data[]) {
super.onPostExecute(data);
if (data != null) {
//this log works fine: the fetched data is successfully stored...
for (int i = 0; i<data.length; i++) {
Log.v("onPostExecute", data[i].toString());
}
//how do I pass this data to the main thread?
mainActivity = new MainActivity();
mainActivity.setWeatherData(data);
}
}
}
Finally, mAdapter.java:
public class mAdapter extends RecyclerView.Adapter<mAdapter.ViewHolder> {
private String data[];
public mAdapter(String data[]) {
this.data = data;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View listView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_single_list, parent, false);
return new ViewHolder(listView);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.weather.setText(data[position]);
Log.v("BindView", "Item " + position + " set.");
}
#Override
public int getItemCount() {
if (data == null) {
Log.v("WeatherAdapter", "Oops, getting null in the adapter.");
return 0;
} else {
return data.length;
}
}
public void refreshContents(String data[]) {
this.data = null;
this.data = data;
notifyDataSetChanged();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView weather, day;
//currently ViewHolder is set as the TextView for logging
public ViewHolder(View v) {
super(v);
weather = (TextView) v.findViewById(R.id.test_text);
// Define click listener for the ViewHolder's View.
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "Element " + getAdapterPosition() + " clicked.");
}
});
}
}
}
Thank you in advance!
First don't create new object of MainActivity in MyAsyncTask. Actually what's happening is AsyncTask runs on a new Thread so when you do
myAsyncTask.execute("43017,us");
recyclerView.getAdapter().notifyDataSetChanged();
adapter.refreshContents(weatherData);
then myAsyncTask runs in a different thread and the next lines start executing right before .execute without waiting for asynctask to finish and even if it waits for the asynctask to finish, creating a new object to update the data in MainActivity is not gonna work. So what you can do to update your list from onPostExecute method is pass your Activity to myAsyncTask from parameters. Don't initialize your myAsyncTask in the beginning, just remove the = new MyAsyncTask() from private MyAsyncTask myAsyncTask = new MyAsyncTask(); in MainActivity and now replace the lines in MainActivity with this:
Instead of this in your MainActivity
myAsyncTask.execute("43017,us");
recyclerView.getAdapter().notifyDataSetChanged();
adapter.refreshContents(weatherData);
for (int i = 0; i<weatherData.length; i++) {
Log.v("Refresh button", weatherData[i].toString());
}
Write this
myAsyncTask = new MyAsyncTask(this);
myAsyncTask.execute("43017,us");
and to refresh the contents you can make your adapter public so that you could call notifydatasetchanged from myAsyncTask itself but if you want to follow your code written after .execute then you can move it to a new method something like below
public void refreshList(){
recyclerView.getAdapter().notifyDataSetChanged();
adapter.refreshContents(weatherData);
for (int i = 0; i<weatherData.length; i++) {
Log.v("Refresh button", weatherData[i].toString());
}
}
and now what's left is getting context of your MainActivity in MyAsyncTask and refreshing your list in onPostExecute. So make changes like following:
Create a constructor of your MyAsyncTask
public class MyAsyncTask extends AsyncTask<String,Void,String[]> {
MainActivity mainActivity;
public MyAsyncTask(MainActivity mainActivity){
this.mainActivity = mainActivity;
}
Replace this in MyAsyncTask
mainActivity = new MainActivity();
mainActivity.setWeatherData(data);
With this
mainActivity.setWeatherData(data);
mainActivity.refreshList();
I din't tested it myself but i think this should solve your problem. You can try debugging this and see how it is working. And if you face any problems please comment down below.
Edit
Based on the comment by #Ganesh Patil you can create an interface for this solution as well. For the reference of using interface in AsyncTask you can follow this link:
https://stackoverflow.com/a/28958913/7071039
But to keep it simple i didn't used interface and just passed the context of MainActivity in the MyAsyncTask
Editing based on the comment
Dear PC HUB, firstly thank you so much for your very detailed answer.
All of your explanations made sense and I applied the codes. My app
now doesn't crash and all the data is properly passed / retrieved but
somehow mainActivity.refreshList() and
recyclerView.getAdapter().notifyDataSetChanged() is still not working.
Hence, my recyclerView still doesn't change the contents at all... I
am not sure of what to do. – Rikuto Echigoya
change your refreshList into this
public void refreshList(){
/* Check your Weather Data size in this method to find out weather your data is changing or not */
Log.d("Tag","SIZE OF WEATHER DATA : "+weatherData.length);
/* You already have the adapter object so you don't need to
get it using recyclerview.getAdapter. Just do it directly like this */
adapter.notifyDataSetChanged();
// Not changing this as this will not stop your list from refreshing :P
for (int i = 0; i<weatherData.length; i++) {
Log.v("Refresh button", weatherData[i].toString());
}
}
Also make sure that you've called mainActivity.setWeatherData(data); before mainActivity.refreshList(); in your MyAsyncTask.
If it still doesn't solve your problem then share your updated code so that we could see why your list is not getting updated :)

AsyncTask/ or Thread causes list view row to populate value only when scrolled

My app consists of a custom list view and each row contains text.
My MainActivity puts the translated strings into a HashMap called feedData which is retrieved by a CustomListView Class where the TextView for each row is set.
Everything about my custom list view performs perfectly. I am getting this error because I'm implementing the Google API Translation which forces me to use AsyncTask or a Thread. The values populate into each row but only when I scroll up and down.
MainActivity
TranslateString(feedText, feedData);
arrayFeedList.add(feedData);
Translate String Method:
public void TranslateString(final String mText, final HashMap<String, String> mList) {
AsyncTask<Void, Void, Void> asyncTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... voids) {
try {
Translate translate = TranslateOptions.builder().setApiKey("AIzaSyB7cCDBbeoZ2tYTH-Ynv25OaPraLmTG7Hw").build().getService();
Translation translation =
translate.translate(
mText,
TranslateOption.sourceLanguage("tr"),
TranslateOption.targetLanguage("en"));
returnedString = translation.getTranslatedText();
check = 1;
} catch (Exception e) {
check = 2;
}
return null;
}
#Override
protected void onPostExecute(Void result) {
if(check == 1){
mList.put("feed", returnedString);
}
else if(check == 2){
mList.put("feed", mText + " " + getContext().getString(R.string.translationfailed) + " in catch");
}
}
};
asyncTask.execute();
}
}
Doing this in my MainActivity fixed my problem: (After deleting the AsyncTask Method Completely)
if (android.os.Build.VERSION.SDK_INT > 9)
{
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}

When items are redrawn after invoking `invalidateViews()`

When are the items redrawn after invoking invalidateViews() ?
I ask because i try to refresh listItems after a bg-thread notify an image rsc was downloaded.
But nothing is updated. Only after exiting and re-entering the new icons are drawn.
I have an activity with adapter of type SettingValueAdapter extends BaseAdapter
it has a member:
private SettingsValue[] values;
it has two interesting methods:
#Override
public View getView(int position, View view, ViewGroup parent) {
AddressItem ai= (AddressItem)getItem(position);
DriveToNativeManager dnm = DriveToNativeManager.getInstance();
if (view == null) {
LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = li.inflate(R.layout.address_item, null);
}
view.setTag(R.id.addressItem,ai);
view.setTag(position);
view.findViewById(R.id.fullAddressItemCol).setVisibility(View.VISIBLE);
view.findViewById(R.id.addressItemTouch).setVisibility(View.GONE);
view.findViewById(R.id.addressItemImage).setVisibility(View.GONE);
if (ai != null) {
...
}
view.findViewById(R.id.addressItemIconLayout).setVisibility(View.VISIBLE);
Drawable icon = ResManager.GetSkinDrawable(ai.getIcon() + ".bin");
((ImageView)view.findViewById(R.id.addressItemIcon)).setImageDrawable(icon);
..
}
}
public void refreshListIcons() {
// NativeManager nativeManager = AppService.getNativeManager();
// SettingsValue[] values = new SettingsValue[categories.length];
// for (int i = 0; i < categories.length; i++) {
// values[i] = new SettingsValue(categories[i].value, nativeManager.getLanguageString(categories[i].displayString), false);
// values[i].icon = ResManager.GetSkinDrawable(categories[i].iconName + ".bin");
// }
// adapter.setValues(values);
this.runOnUiThread(new Runnable() {
#Override
public void run() {
adapter.notifyDataSetChanged();
}
});
}
I attach a callback to the bg-thread (c language) image downloading process.
The callback switches to the ui-thread and calls this refreshList:
public void refreshSearchIconsOnSearchActivity() {
Runnable refreshViewEvent = new Runnable() {
#Override
public void run() {
Activity currentActivity = AppService.getActiveActivity();
if (currentActivity instanceof SearchActivity) {
Log.d("w", "refreshSearchIconsOnSearchActivity callback running in thread "
+ Thread.currentThread().getId() );
//results list
((SearchActivity) currentActivity).refreshList();
}
}
};
AppService.Post(refreshViewEvent);
}
However, the images are done downloading and are not refreshed on the activity.
They are refreshed only when I leave an re-enter the activity.
What am I missing?
InvalidateViews just causes the listView to redraw itself. It will not call getView to do so, it just resets the current ones on screen- basically it just does
for(View child: getChildren()){
child.invalidate();
}
If you want to update the list, call notifyDataSetChanged on the adaptor.

Progress bar only load one time

My progress bar can only use one time,when i click it second time,it likes a loop,never end,what is the problem?
class ProgressThread extends Thread {
final static int DONE = 0;
final static int RUNNING = 1;
int maxBarValue=100;
int delay=40;
Handler mHandler;
int mState;
int total;
// Constructor with an argument that specifies Handler on main thread
// to which messages will be sent by this thread.
ProgressThread(Handler h) {
mHandler = h;
}
#Override
public void run() {
mState = RUNNING;
total = maxBarValue;
while (mState == RUNNING) {
// The method Thread.sleep throws an InterruptedException if Thread.interrupt()
// were to be issued while thread is sleeping; the exception must be caught.
try {
// Control speed of update (but precision of delay not guaranteed)
Thread.sleep(delay);
} catch (InterruptedException e) {
Log.e("ERROR", "Thread was Interrupted");
}
// Send message (with current value of total as data) to Handler on UI thread
// so that it can update the progress bar.
Message msg = mHandler.obtainMessage();
Bundle b = new Bundle();
b.putInt("total", total);
msg.setData(b);
mHandler.sendMessage(msg);
total--; // Count down
}
total=maxBarValue;
}
public class ProgressBarActivity extends Activity {
ProgressThread progThread;
ProgressDialog progDialog;
Button button1, button2;
int typeBar; // Determines type progress bar: 0 = spinner, 1 = horizontal
int delay = 40; // Milliseconds of delay in the update loop
int maxBarValue = 200; // Maximum value of horizontal progress bar
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Process button to start spinner progress dialog with anonymous inner class
button1 = (Button) findViewById(R.id.Button01);
button1.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
typeBar = 0;
showDialog(typeBar);
}
});
// Process button to start horizontal progress bar dialog with anonymous inner class
button2 = (Button) findViewById(R.id.Button02);
button2.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
typeBar = 1;
showDialog(typeBar);
}
});
}
// Method to create a progress bar dialog of either spinner or horizontal type
#Override
protected Dialog onCreateDialog(int id) {
switch(id) {
case 0: // Spinner
progDialog = new ProgressDialog(this);
progDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progDialog.setMessage("Loading...");
progThread = new ProgressThread(handler);
progThread.start();
return progDialog;
case 1: // Horizontal
progDialog = new ProgressDialog(this);
progDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progDialog.setMax(maxBarValue);
progDialog.setMessage("Dollars in checking account:");
progThread = new ProgressThread(handler);
progThread.start();
return progDialog;
default:
return null;
}
}
// Handler on the main (UI) thread that will receive messages from the
// second thread and update the progress.
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
// Get the current value of the variable total from the message data
// and update the progress bar.
int total = msg.getData().getInt("total");
progDialog.setProgress(total);
if (total <= 0){
dismissDialog(typeBar);
progThread.setState(ProgressThread.DONE);
}
}
};
}
// Set current state of thread (use state=ProgressThread.DONE to stop thread)
public void setState(int state) {
state=ProgressThread.DONE;
mState = state;
}
}
ProgressBar.postInvalidate() you can try this.

Categories