从服务器 json 响应延迟加载 listview 项

Posted

技术标签:

【中文标题】从服务器 json 响应延迟加载 listview 项【英文标题】:Lazy Load listview Item from server json response 【发布时间】:2015-07-25 14:45:21 【问题描述】:

我正在开发一个 android 应用程序,它通过 json 解析器从服务器加载数据。我想从服务器加载 10 项部分中的数据,当用户向下滚动列表视图时,从服务器加载新的 10 项部分并添加到当前列表视图(例如市场应用程序)。

这里是java代码:

public class AllProductsActivity extends ListActivity 
    //jpcode
    int part=0;
    String refreshNumber="0";
    //convert to shamsi
    Roozh jCal = new Roozh();

    String myjpdiff;
    ImageButton btnNewProduct; 
    View ntCheck;
    private SessionManager session;
    private Button logout;
    //internet check jp
    // flag for Internet connection status
        Boolean isInternetPresent = false;

        // Connection detector class
        ConnectionDetector cd;

        //end internet check jp
        private SQLiteHandler db; //jpcode
    //end jpcode

    // Progress Dialog
    private ProgressDialog pDialog;

    // Creating JSON Parser object
    JSONParser jParser = new JSONParser();

    ArrayList<HashMap<String, String>> productsList;

    // url to get all products list
    private static String url_all_products = "http://www.jpdesign.ir/android_login_api/ac/get_all_products.php";

    // JSON Node names
    private static final String TAG_SUCCESS = "success";
    private static final String TAG_PRODUCTS = "products";
    private static final String TAG_PID = "pid";
    private static final String TAG_NAME = "name";
    //jpcode
    private static final String TAG_AUTH = "auth";
    private static final String TAG_HIT = "hit";
    private static final String TAG_DATE = "created_at";
    private static final String TAG_JPTIME = "jptime";
    private static final String TAG_JPPart = "part";
    private TextView txtName;
    // products JSONArray
    JSONArray products = null;
    Typeface   jpfont;

    public PullToRefreshListView listView;  
    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        overridePendingTransition(R.anim.push_right_in,R.anim.push_right_out);
        setContentView(R.layout.all_products);


           jpfont = Typeface.createFromAsset(getAssets(), "fonts/yekan.ttf");
          TextView fakeDate= (TextView) findViewById(R.id.textView1);
          fakeDate.setTypeface(jpfont);


        // SQLite database handler
        db = new SQLiteHandler(getApplicationContext());
        // session manager
        session = new SessionManager(getApplicationContext());    //jpcode

        //adding slidemenu
        final SlidingMenu menu = new SlidingMenu(this);
        menu.setMode(SlidingMenu.RIGHT);
        menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
        menu.setShadowWidthRes(R.dimen.shadow_width);
        menu.setShadowDrawable(R.drawable.shadowright);
        menu.setBehindOffsetRes(R.dimen.slidingmenu_offset);
        menu.setFadeDegree(0.35f);
        menu.attachToActivity(this, SlidingMenu.SLIDING_CONTENT);
        menu.setMenu(R.layout.slide_layout);
        ImageButton iconfehrest = (ImageButton) findViewById(R.id.sliding);
// get name of user
        // Fetching user details from sqlite
        HashMap<String, String> user = db.getUserDetails();

        String name = user.get("name");
        String email = user.get("email");
        txtName = (TextView) findViewById(R.id.mnt);
        // Displaying the user details on the screen
        Log.d("LOG", name +" and "+email);
        txtName.setText(name);
        //txtEmail.setText(email);


///end get name
        iconfehrest.setOnClickListener(new View.OnClickListener() 

            @Override
            public void onClick(View view) 
                menu.toggle();
            
        );


        //end slide menu



