【问题标题】:Dynamically increasing the number of elements in a listview动态增加列表视图中的元素数量
【发布时间】:2012-04-14 08:40:36
【问题描述】:

我想增加列表视图滚动到末尾时动态显示的项目数量。 就我而言,我的列表视图最初将显示 10 个项目。然后当我们滚动到最后一个项目时,它必须开始显示另外 10 个项目,依此类推。 我该怎么做??

这是我的自定义数组适配器

    package com.android.listview;

import java.util.ArrayList;

import com.android.listview.R;
import com.android.listview.Product;

import android.widget.ArrayAdapter;

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.android.listview.ListViewActivity;

public class CustomArrayAdapter extends ArrayAdapter<Product> implements
        OnScrollListener {

    private final Context context;
    private final ArrayList<Product> values;

    static class ViewHolder {
        public TextView text;
        public ImageView image;
    }

    public CustomArrayAdapter(Context arg0, int arg1, int arg2,
            ArrayList<Product> arg3) {
        super(arg0, arg1, arg2, arg3);
        this.context = arg0;
        this.values = arg3;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        int product_id = 0;
        View rowView = inflater.inflate(R.layout.feed_items, parent, false);
        try {

            ImageView wic_logo = (ImageView) rowView.findViewById(R.id.logo);
            TextView label = (TextView) rowView.findViewById(R.id.label);

            Product p = values.get(position);
            product_id = p.productId;
            String date = new java.text.SimpleDateFormat("dd/MM/yy")
                    .format(new java.util.Date(p.timeStamp));
            label.setText(p.productName + "\n" + p.reportedPrice + "   MRP: "
                    + p.mrp + "\n" + "Discount: " + p.discount + "%   "
                    + p.area + "  " + p.city + "\n" + "Shared by " + p.userName
                    + " " + "on" + " " + date);

            wic_logo.setImageResource(R.drawable.wic_logo_small);
            Log.d("date", "" + date);

            Log.d("Custom Array Adapter", "at" + position);
        } catch (Exception e) {
            Log.d("Custom Array Adapter", "catch");
        }

        return rowView;
    }

    public void onScroll(AbsListView arg0, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        Log.d("entered onScroll", " " + firstVisibleItem + visibleItemCount
                + totalItemCount);
        if (((firstVisibleItem + visibleItemCount) >= totalItemCount - 1)) {
            Log.d("entered if", " " + firstVisibleItem + visibleItemCount
                    + totalItemCount);
            // if we're at the bottom of the listview, load more data
            addData(totalItemCount, values.get(totalItemCount).productId);
        }
    }

    private void addData(int totalItemCount, int productId) {

        Toast.makeText(getContext(), "last item", Toast.LENGTH_SHORT).show();
    }

    public void onScrollStateChanged(AbsListView arg0, int arg1) {

    }
}

这是我的活动

package com.android.listview;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.android.listview.CustomArrayAdapter;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.Button;
import android.widget.ListView;

public class ListViewActivity extends Activity {

    static Product[] feed_products_list;
    private JSONArray JArray;
    private InputStream is;
    private StringBuilder sb;
    private String result;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Button feed_button = (Button) findViewById(R.id.feedButton_feed);
        feed_button.setBackgroundResource(R.color.grey);
        ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
        try {
            HttpClient httpclient = new DefaultHttpClient();
            HttpPost httppost = new HttpPost("http://10.0.2.2/wic2/mobile/feed");
            httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
            ResponseHandler<String> responseHandler = new BasicResponseHandler();
            HttpResponse response = httpclient.execute(httppost);
            HttpEntity entity = response.getEntity();
            is = entity.getContent();

            try {
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(is, "iso-8859-1"), 8);
                sb = new StringBuilder();
                sb.append(reader.readLine() + "\n");
                String line = "0";
                while ((line = reader.readLine()) != null) {
                    sb.append(line + "\n");
                }
                is.close();
                result = sb.toString();
                Log.d("result", result);
            } catch (Exception e) {
                Log.e("error", "Error in http connection" + e.toString());
            }

