1

So I have a List of job names in a ListView that is generated by a custom adapter that extends BaseAdapter. All items are shown as grayed out initially. For each item, I send an async request through a web service in order to get the status of this job. At the same time, I show an indefinite progress bar in each row. Everytime a response is received, a callback method onSuccess(int itemPosition) gets called for that particular item. itemPosition is the index of the item in the List. In this method I want to set the color of the Text according to received status AND remove the progress bar. I tried the following with no luck:

public void onSuccess(int itemPosition, int status) {
    View convertView = getLayoutInflater().inflate(R.layout.rowlayout, null);
    ((ProgressBar)convertView.findViewById(R.id.progressbar)).setVisibility(ProgressBar.GONE);
    if(status == READY)
        ((TextView)convertView.findViewById(R.id.jobname))
              .setTextColor(status == READY ? Color.GREEN : Color.RED);
        mListViewAdapter.getView(itemPosition, convertView, null);
    }

Any ideas how I should handle this?

ercan
  • 1,639
  • 1
  • 20
  • 34
  • 3
    don't call getView your self. always modify the underlying data, notify the adapter, and let it handle the refreshing of the view. – njzk2 Jan 16 '14 at 13:12
  • Thanks, but I have the following problem. The List is a List of "Job" objects. This object has no field to show if the response is already received or not. Is there any way I can control the visibility of the progress bar from outside, instead of from getView()? – ercan Jan 16 '14 at 13:17
  • And also, I don't want the whole List to be refreshed although only one item is touched. – ercan Jan 16 '14 at 13:17
  • 1
    don't worry about the whole list being refreshed, only the visible elements will, and the double buffering makes sure you don't see it. anyway, you can't have any form of control on the way the listview handles its views. you need to give the adapter some data to make it change the view. putting this data in the job is the most sensible way, imho – njzk2 Jan 16 '14 at 13:19
  • http://stackoverflow.com/a/2679284/1405008 refer this more crisp solution to update the UI only when it displaying in screen. – CoolMonster Jan 16 '14 at 13:22

3 Answers3

2

Any of the other answers involving editing specific Views are not solutions - they will fail the moment you scroll and those ListView rows get recycled! As you scroll, the ListView will continually use the list/array/whatever of Jobs to re-populate themselves. Not to mention, your ListView will not have as many rows as there are Jobs, it will only have as many rows as it needs to fill the screen. So, you will not even be able to access the rows that pertain to Jobs that currently aren't visible. Depending on the device this is on, the orientation, and if you ever change the layout of this screen in the future, the amount of the visible rows/jobs will vary, making this "solution" even worse.

Assuming your custom Adapter is backed by an Array of Jobs (or whatever data structure you've decided to back it with) which is a member of the adapter, simply alter the Array and then call notifyDataSetChanged on the adapter. This is exactly what notifyDataSetChanged is for, and you will not notice the whole ListView refreshing. If you're looking to optimize your ListView performance, at least make sure you're not inflating the row views in every getView call, and then additionally implement the ViewHolder pattern.

Sam Dozor
  • 40,335
  • 6
  • 42
  • 42
1

njzk2 was right. You can set in your adapter an HashMap that store the state 'running' or 'downloaded' for a specified Job object. A method in your adapter allows you to set this information. In your getView, check for the Job object that is inflated if it's 'running' or 'downloaded' and display what you want. This check has to be done even if you've got a convertView.

Groco
  • 1,301
  • 15
  • 19
0

Try doing this inside your activity:

public void onSuccess(int itemPosition, int status) {
View childView = yourListView.getChildAt(itemPostion);
((ProgressBar)childView.findViewById(R.id.progressbar)).setVisibility(ProgressBar.GONE);
if(status == READY)
    ((TextView)childView.findViewById(R.id.jobname))
          .setTextColor(status == READY ? Color.GREEN : Color.RED);

}
Abhishek Shukla
  • 1,242
  • 8
  • 11