【问题标题】:how to maintain scroll position of listview when it updates更新时如何保持列表视图的滚动位置
【发布时间】:2012-04-17 17:29:51
【问题描述】:

我已经阅读了很多示例,但是如果我希望在 ListViewJSON 更新后保持滚动位置,那么我可以不使用 AsyncTask 实例来做到这一点吗?

我的列表代码是

 String wrd;
    //ArrayList<HashMap<String,String>> mylist;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Intent i2=getIntent();
         wrd=i2.getStringExtra("entrd");
        Log.v("keyis",wrd);



        final Handler handler = new Handler();
        Runnable runable = new Runnable() {

            @Override
            public void run() {

                //call the function
                LoadData();
                //also call the same runnable
                handler.postDelayed(this, 40000);
            }
        };
        handler.postDelayed(runable, 10);

    }public void LoadData(){


         JSONObject j2=JSONfunctions.getJSONfromURL("/webservice_search.php?keyword="+wrd+"&format=json");
         ArrayList<HashMap<String,String>> mylist = new  ArrayList<HashMap<String,String>>();

         try{JSONArray jray=j2.getJSONArray("listings");
            for(int i=0;i<jray.length();i++){
                Log.v("state","json data being read");
                JSONObject j3= jray.getJSONObject(i);
                String first=j3.getString("listing");
                Log.v("sublist", first);
                JSONObject j4=j3.getJSONObject("listing");
                String sec=j4.getString("links");

                int maxLength = (sec.length() < 30)?sec.length():27;
                sec.substring(0, maxLength);
                String cutsec=sec.substring(0,maxLength);
                Log.v("links are",cutsec);
                String img=j4.getString("image_name");
                Log.v("image name is ",img);
                //Uri dimg=Uri.parse("http://zeesms.info/android_app_images/Koala.jpg");
                HashMap<String,String> map=new HashMap<String,String>();

                map.put("Id",String.valueOf(i));
                map.put(Li_nk,cutsec);
                map.put(Image_name,j4.getString("image_name"));

                map.put(KEY_THUMB_URL,"http://zeesms.info/android_app_images/"+img);
                mylist.add(map);

            }

            }
            catch(JSONException e){

                Log.e("loG_tag","Error parsing"+e.toString());
            }
         LazyAdapter adapter = new LazyAdapter(this,mylist);
         adapter.notifyDataSetChanged();

            ListView list=(ListView)findViewById(R.id.lv1);
             list.setEmptyView(findViewById(R.id.empty));
             list.setAdapter(adapter);

                list.setItemsCanFocus(false);

而我的适配器是

public class LazyAdapter extends BaseAdapter {
private Activity activity;
private ArrayList<HashMap<String, String>> data;
private static LayoutInflater inflater=null;
public ImageLoader imageLoader; 


public LazyAdapter(Activity a, ArrayList<HashMap<String, String>> d) {
    activity = a;
    data=d;
    inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    imageLoader=new ImageLoader(activity.getApplicationContext());
}

@Override
public int getCount() {
    // TODO Auto-generated method stub
    return data.size();
}

@Override
public Object getItem(int position) {
    // TODO Auto-generated method stub
    return position;
}

@Override
public long getItemId(int position) {
    // TODO Auto-generated method stub
    return position;
}



@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View vi=convertView;
    if(convertView==null)

        vi = inflater.inflate(R.layout.custom_row_view1, null);

    TextView title = (TextView)vi.findViewById(R.id.linkname); // merchnts name
    TextView artist = (TextView)vi.findViewById(R.id.imagename); // address
    //TextView duration = (TextView)vi.findViewById(R.id); // distance
   ImageView thumb_image=(ImageView)vi.findViewById(R.id.mClogo); // logo

    HashMap<String, String> jsn = new HashMap<String, String>();
    jsn = data.get(position);

    // Setting all values in listview
   title.setText(jsn.get(Second.Li_nk));
   artist.setText(jsn.get(Second.Image_name));
    //duration.setText(song.get(CustomizedListView.KEY_DURATION));
    imageLoader.DisplayImage(jsn.get(Second.KEY_THUMB_URL), thumb_image);
    return vi;
}

最后用于 json 解析的类是

    public class JSONfunctions {


    public static JSONObject getJSONfromURL(String url){
        InputStream is = null;
        String result = "";
        JSONObject jArray = null;
        String  str1="http://zeesms.info"+url;

  // ArrayList<NameValuePair> namevaluepairs = new ArrayList<NameValuePair>();
        Log.v("url result",url);
        //namevaluepairs.add(new BasicNameValuePair("location",str1));
        //http post
        try{   
            HttpClient httpclient= new DefaultHttpClient();
            HttpGet request = new HttpGet();

            request.setURI(new URI(str1));
            HttpResponse response = httpclient.execute(request);

            is  = response.getEntity().getContent();
            if(is==null){
                 Log.v("url result","is  null");
            }
            else
            {
                Log.v("url result","is  not null");
            }

        /*    BufferedReader buf = new BufferedReader(new InputStreamReader(is,"UTF-8"));

            StringBuilder sb = new StringBuilder();
            String s;
            while(true )
            {
                s = buf.readLine();
                if(s==null || s.length()==0)
                    break;
                sb.append(s);

            }
            buf.close();
            is.close();

            sb.toString();  */



        //  httppost.setEntity(new UrlEncodedFormEntity(namevaluepairs));
            //HttpResponse response=httpclient.execute(httppost);
            //HttpEntity entity=response.getEntity();
            //is=entity.getContent();


            /*
                HttpClient httpclient = new DefaultHttpClient();
                HttpPost httppost = new HttpPost(url);
                HttpResponse response = httpclient.execute(httppost);
                HttpEntity entity = response.getEntity();
                is = entity.getContent();
*/
        }catch(Exception e){
                Log.v("log_tag", "Error in http connection "+e.toString());

                AlertDialog.Builder alert=new AlertDialog.Builder(null);
                alert.setMessage("Invalid Keyword").setPositiveButton("Ok", new OnClickListener(){

                    @Override
                    public void onClick(DialogInterface arg0, int arg1) {
                        // TODO Auto-generated method stub

                    }

                });
        }

      //convert response to string
        try{
            Log.v("url result","getting result starts");

                BufferedReader reader = new BufferedReader(new InputStreamReader(is,"iso-8859-1"),8);

                StringBuilder sb = new StringBuilder();

                String line = null;
                Log.v("url result","getting result");
                while ((line = reader.readLine()) != null) {
                    Log.v("url result","getting result");
                        sb.append(line + "\n");
                }

                is.close();

                result=sb.toString();
                Log.v("url result",result);

        }catch(Exception e){
                Log.e("log_tag", "Error converting result "+e.toString());
        }

        try{

            jArray = new JSONObject(result);            
        }catch(JSONException e){
                Log.e("log_tag", "Error parsing data "+e.toString());
        }

        return jArray;
    }



}

如果数据是从网页更新的,那么在顶部显示更新项目的最简单方法是什么??

【问题讨论】:

    标签: android json listview scroll autoscroll


    【解决方案1】:

    只调用 notifydatasetchanged() 更容易保持滚动位置。问题是每次数据更新时您都在创建一个新适配器...您应该执行以下操作:

    if(listView.getAdapter()==null)
       listView.setAdapter(myAdapter);
    else{
       myAdapter.updateData(myNewData);  //update adapter's data
       myAdapter.notifyDataSetChanged(); //notifies any View reflecting data to refresh
    }
    

    这样,您的列表视图将保持滚动位置。

    如果您想滚动到新位置,请使用:

    list.smoothScrollToPosition(int position);
    

    【讨论】:

    • 在 notifydatasetchanged 加载新页面并从第一页显示视图后,请帮助每个新页面加载并移至顶部
    • 您没有正确使用它。如果它移到顶部,则您将所有项目重新插入列表中
    • @SebastianBreit 我是新手,但你能解释一下如何使用 myAdapter.updateData(myNewdata); ?应该在 myNewdata 中传递什么?请详细说明?
    • @Vikrant,通常是任何类型的对象列表。 (数组/数组列表/向量)。在您的适配器内部,您将拥有对该列表的引用,以便在您的视图中显示它。我强烈建议你看看任何 android 适配器教程
    • 太棒了!我的列表不再移动了。它停留在删除和插入的位置。
    【解决方案2】:

    如果由于某种原因你不想调用 notifyDataSetChanged(),你可以使用 setSelectionFromTop() 来保持位置

    更新适配器之前:

    lastViewedPosition = listView.getFirstVisiblePosition();
    
    //get offset of first visible view
    View v = listView.getChildAt(0);
    topOffset = (v == null) ? 0 : v.getTop();
    

    更新适配器后:

    listView.setSelectionFromTop(lastViewedPosition, topOffset);
    

    【讨论】:

    • 最佳答案,拯救了我的一天
    【解决方案3】:
    list.smoothScrollToPosition(int position);     //my favorite :)
    

    它还可以帮助您将 nice'n'smooth 滚动到特定项目

    【讨论】:

    • 我应该在 datasetnotify 更改之后添加这个吗?还是在我的 oncreate 中??
    • 最后 - 当你的列表有项目可以滚动时
    • 只是一个快速查询,如果我想在这里颠倒我的列表顺序,即如果我希望最后一个项目首先出现等等,我该怎么做?
    • 要么反转您的 ArrayList 并在您的适配器上调用 notifyDataSetChanged(),或者将 setStackFromBottom(true) 设置为您的设置适配器之前的列表视图。
    • 如何反转数组列表?我试过 setStackFromBottom(true),但它只是向下滚动到最后一项
    【解决方案4】:
    listview.setSelection( i );
    

    这将帮助您将特定行设置在顶部

    【讨论】:

    • @lenooh:我也是!
    【解决方案5】:

    整体情况:

    在您的 API 响应回调中,调用以下函数(示例):

    MyAdapter mAdapter;
    ArrayList<Users> mUsers;
    
    private void updateListView(ArrayList<Users> users) {
        mUsers.addAll(users);
        if(mAdapter == null) {
            mAdapter = new MyAdapter(getContext(), mUsers);
            mListView.setAdapter(mAdapter);
        }
        mAdapter.notifyDataSetChanged(); // Add this one
    }
    

    【讨论】:

      【解决方案6】:

      如果您使用的是 ArrayAdapter(或其子类),则问题可能是由于适配器在您在添加新项目之前对其进行清理时更新了列表:

      adapter.clear();
      adapter.addAll(...);
      

      您可以通过包装修改适配器的代码来修复它,如下所示:

      adapter.setNotifyOnChange(false); // Disable calling notifyDatasetChanged() on modification
      adapter.clear();
      adapter.addAll(...); // Notify the adapter about that data has changed. Note: it will re-enable notifyOnChange
      adapter.notifyDataSetChanged();
      

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-17
      • 1970-01-01
      • 2016-12-03
      • 2022-08-15
      • 2018-04-08
      • 1970-01-01
      • 1970-01-01
      • 2010-09-24
      相关资源
      最近更新 更多