Listview в андроиде не обновлял вид, пока не перетащил - PullRequest
6 голосов
/ 18 июля 2011

Я использую код, приведенный ниже:

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

, но странно то, что после заполнения списка единственный доступный элемент - это первое, что в списке, строки непосредственно ниже будут пустыми, если яперетащите вниз из поля зрения, затем вернитесь назад, тогда это будет видно.Я почти уверен, что приведенный выше код верен, когда я следовал руководству.Но я не могу ожидать, что пользователь будет перетаскивать его назад и снова, чтобы увидеть все, что с этим связано ...

И, к тому же, я только что заметил, что мои данные заполнены неправильно, так как это предупреждение появится 07-19 23:54:49.947: WARN/InputManagerService(58): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@44eb97c0 Я совершенно уверен, что мои коды верны, и вот где это останавливается:

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;
}

и из трассировки LogCat я бы только добрался до позиции 3 :( в чем может быть проблема? Кто-то, пожалуйста, помогите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());

}

это вызывается из асинхронной задачи в функции doInBackground ()

Ответы [ 9 ]

9 голосов
/ 05 ноября 2011

Попробуйте вызвать ListView.invalidateViews () в представлении списка. Работал на меня.

Даже если вы вызываете notifyDataSetChanged () и / или notifyDataSetInvalidated () из потока пользовательского интерфейса на адаптере, они делают недействительными только данные, а не представления. Следовательно.

5 голосов
/ 18 июля 2011

Вы должны вызвать notifyDataSetChanged() в потоке пользовательского интерфейса, попробуйте использовать runOnUiThread().Во-вторых, notifyDataSetChanged() следует вызывать только после добавления, удаления и очистки функций.

1 голос
/ 24 июля 2016

Хорошо, я решил проблему.

Нет ничего плохого в ListAdapter. Проблема в родительских представлениях ListView.

onMeasure должен вызываться на ListView каждый раз, когда изменяется макет. то есть onMeasure или onLayout вызывается одним из его родителей.

У меня был пользовательский вид в качестве родителя родителя ListView. В котором я точно отказался измерить детей, чтобы ускорить процесс верстки.

0 голосов
/ 09 января 2019

То же, что и ответ @ ac19, проблема была добавлена ​​путем добавления сообщения-обработчика.

Я использую пользовательский адаптер и типичный ListView, обновлю данные, если получу обратный вызов Bluetooth. Когда я вызывал «Adapter.notifyDataSetChanged ()» в функции обратного вызова, список не обновлялся, пока я не коснулся экрана.

Я защищаю сообщение и добавляю следующий код в функцию обратного вызова (заменен Adapter.notifyDataSetChanged ())

Message m = new Message();
m.what = MessageYouDefined;
mHandler.sendMessage(m);

И добавлен обработчик в onCreate

mHandler=new Handler(){
    public void handleMessage(Message msg)
    {
        switch (msg.what){
             case UpdateChargerList:
             chargerAdapter.notifyDataSetChanged();
             break;
         }
         super.handleMessage(msg);
    }
};
0 голосов
/ 22 апреля 2016

Как уже говорили некоторые другие, эта проблема вызвана тем, что код не вызывается в потоке пользовательского интерфейса, поскольку вы выполняете его из AsyncTask.Поскольку я пока не могу комментировать, вот другой ответ.

Я столкнулся с той же проблемой: я обновил данные (которые содержались в статическом контексте), но список не обновился после вызова notifyDataSetChanged () дляадаптер.После перетаскивания / прокрутки пользовательский интерфейс обновляется, и данные автоматически обновляются.

Проблема заключается в том, что только исходный поток, создавший иерархию представлений, может касаться его представлений.Я предполагаю, что вы запускаете Runnable из обратного вызова. Таким образом, вам нужно вызвать его в потоке пользовательского интерфейса, чтобы список обновлялся сам, а во фрагменте вы должны сделать что-то вроде:

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

Есливы запускаете adaptor.notifyDataSetChanged () вне потока пользовательского интерфейса, обычно вы также наталкиваетесь на CalledFromWrongThreadException, в некотором блоке try catch это могло быть скрыто.

0 голосов
/ 10 декабря 2013

У меня была та же проблема, но мне не хватало того, что позиция отправлялась не всегда, например, был пропущен (позиции 0 и 2), и это не былообновление, пока я не прокрутил.

Это исправило это для меня (смотрите, что я использовал асинктас) пошло от этого:

@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;
}

К этому (Создан внутренний класс, передайте позицию в конструкторе):

@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
            }
        }
    }
0 голосов
/ 19 июня 2013

У меня была похожая проблема. Простой файловый менеджер: если у меня есть изображение, я должен изменить его размер в отдельном потоке. Поэтому я показываю заполнитель, пока не будет готово измененное изображение. После этого я должен вызвать notifyDataSetChanged () на адаптере. Мое решение - использовать такой обработчик на адаптере

публичный конечный обработчик fileArrayAdapterHandler = new Handler () {

    @Override 
 public void handleMessage(Message msg) {

        notifyDataSetChanged();

    }   

};

В цепочке я отправляю пустое сообщение обработчику в конце этого .... С другим сообщением вы могли бы сделать много других вещей ...

0 голосов
/ 19 июля 2011

Вы можете попробовать обновить просмотр списка, позвонив по номеру listView1.requestLayout() или listView1.setAdapter(adapter).Вы также можете попробовать adapter.notifyDataSetChanged().Если при прокрутке в представлении списка отображаются виды, вы также можете попробовать прокрутить представление списка до конца, а затем программно прокрутить обратно в исходное положение.

ОБНОВЛЕНИЕ:

Я думаю, что проблема может возникнутьиз вашей функции getView ().Попробуйте изменить это на это:

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;
}
0 голосов
/ 18 июля 2011

Вы хотите сделать что-то в фоновом режиме, а затем отправить некоторые изменения в пользовательский интерфейс, верно? Если вы делаете это, вы должны использовать AsyncTask , более простой и эффективный способ фоновой обработки. Всякий раз, когда вы хотите изменить пользовательский интерфейс, просто вызовите onProgressUpdate (), а затем сделайте то, что вы хотите.

...