Listview in android did not refresh the view until dragged
Asked Answered
S

9

8

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()

Silique answered 18/7, 2011 at 11:31 Comment(2)
Did you finally solve this? I'm having the same problem and solutions like notifyDataSetChanged() or invalidate() don't work. I even tried ArrayAdapter<> directly (without custom getView()), nothing worked.Lorinalorinda
I'm getting similar trouble, my list simply disappears on refresh and the new one is displayed once I start to scroll. Did you or Tupteq find any solution?Piper
E
10

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.

Epileptoid answered 4/11, 2011 at 22:8 Comment(0)
Y
6

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.

Yellowbird answered 18/7, 2011 at 12:2 Comment(2)
hmm in that case, then what should do to refresh the view e.g after user drags?Silique
suppose i have update update(modify) content then will it update my view ?Arguable
A
2

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;
}
Armagh answered 19/7, 2011 at 5:30 Comment(3)
hmm both the method didn't work, i tried calling both but it didn't work it didn't even scroll..Silique
Arash, thanks for helping me out here, but it didn't work too. The problem is that it stops after adding the third one which my LogCat would show "added, "g3" then stop then if I drag the listview down and up again, it'd keep looping where my second LogCat ("grade") would keep on running until forever. I'd add the snippet for adding the grade items into an arraylist at my postSilique
Calling requestLayout on the ListView after calling notifyDataSetChanged on the ArrayAdapter fixed a similar problem I was having.Benner
R
2

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.

Rebecarebecca answered 24/7, 2016 at 5:55 Comment(0)
W
0

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.

Wrapped answered 18/7, 2011 at 16:44 Comment(3)
erm, so you mean i should change what i have above to the asynctask? do you have any link for tutorial? :SSilique
A simple example of AsyncTask can be found here: developer.android.com/reference/android/os/AsyncTask.html or here: vogella.de/articles/AndroidPerformance/article.htmlWrapped
i just implemented, but same thing, the ui does not refresh itself until the list is dragged down out of view and dragged back up, something like redrawing :(Silique
M
0

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 ...

Mice answered 18/6, 2013 at 23:57 Comment(0)
S
0

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
            }
        }
    }
Stacte answered 10/12, 2013 at 15:46 Comment(0)
C
0

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.

Chiaroscuro answered 22/4, 2016 at 15:38 Comment(0)
T
0

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);
    }
};
Teatime answered 9/1, 2019 at 4:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.