//jpcode
        logout= (Button) findViewById(R.id.Ulogout);
        logout.setOnClickListener(new View.OnClickListener() 

            @Override
            public void onClick(View v) 
                logoutUser();
            
        );
        final View ntCheck = findViewById(R.id.net_check);
        ntCheck.setVisibility(View.GONE);
        // creating connection detector class instance
        cd = new ConnectionDetector(getApplicationContext());

        // get Internet status
        isInternetPresent = cd.isConnectingToInternet();
      ImageButton ntchecker= (ImageButton) findViewById(R.id.nt_check);

      ntchecker.setOnClickListener(new OnClickListener() 

        @Override
        public void onClick(View arg0) 
            // TODO Auto-generated method stub
            Intent i = new Intent(AllProductsActivity.this,AllProductsActivity.class);    
            startActivity(i);
             

    );

    //jp pull to refresh
      StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder() .detectAll().penaltyLog().build(); 
      StrictMode.setThreadPolicy(policy);
            listView = (PullToRefreshListView) getListView();
            listView.setOnRefreshListener(new OnRefreshListener() 
                //@Override
                public void onRefresh() 
                    // Do work to refresh the list here.
                    productsList = new ArrayList<HashMap<String, String>>();

                    // Loading products in Background Thread
                    new LoadAllProducts().execute();
                    pDialog.hide();

                
            );


            // end of jp pull to refresh


        // check for Internet status
        if (isInternetPresent) 
            // Internet Connection is Present
            // make HTTP requests
            // Hashmap for ListView
            productsList = new ArrayList<HashMap<String, String>>();
            ntCheck.setVisibility(View.GONE); //hide internet checker
            // Loading products in Background Thread
            new LoadAllProducts().execute();
         else 
            // Internet connection is not present
            // Ask user to connect to Internet
            Log.d("No Internet Connection", "You don't have internet connection.");
            //Toast.makeText(this, "You don't have internet connection.", Toast.LENGTH_LONG).show();
            ntCheck.setVisibility(View.VISIBLE);
        

        btnNewProduct = (ImageButton) findViewById(R.id.newpost);
        ImageButton searchBtn = (ImageButton) findViewById(R.id.SearchBtn);

        btnNewProduct.setOnClickListener(new View.OnClickListener() 

            @Override
            public void onClick(View view) 
                // Launching create new product activity
                Intent i = new Intent(AllProductsActivity.this, NewProductActivity.class);
                startActivity(i);

            
        );
        //end of jp
        // Hashmap for ListView
        //jpdast productsList = new ArrayList<HashMap<String, String>>();

        // Loading products in Background Thread
        //jpdast new LoadAllProducts().execute();

        // Get listview
        ListView lv = getListView();



        // on seleting single product
        // launching Edit Product Screen
        lv.setOnItemClickListener(new OnItemClickListener() 

            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) 
                // getting values from selected ListItem
                String pid = ((TextView) view.findViewById(R.id.pid)).getText()
                        .toString();

                // Starting new intent
                Intent in = new Intent(getApplicationContext(),
                        ViewPro.class);
                // sending pid to next activity
                in.putExtra(TAG_PID, pid);

                // starting new activity and expecting some response back
                startActivityForResult(in, 100);
            
        );


        //jp scroller

                //add the footer before adding the adapter, else the footer will not load!