            Log.e("response", "response is:" + response.toString());
        } catch (Exception e) {
            Log.e("error", "Error in http connection" + e.toString());
        }

        ListView tv = (ListView) findViewById(R.id.feedListView);
        try {
            Log.d("JArray", "entered try");
            JArray = new JSONArray(result);
            int length = JArray.length();
            feed_products_list = new Product[length+1];
            Log.d("JArray", "try last line");
        } catch (JSONException e) {
            Log.d("JArray", "in catch");
            e.printStackTrace();
        }

        JSONObject jsonObj;

        for (int i = 0; i < JArray.length(); i++) {
            try {
                Log.d("jsonObj", "entered try");
                jsonObj = JArray.getJSONObject(i);
            } catch (Exception e) {
                Log.d("jsonObj", "in catch");
                continue;
            }

            try {
                Log.d("feed_products_list", "entered try");
                feed_products_list[i] = new Product(jsonObj.getInt("id"),
                        jsonObj.getString("image"),
                        jsonObj.getString("product_name"),
                        jsonObj.getString("reported_price_formated"),
                        jsonObj.getString("store_area"),
                        jsonObj.getString("store_city"),
                        jsonObj.getString("mrp"),
                        jsonObj.getString("user_name"),
                        jsonObj.getLong("reported_timestamp"),
                        jsonObj.getInt("discount"));
                Log.d("feed_products_list", feed_products_list[i].productName);
            } catch (JSONException e) {
                Log.d("feed_products_list in catch",
                        feed_products_list[i].productName);
                e.printStackTrace();
            }
        }

        tv.setAdapter(new CustomArrayAdapter(this, R.layout.feed_items,
                R.id.label, feed_products_list));


    }
}

还有一个问题是我必须用 JArray 中的项目数来初始化我的数组 feed_products_list[length]。所以每次滚动到最后一项并重新填充整个列表时,我都无法更改数组大小

