android中的Listview直到拖动才刷新视图

时间:2011-07-18 11:31:29

标签: android layout android-listview refresh

我正在使用以下代码:

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 :(可能是什么问题? 有人请帮帮我......

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

中的asyncatask调用的

9 个答案:

答案 0 :(得分:9)

尝试在列表视图中调用ListView.invalidateViews()。为我工作。

即使从适配器上的UI线程调用notifyDataSetChanged()和/或notifyDataSetInvalidated(),这些也只会使数据无效,而不会使视图无效。因此。

答案 1 :(得分:5)

您应该使用notifyDataSetChanged()在UI线程中调用runOnUiThread()。 第二件事是notifyDataSetChanged()只应在添加,删除和清除函数后调用。

答案 2 :(得分:1)

好的,我解决了这个问题。

ListAdapter没有任何问题。问题来自ListView的父视图。

每次更改布局时,必须在onMeasure上调用

ListView。即onMeasureonLayout在其父母之一上被召唤。

我有一个自定义视图作为ListView的父级的父级。其中我精确地拒绝测量孩子以使布局过程更快。

答案 3 :(得分:0)

您想在后台执行某些操作然后向UI发送一些更改,对吗?如果您这样做,则应使用AsyncTask,这是一种更简单,更有效的后台处理方式。每当你想要改变UI时,只需调用onProgressUpdate()然后在那里做你想做的事。

答案 4 :(得分:0)

您可以致电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;
}

答案 5 :(得分:0)

我有类似的问题。一个简单的文件管理器:如果我有一个图像,我将用一个单独的线程来调整它。所以我显示一个占位符,直到调整大小的图像准备好。之后,我将在适配器上调用notifyDataSetChanged()。我的解决方案是在适配器上使用这样的处理程序

  

public final Handler fileArrayAdapterHandler = new Handler(){

     
    @Override 
 public void handleMessage(Message msg) {

        notifyDataSetChanged();

    }   
         

};

  

在线程上,我向处理程序发送一条空消息.... 有了不同的信息,你可以做很多其他事情......

答案 6 :(得分:0)

我遇到了同样的问题,我缺少的是 位置 并不总是被发送,例如正在跳过(位置0和2)这些在我滚动之前没有更新。

这为我修复了(看到我使用了asynctask)从这里开始:

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

答案 7 :(得分:0)

正如其他一些人已经说过的那样,这个问题是由于你从AsyncTask执行代码而没有在UI线程上调用代码。由于我还没有评论,这是另一个答案。

我遇到了同样的问题:我更新了数据(在静态上下文中保存),但是在调用适配器上的notifyDataSetChanged()之后listview没有更新。拖动/滚动后,UI会更新,数据会自动刷新。

问题是只有创建视图层次结构的原始线程才能触及其视图。我假设您正在从回调中运行Runnable因此,您需要在UI线程上调用它以使listview更新自身,在片段中您可以执行以下操作:

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

如果你在UI线程之外运行adapter.notifyDataSetChanged(),你通常也会遇到CalledFromWrongThreadException,一些try catch块可能会掩盖它。

答案 8 :(得分:0)

与@ ac19的答案一样,通过添加处理程序消息来解决问题。

我使用自定义适配器和典型的ListView,如果收到蓝牙回调,将更新数据。当我在回调函数中调用“ Adapter.notifyDataSetChanged()”时,List直到触摸屏幕后才更新。

我无视一条消息,并在回调函数中添加以下代码(已替换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);
    }
};