//              View footerView = ((LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.footer, null, false);
//              this.getListView().addFooterView(footerView);
                //Here is where the magic happens
                lv.setOnScrollListener(new OnScrollListener() 
                    ListAdapter adapter = new SimpleAdapter(
                            AllProductsActivity.this, productsList,
                            R.layout.list_item, new String[]  TAG_PID,
                                    TAG_NAME,TAG_AUTH,TAG_HIT, TAG_DATE,
                            new int[]  R.id.pid, R.id.name, R.id.auth, R.id.hit, R.id.date 

                            );
                    @Override
                    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) 
                                int lastItem = firstVisibleItem + visibleItemCount;
                                int lastItemPosition=adapter.getCount();
                        if ( adapter.getCount() >= 10 && lastItem  > adapter.getCount() - 6) 
                            boolean isLoading = false;
                            if (!isLoading) 
                                if(isInternetPresent)
                                    if(lastItem > lastItemPosition)
                                        //productsList = new ArrayList<HashMap<String, String>>();

                                        // Loading products in Background Thread
                                        new LoadAllProducts().execute();
                                        //receivedData();
                                        Log.d("LOG", "jpdesign is here");
                                        ((BaseAdapter) adapter).notifyDataSetChanged();
                                        part += 1;
                                        
                                    
                            isLoading = true;
                                
                            
                        
                            public void onScrollStateChanged(AbsListView view, int scrollState) 

                    );

                //jp end scroller


    

    // Response from Edit Product Activity
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) 
        super.onActivityResult(requestCode, resultCode, data);
        // if result code 100
        if (resultCode == 100) 
            // if result code 100 is received 
            // means user edited/deleted product
            // reload this screen again
            Intent intent = getIntent();
            finish();
            startActivity(intent);
        

    

    /**
     * Background Async Task to Load all product by making HTTP Request
     * */
    class LoadAllProducts extends AsyncTask<String, String, String> 

        /**
         * Before starting background thread Show Progress Dialog
         * */
        @Override
        protected void onPreExecute() 
            super.onPreExecute();
            pDialog = new ProgressDialog(AllProductsActivity.this);
            pDialog.setMessage("در حال دریافت اطلاعات ...");
            pDialog.setIndeterminate(false);
            pDialog.setCancelable(false);
            pDialog.show();

        

        /**
         * getting All products from url
         * */
        protected String doInBackground(String... args) 


             Log.d("LOG", part+"");
             List<NameValuePair> params2 = new ArrayList<NameValuePair>();
            params2.add(new BasicNameValuePair(TAG_JPPart, "" + part));

            JSONObject json2 = jParser.makeHttpRequest(url_all_products, "POST", params2);

            Log.d("post checker: ", json2.toString());

            // Building Parameters
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            // getting JSON string from URL
            JSONObject json = jParser.makeHttpRequest(url_all_products, "GET", params);


            // Check your log cat for JSON reponse
            //Log.d("jpdesign All Products: ", json.toString());

            try 
                // Checking for SUCCESS TAG
                int success = json.getInt(TAG_SUCCESS);

                if (success == 1 ) 
                    //adapter.notifyDataSetChanged();

                    refreshNumber="1";
                    // products found
                    // Getting Array of Products
                    products = json2.getJSONArray(TAG_PRODUCTS);
                    String myjpdate=json.getString(TAG_JPTIME);
                     // Log.d("TIME TEST", myjpdate);
                      Log.d("TIME TEST", products+"");
                    // looping through All Products
                //for (int i = 0; i < products.length(); i++) 
                      for (int i =  0; i < products.length(); i++)     
                        JSONObject c = products.getJSONObject(i);

                        // Storing each json item in variable
                        String id = c.getString(TAG_PID);
                        String name = c.getString(TAG_NAME);
                        //jpcode
                        String auth = c.getString(TAG_AUTH);
                        String hit = c.getString(TAG_HIT);
                        String date = c.getString(TAG_DATE);

                       //jptime diff
                        String dateStart = date;
                        String dateStop = myjpdate;

                            Date d1 = null;
                            Date d2 = null;
                            Date jd1 = null;
                            Date jd2 = null;

                            Date fyear = null;


                            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                            SimpleDateFormat jpformat = new SimpleDateFormat("yyyy-MM-dd");






                            try 
                                d1 = format.parse(dateStart);
                                d2 = format.parse(dateStop);
                                jd1 =jpformat.parse(dateStart);
                                jd2 =jpformat.parse(dateStop);

                                DateFormat formatter ; 

                                formatter = new SimpleDateFormat("yyyy-MM-dd");
                                fyear = (Date)formatter.parse(dateStart); 


                                // (3) create a new String using the date format we want
                                String YMD = formatter.format(fyear);

                                int len=YMD.length();
                                String[] myInArray=new String[len];

                                   String FY=String.valueOf(YMD.charAt(0))+String.valueOf(YMD.charAt(1))+String.valueOf(YMD.charAt(2))+String.valueOf(YMD.charAt(3));
                                   String FM=String.valueOf(YMD.charAt(5))+String.valueOf(YMD.charAt(6));
                                   String FD=String.valueOf(YMD.charAt(8))+String.valueOf(YMD.charAt(9));

                                jCal.GregorianToPersian(Integer.parseInt(FY), Integer.parseInt(FM), Integer.parseInt(FD));
                                String myconverttime= jCal.toString();
                                //in milliseconds
                                long diff = d2.getTime() - d1.getTime();
                                long jpdiff = jd2.getTime() - jd1.getTime();


                                long diffSeconds = diff / 1000 % 60;
                                long diffMinutes = diff / (60 * 1000) % 60;
                                long diffHours = diff / (60 * 60 * 1000) % 24;
                                long diffDays = diff / (24 * 60 * 60 * 1000);
 // 1s=1000 ,1m=60000,1h=3.6e+6 1day = 86400000


                            if(jpdiff==0 && diff<=60000)  myjpdiff="هم اکنون";
                            if(jpdiff==0 && diff>60000 && diff<(59*60000))  myjpdiff=diffMinutes+" دقیقه قبل";
                            if(jpdiff==0 && diff>(60*60000) && diff<(24*59*60000))  myjpdiff=diffHours+" ساعت قبل";
                            if(jpdiff==86400000)  myjpdiff="   1 روز قبل   ";
                            if(jpdiff>86400000)  myjpdiff=myconverttime;


                            Log.d("TIME TEST",FY+"   "+diff+"   "+ jpdiff+"    "+diffDays+"day "+diffHours+"hour "+diffMinutes+"");
                         catch (Exception e) 
                            e.printStackTrace();
                        


                        //end jptime diff
                        // creating new HashMap
                        HashMap<String, String> map = new HashMap<String, String>();

                        // adding each child node to HashMap key => value
                        map.put(TAG_PID, id);
                        map.put(TAG_NAME, name);
                        map.put(TAG_AUTH, auth); //jpcode 
                        map.put(TAG_HIT, hit); //jpcode
                        map.put(TAG_DATE, myjpdiff); //jpcode
                        // adding HashList to ArrayList
                        productsList.add(map);


                    



                 else 
                    refreshNumber="0";
                    // no products found
                    // Launch Add New product Activity
                    Intent i = new Intent(getApplicationContext(),
                            NewProductActivity.class);
                    // Closing all previous activities
                    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                    startActivity(i);
                

             catch (JSONException e) 
                e.printStackTrace();
            

            return null;

        

        /**
         * After completing background task Dismiss the progress dialog
         * **/
        protected void onPostExecute(String file_url) 

            // dismiss the dialog after getting all products
            pDialog.dismiss();

            // updating UI from Background Thread
            runOnUiThread(new Runnable() 
                public void run() 
                    /**
                     * Updating parsed JSON data into ListView
                     **/

//                  TextView dt=(TextView) findViewById(R.id.date);
//                  dt.setTypeface(jpfont);
                    ListAdapter adapter = new SimpleAdapter(
                            AllProductsActivity.this, productsList,
                            R.layout.list_item, new String[]  TAG_PID,
                                    TAG_NAME,TAG_AUTH,TAG_HIT, TAG_DATE,
                            new int[]  R.id.pid, R.id.name, R.id.auth, R.id.hit, R.id.date 

                            );


                    // updating listview
                    setListAdapter(adapter);


                    ((PullToRefreshListView) getListView()).onRefreshComplete();

                

            );

        





    


    //jpcode logout

    private void logoutUser() 
        session.setLogin(false);

        db.deleteUsers();

        // Launching the login activity
        Intent intent = new Intent(AllProductsActivity.this, LoginActivity.class);
        startActivity(intent);
        finish();
    
    //end jp logout

