Reputation: 171
I am using the code below:
private Runnable returnRes = new Runnable() {
@Override
public void run() {
if(m_orders != null && m_orders.size() > 0){
m_adapter.notifyDataSetChanged();
for(int i=0;i<m_orders.size();i++)
m_adapter.add(m_orders.get(i));
}
m_ProgressDialog.dismiss();
m_adapter.notifyDataSetChanged();
}
};
but the weird thing is, after the list populates, the only item available is the first thing on the list the rows directly below would be empty unless I drag down out of view then back again then it'd show. I'm pretty sure the code above is right as I followed a tutorial. But, I cant expect the user to drag down and back again to see the things involved...
And to add, I just noticed that my datas are not populated properly as this warning would appear 07-19 23:54:49.947: WARN/InputManagerService(58): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@44eb97c0
and I'm quite sure that my codes are correct and the following is where it stops:
public View getView(int position, View convertView, ViewGroup parent){
View v = convertView;
if(v != null){
return v;
}
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row, null);
Log.d("added", "g" + position);
Grade g = grades.get(position);
if(g != null){
TextView name = (TextView) findViewById(R.id.bottomtext);
TextView id = (TextView) findViewById(R.id.toptext);
if(name != null)
name.setText(g.getName());
if(id != null)
id.setText(g.getId());
Log.d("grade", "grade " + g.toString());
}
return v;
}
and from the LogCat trace I would only get to position 3 :( what could be the problem? someone please help me...
LoginByHttpPost gradeIndex = new LoginByHttpPost();
HttpURLConnection gradePage = gradeIndex.doHttpGet(TARGETURL);
String gradeInd = gradeIndex.readResponse(gradePage);
Document doc = Jsoup.parse(gradeInd);
// do more things here
Log.d("grade now ", grades.get(0).text());
Log.d("gradef now ", gradesF.text());
for(int i = 0; i < grades.size(); i += 5){
Grade grade = new Grade();
grade.setId(grades.get(i).text());
grade.setName(grades.get(i + 1).text());
//gradeList.add(grade);
ga.add(grade); //this is my arrayadapter not sure where to add my object to through :(
}
for(int i = 0; i < gradesF.size(); i++){
gradeList.get(i).setGrade(gradesF.get(i).text());
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.d("prob", e.getMessage());
}
this is called from the asyncatask in the function doInBackground()
Upvotes: 9
Views: 11405
Reputation: 31
Same as @ac19 's answer, problem was sloved by adding handler-message.
I use custom adapter and typical ListView, will update data if I get bluetooth callback. When I called "Adapter.notifyDataSetChanged()" in callback function, List didn't updated until I touched screen.
I defiend a message and add following code in callback function (replaced Adapter.notifyDataSetChanged())
Message m = new Message();
m.what = MessageYouDefined;
mHandler.sendMessage(m);
And added handler in onCreate
mHandler=new Handler(){
public void handleMessage(Message msg)
{
switch (msg.what){
case UpdateChargerList:
chargerAdapter.notifyDataSetChanged();
break;
}
super.handleMessage(msg);
}
};
Upvotes: 0
Reputation: 570
Ok, I solved the problem.
There is nothing wrong with the ListAdapter
. The problem is from the parent views of the ListView
.
onMeasure
must be called on the ListView
every time the layout is changed. i.e. onMeasure
or onLayout
is called on one of its parents.
I had a custom view as the parent of the parent of the ListView
. In which I precisely refused to measure the children to make the layout process faster.
Upvotes: 2
Reputation: 2464
As some others have already stated, this problem is caused by the fact that the code is not called on the UI thread since you are executing it from an AsyncTask. Since I cannot comment yet, here's another answer.
I was facing the same issue: I updated the data (which was held in a static context), but the listview did not update after calling notifyDataSetChanged() on the adapter. After dragging/scrolling, the UI is updated and the data automatically refreshed.
The issue is that only the original thread that created a view hierarchy can touch its views. I suppose you are running the Runnable from the callback Thus, you need to call it on the UI thread for the listview to update itself, in a fragment you would do something along the lines of:
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
// Change the data source here,
// eg. some ArrayList<ItemObject> in this case
someDataSource.clear();
someDataSource.add(new ItemObject());
// ...
// And notify the adapter of the changes to the data source
adapter.notifyDataSetChanged();
}
});
If you run adapter.notifyDataSetChanged() outside the UI thread, you will usually also run into a CalledFromWrongThreadException
, some try catch block might have masked that.
Upvotes: 0
Reputation: 1356
i was having the same issue, what i was missing was that the position was not always been sent, for example was skipping (position 0 and 2) and these were no updating until i scrolled.
This fix it for me (See that i used an asynctask) went from this:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
...
new AsyncTask<ViewHolder, Void, Bitmap>() {
private ViewHolder v;
@Override
protected Bitmap doInBackground(ViewHolder... params) {
// Code
}
@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
if (v.position == position) {
// Code
}
}
}.execute(viewHolder);
return convertView;
}
To this (Created an inner class, pass the position in the constructor):
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
....
new DownloadImage(position).execute(viewHolder);
return convertView;
}
private class DownloadImage extends AsyncTask<ViewHolder, Void, Bitmap> {
private ViewHolder v;
private int myPosition;
public DownloadImage(int p) {
myPosition = p;
}
@Override
protected Bitmap doInBackground(ViewHolder... params) {
// Code
return result;
}
@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
if (v.position == myPosition) {
// Code
}
}
}
Upvotes: 0
Reputation: 11
I had a similar problem. A simple file manager: if I have an image I've to resize it with a separate thread. So I show a placeholder until the resized image is ready. After that I've to call notifyDataSetChanged() on the adapter. My solution is to use an handler like this on the adapter
public final Handler fileArrayAdapterHandler = new Handler() {
@Override public void handleMessage(Message msg) { notifyDataSetChanged(); }
};
On the thread I send an empty message to the handler at the end of it.... With different message you could do many other things ...
Upvotes: 0
Reputation: 415
You should call notifyDataSetChanged()
in the UI thread try using runOnUiThread()
.
The second thing is notifyDataSetChanged()
should be called only after add, remove and clear functions.
Upvotes: 6
Reputation: 642
Try calling ListView.invalidateViews() on the list view. Worked for me.
Even if you call notifyDataSetChanged() and/or notifyDataSetInvalidated() from the UI thread on the adapter, these only invalidates the data and not the views. Hence.
Upvotes: 10
Reputation: 10810
You could try refreshing the listview by calling listView1.requestLayout()
or listView1.setAdapter(adapter)
. You could also try adapter.notifyDataSetChanged()
. If scrolling on listview makes the views visible, you could also try scrolling the listview to the bottom and then scroll back to the original position programmatically.
UPDATE:
I think the problem may be coming from your getView() function. Try changing it to this:
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
if (v == null)
{
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row, null);
Log.d("added", "g" + position);
}
Grade g = grades.get(position);
if(g != null)
{
TextView name = (TextView) findViewById(R.id.bottomtext);
TextView id = (TextView) findViewById(R.id.toptext);
if(name != null)
{
name.setText(g.getName());
}
if(id != null)
{
id.setText(g.getId());
}
Log.d("grade", "grade " + g.toString());
}
return v;
}
Upvotes: 2
Reputation: 24423
You want to do something in background then send some change to UI, right? If you are doing this, you should use AsyncTask, a simpler and more effective way for background processing. Whenever your want to change the UI, just call onProgressUpdate() then do what you want there.
Upvotes: 0