【问题讨论】:

    标签: android android-listview dynamic-data


    【解决方案1】:

    首先,您的代码存在一些问题。在您的Activity 中,将变量values 更改为ArrayList&lt;Product&gt;,因为您无法在创建后操作数组的长度。接下来,将 JArray 重命名为 jArray;如果第一个字母是大写字母,则表明您正在处理的是类而不是变量。

    另外,您没有使用 ViewHolder 模式,这极大地提高了性能。查看this link on vogella.com about ListView;更具体地说,请查看第 3.1 和 3.2 章

    CustomArrayAdapter 中,实现OnScrollListener 并添加所需的方法。然后,在onScroll(...) 中,确定是否要添加数据(例如,用户到达列表底部)。最后,加载新项目,使用values.add(product)values.addAll(products) 将它们添加到您的数据集,其中产品是Products 中的List,并在每次调用@987654334 后从CustomArrayAdapter 中调用notifyDataSetChanged @ 或values.addAll(...)

    例如,您可以在代码中更改以下内容:

    在您的活动中:

    • 删除线

      int length = JArray.length();
      feed_products_list = new Product[length+1];
      
    • feed_products_list 中删除“静态”并将其更改为 ArrayList:

      private ArrayList<Product> feed_products_list = new ArrayList<Product>();
      
    • 代替feed_products_list[i] = new Product(jsonObj.getInt("id"), .... yadiya ...,调用feed_products_list.add(new Product(jsonObj.getInt("id"), ... yadiya ...`。

    在您的适配器中:

    • 创建类implement OnScrollListener,并将onScroll()-方法设置为如下所示:

      public void onScroll(AbsListView view, int firstVisibleItem,
                              int visibleItemCount, final int totalItemCount) {
          if(((firstVisibleItem + visibleItemCount) >= totalItemCount)) {
      
              // if we're at the bottom of the listview, load more data
              addData(totalItemCount);
          }
      }
      
    • 创建一个方法addData(long offset):

      private void addData(long offset) {
      
          // download your data, pass the offset so you know where to start
          // and when you convert your json into `Product`s
          Product product = new Product(JSONObject.getInt("id"), ... yadiya ...);
          this.add(product);
          this.notifyDataSetChanged();
      
          // make sure to call notifyDataSetChanged() on your UI-Thread.
      }
      

    【讨论】:

    • 这里的偏移量是我们要添加其他项目的列表中最后一项的位置??
    • 是的,您可以使用它来通知您的服务器已经下载了哪些项目。其他方法是发布当前日期时间,或最后一次获取项目的日期时间 - 这取决于您的需要。
    • 它在哪里指定当我滚动我正在使用的列表视图时调用 onScroll 方法.....就在 onScroll 中的 if 块之前我添加了一个日志并且从未出现在我的日志猫中当我滚动列表时
    • 你的班级有implement onScrollListener(...)吗?
    • 你的意思是我的 CustomArrayAdapter 类??...是的
    【解决方案2】:

    对于动态增加大小,最好使用ArrayList。对于滚动,您可以使用@Mayank idea。

    【讨论】:

      【解决方案3】:

      您应该将scroll listener 附加到您的listview

      ListView lv = (ListView)findViewById(R.id.list_view); 
      lv.setOnScrollListener(new OnScrollListener() { 
          @Override 
          public void onScroll(AbsListView view, int firstVisibleItem,  
              int visibleItemCount, int totalItemCount) { 
              //Check if the last view is visible 
              if (view.getLastVisiblePosition()+1 == 10) { 
                  //load more content 
              } 
          } 
      });
      

      更新

      所以最初在您的feed_products_list 中,您将拥有 10 个项目,当用户向下滚动时,将另外 10 个项目添加到列表中并将 CustomArrayAdapter 重置为 listView。继续这样做,直到您拥有列表中的所有项目。

      【讨论】:

      • 谢谢。但也请帮助我如何动态增加包含列表项的数组大小。最初滚动时它是 10,它必须是我 20 30 40 n 等等
      【解决方案4】:

      使用 ArrayList 代替数组 像这样

      public class CustomArrayAdapter extends ArrayAdapter<Object> {
      
          private final Context context;
          private final ArrayList<Product> values;
      

      在你的getView()

                  Product p = values.get(position);
      

      您可以在适配器内部提供一个方法来将元素添加到 ArrayList 和 notifyDataSetChange() 它看起来像这样

      public void addElement(Product p){
      values.add(p);
      notifiyDataSetChange();
      }
      

      使用OnScrollListener 加载更多数据 示例:

      listView.setOnScrollListener(new OnScrollListener() { 
          @Override 
          public void onScroll(AbsListView view, int firstVisibleItem,  
              int visibleItemCount, int totalItemCount) { 
      
              if (totalItemCount - visibleItemCount <= firstVisibeItem + 5) { 
                  //load more content 
      
                  .....
                  adpater.addElement(p);
      
              } 
      
      
           } 
          });
      

      【讨论】:

        【解决方案5】:

        您不需要这样做。 Android 列表视图可以轻松处理数千个条目——前提是您仔细编写适配器并重用视图。因此,在您的 getView() 方法中,您必须检查是否提供了 converView 并且是否正确,然后使用新值填充它。 (Andriod 非常聪明,它提供回收现在不可见的列表条目) - 这将立即提升性能

        这样做:

        View rowView = convertView;
        if(rowView == null) {
           // do what you are doing now to inflate view
        }
        // do what you are doing now to set up view
        
        return rowView;
        

        如果您不想从 无论您立即存储什么 - 在这种情况下,您必须注册滚动侦听器并通过加载丢失的条目来对其做出反应,然后发出列表数据已更改的信号。而且您不必使用数组作为后备存储 - 列表将完美匹配此目的

        【讨论】:

        • 能否请您提供一个链接,详细说明您在第 1 段中对 converView 的解释
        • @Archie.bpgc 正在从网络资源下载内容;从一开始就加载更多数据可能不利于用户体验,因为初始加载时间会更长,尤其是在连接不良或数据收集的大小很大的情况下。
        • 我在游戏中做的几乎一样。最初我在后台加载所有高分数据,所以新用户在开始时没有所有高分(通常新用户在玩几场游戏之前对它们不感兴趣) - 所以高分在后台加载。在此之后,我只提取自上次已知的 higscore 条目(小)以来的更改。我的数据存在于一个不相关的对象中,列表适配器只是在需要时为它们提取列表。
        • 是的,在用户不需要尽快获取数据的情况下,或者如果数据集一开始并没有那么大,这很好。在其他情况下,重要的是不要让用户等待,特别是如果您可以选择在需要时加载更多内容。此外,如果您拥有庞大的用户群,通过按需加载数据,您可能会节省大量数据。
        【解决方案6】:

        我想你想要Lazy loading这样的东西。

        这被称为延迟加载。我相信你还没有尝试过这样的搜索。我给了你GridView的例子。这是Listview的其他链接Other Link

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-03-21
          • 1970-01-01
          • 2020-09-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多