这是服务器上的 php 文件:

<?php

header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1

header("Expires: Sat, 26 Jul 2014 05:00:00 GMT"); // Date in the past

?>
<?php

/*
 * Following code will list all the products
 */

// array for JSON response
$response = array();


// include db connect class
require_once __DIR__ . '/db_connect.php';

// connecting to db
$db = new DB_CONNECT();

// get all products from products table

//jpadd codes
 $part = $_POST['part'];
 //$part = $_GET['part'];
  $start = $part * 10;

$result = mysql_query("SELECT *FROM products   ORDER BY`created_at` DESC LIMIT $start, 10") or die(mysql_error());
//$result = mysql_query("SELECT *FROM products ORDER BY`created_at` DESC") or die(mysql_error());

// check for empty result
if (mysql_num_rows($result) > 0) 
    // looping through all results
    // products node
 $response["jptime"] = date("Y-m-d H:i:s");
 //$jptime["my_date"]= date("Y-m-d H:i:s");
    $response["products"] = array();
 $response["part"] = $part;

    while ($row = mysql_fetch_array($result)) 
        // temp user array
        $product = array();
        $product["pid"] = $row["pid"];
        $product["name"] = $row["name"];
        //$product["price"] = $row["price"];
       //$product["description"] = $row["description"];
        $product["created_at"] = $row["created_at"];
        //$product["updated_at"] = $row["updated_at"];
        //jpcode
        $product["auth"] = $row["auth"];
        $product["hit"] = $row["hit"];

     // $my_date = date("Y-m-d H:i:s");


        // push single product into final response array
        array_push($response["products"], $product);
    
    // success
    $response["success"] = 1;

    // echoing JSON response
    echo json_encode($response);
 else 
    // no products found
    $response["success"] = 0;
    $response["message"] = "محصولی یافت نشد";

    // echo no users JSON
    echo json_encode($response);

?>

但是当用户向下滚动列表时没有任何反应

【问题讨论】:

首先从 Scroll 方法中删除适配器代码,然后尝试从 LoadAllProducts onPostExecute() 更新列表适配器。 签出:mobile.dzone.com/news/android-tutorial-dynamicaly 我删除了它,但发生了 nullexception 有什么解决办法吗? 【参考方案1】:
My application code which worked:


public class Product_Listing extends Fragment 

private static final String TAG = SubCategoryActivity.class.getSimpleName();
private static final String TAG_IMAGEPATH = "imagepath";
private static final String TAG_PRODUCTID = "productid";
private static final String TAG_PRODUCTNAME = "productname";
private static final String TAG_SUPPLIERID = "supplierid";
private static final String TAG_SUPPLIERNAME = "suppliername";
private static final String TAG_CATEGORY_ID = "catid";
private static final String TAG_PRODUCT_COUNT = "productcount";

private ProgressDialog pDialog;
private List<Products> catList = new ArrayList<Products>();
private ListView listView;
private ProductsAdapter adapter;
int id_count = 0;

private int current_page = 0;
int mPreLast;

public Product_Listing() 


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) 
    return inflater.inflate(R.layout.fragment_product__listing, container, false);


@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) 
    super.onActivityCreated(savedInstanceState);
    listView = (ListView) getView().findViewById(R.id.list1);
    adapter = new ProductsAdapter(getActivity(), catList);
    listView.setAdapter(adapter);
    int currentPosition = listView.getFirstVisiblePosition();
    listView.setSelectionFromTop(currentPosition + 1, 0);

    listView.setOnScrollListener(new AbsListView.OnScrollListener()
    
        @Override
        public void onScrollStateChanged(AbsListView absListView, int i)
        

        

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
        
            int lastItem = firstVisibleItem + visibleItemCount;
            if(lastItem == totalItemCount)
                if (mPreLast != lastItem)
                
                    mPreLast = lastItem;
                    new LoadProductDesc().execute();
                
            
        
    );

    new LoadProductDesc().execute();




private void hidePDialog() 
    if (pDialog != null && pDialog.isShowing()) 
        pDialog.dismiss();
        pDialog = null;
    


class LoadProductDesc extends AsyncTask<String, String, String> 

    /**
     * Before starting background thread Show Progress Dialog
     */
    @Override
    protected void onPreExecute() 
        super.onPreExecute();
        pDialog = new ProgressDialog(getActivity());
        pDialog.setMessage("Getting Data ...");
        pDialog.setIndeterminate(false);
        pDialog.setCancelable(true);
        pDialog.show();
    


    protected String doInBackground(String... args) 

        HttpClient httpclient = new DefaultHttpClient();
        HttpResponse response;
        String responseString = null;
        try 
            // make a HTTP request

            response = httpclient.execute(new HttpGet());
            StatusLine statusLine = response.getStatusLine();
            if (statusLine.getStatusCode() == HttpStatus.SC_OK) 
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                response.getEntity().writeTo(out);
                out.close();
                responseString = out.toString();
             else 
                // close connection
                response.getEntity().getContent().close();
                throw new IOException(statusLine.getReasonPhrase());
            
         catch (Exception e) 
            Log.d("Test", "Couldn't make a successful request!");
        
        return responseString;
    


    protected void onPostExecute(final String response) 

        super.onPostExecute(response);
        // Creating volley request obj
        String s1 = getActivity().getIntent().getStringExtra("index");
        current_page += 1;
        final String url = "Your URL Link" + s1 + "," + current_page;

                JsonArrayRequest movieReq = new JsonArrayRequest(url,
                        new Response.Listener<JSONArray>() 
                            @Override
                            public void onResponse(JSONArray response) 
                                Log.d(TAG, response.toString());

                                try
                                
                                    if (isNetworkStatusAvialable (getActivity())) 

                                            // Parsing json
                                            for (int i = 0; i < response.length() && response.length() != 0; i++)
                                            
                                                JSONObject obj = response.getJSONObject(i);
                                                Products products = new Products();
                                                id_count = id_count + 1;
                                                products.setProductName(obj.getString(TAG_PRODUCTNAME));
                                                products.setThumbnailUrl(obj.getString(TAG_IMAGEPATH));
                                                products.setProductID(obj.getInt(TAG_PRODUCTID));
                                                products.setSupplierName(obj.getString(TAG_SUPPLIERNAME));
                                                products.setSupplierID(obj.getInt(TAG_SUPPLIERID));
                                                products.setCategoryID(obj.getInt(TAG_CATEGORY_ID));
                                                String count = obj.getString(TAG_PRODUCT_COUNT);

                                                catList.add(products);

                                                TextView textView = (TextView) getView().findViewById(R.id.ListofProducts);
                                                textView.setText(String.valueOf("Total 1 to " + id_count + " Products listed of " + count));
                                            

                                    
                                    else
                                    
                                        Toast.makeText(getActivity(),"Check Internet Connectivity!!",Toast.LENGTH_LONG).show();
                                        return;
                                    

                                 catch (JSONException e) 
                                    e.printStackTrace();
                                 catch (NullPointerException ne) 
                                    Toast.makeText(getActivity(), "Check Internet Connectivity!!", Toast.LENGTH_LONG).show();
                                
                                hidePDialog();

                                // notifying list adapter about data changes
                                // so that it renders the list view with updated data
                                adapter.notifyDataSetChanged();

                            
                        , new Response.ErrorListener() 
                    @Override
                    public void onErrorResponse(VolleyError error) 
                        VolleyLog.d(TAG, "Error: " + error.getMessage());
                        hidePDialog();
                    
                );
                // Adding request to request queue
                AppController.getInstance().addToRequestQueue(movieReq);
            





public static boolean isNetworkStatusAvialable (Context context) 
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    if (connectivityManager != null)
    
        NetworkInfo netInfos = connectivityManager.getActiveNetworkInfo();
        if(netInfos != null)
            if(netInfos.isConnected())
                return true;
    
    return false;



  

【讨论】:

以上是关于从服务器 json 响应延迟加载 listview 项的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Android 的 ListView 中延迟加载图像

在 Spring Boot jpa 中将延迟加载的对象转换为 JSON

从 URL 加载带有 JSON 数据的 ListView

Android中的Listview延迟加载平滑[重复]

Flutter:延迟加载来自 Firestore 的数据

每 2 秒刷新一次从 JSON 响应中填充的 listView