无尽的 recyclerview 以及在 recyclerview 中从服务器加载滚动使用 cardview 加载图像和文本

endless recyclerview along with load onscroll from server in recyclerview using cardview to load images and text

我已经使用 cardview 实现了 recyclerview,以使用本教程从我的服务器获取图像和文本:http://www.simplifiedcoding.net/android-custom-listview-with-images-using-recyclerview-and-volley/

我已成功获取数据并根据我的要求修改了代码,现在我想实现类似于Instagram应用程序的滑动刷新和无限滚动。我已经尝试了很多教程和 SO 问题,但是我无法实现其中任何一个。

我部分成功地实现了滑动刷新,但应用程序退出并显示 inconsistency error 。请指导

MainActivity.java

public class MainActivity extends AppCompatActivity  implements SwipeRefreshLayout.OnRefreshListener{

    SwipeRefreshLayout swipeLayout;

    LinearLayoutManager mLayoutManager;

    // initially offset will be 0, later will be updated while parsing the json
    private int offSet = 0;

    private boolean loading = true;
    int pastVisiblesItems, visibleItemCount, totalItemCount;

//Creating a List of superheroes
private List<SuperHeroes> listSuperHeroes;

//Creating Views
private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
private RecyclerView.Adapter adapter;
public String Img;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //Initializing Views
    recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
    recyclerView.setHasFixedSize(true);
    layoutManager = new LinearLayoutManager(this);
    recyclerView.setLayoutManager(layoutManager);

    //Initializing our superheroes list
    listSuperHeroes = new ArrayList<>();


        mLayoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(mLayoutManager);

        swipeLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_container);
        swipeLayout.setOnRefreshListener(this);
        swipeLayout.setColorSchemeResources(android.R.color.holo_blue_bright,
                android.R.color.holo_green_light,
                android.R.color.holo_orange_light,
                android.R.color.holo_red_light);

        swipeLayout.post(new Runnable() {
                             @Override
                             public void run() {
                                 swipeLayout.setRefreshing(true);

                                 getData();
                             }
                         }
        );

        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                if (dy > 0) //check for scroll down
                {
                    visibleItemCount = mLayoutManager.getChildCount();
                    totalItemCount = mLayoutManager.getItemCount();
                    pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();

                    if (loading) {
                        if ((visibleItemCount + pastVisiblesItems) >= totalItemCount) {
                            loading = false;
                            Log.v("...", "Last Item Wow !");


                            //Do pagination.. i.e. fetch new data


                            loading = true;
                        }
                    }
                }
            }
        });
    }



    //This method will get data from the web api
    private void getData(){
        //Showing a progress dialog
        // final ProgressDialog loading = ProgressDialog.show(this,"Loading Data", "Please wait...",false,false);

// appending offset to url
        String url = Config.DATA_URL;
        String url1 = url + offSet;
        //Creating a json array request
        JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(url1,
                new Response.Listener<JSONArray>() {
                    @Override
                    public void onResponse(JSONArray response) {
                        //Dismissing progress dialog
                        // loading.dismiss();

                        //calling method to parse json array
                        parseData(response);
                        adapter.notifyDataSetChanged();
                        // stopping swipe refresh
                        swipeLayout.setRefreshing(false);
                    }

                },

                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {

                    }
                });



        //Creating request queue
        RequestQueue requestQueue = Volley.newRequestQueue(this);

        //Adding request to the queue
        requestQueue.add(jsonArrayRequest);


    }

    //This method will parse json data
    private void parseData(JSONArray array){
        for(int i = 0; i<array.length(); i++) {
            SuperHeroes superHero = new SuperHeroes();
            CardAdapter car = new CardAdapter();
            JSONObject json = null;
            try {
                json = array.getJSONObject(i);
                superHero.setImageUrl(json.getString(Config.TAG_IMAGE_URL));
                Img =json.getString(Config.TAG_IMAGE_URL);
                superHero.setName(json.getString(Config.TAG_NAME));
                superHero.setRank(json.getInt(Config.TAG_RANK));
                // superHero.setRealName(json.getString(Config.TAG_REAL_NAME));
                //superHero.setCreatedBy(json.getString(Config.TAG_CREATED_BY));
                //superHero.setFirstAppearance(json.getString(Config.TAG_FIRST_APPEARANCE));
                int rank = json.getInt("pid");

                // updating offset value to highest value
                if (rank >= offSet)
                    offSet = rank;

                //  ArrayList<String> powers = new ArrayList<String>();

                //JSONArray jsonArray = json.getJSONArray(Config.TAG_POWERS);

               /* for(int j = 0; j<jsonArray.length(); j++){
                    powers.add(((String) jsonArray.get(j))+"\n");
                }*/
                //superHero.setPowers(powers);
                Log.d("test",Img);
                car.setImageUrl(Img);


            } catch (JSONException e) {
                e.printStackTrace();
            }
            listSuperHeroes.add(superHero);

        }

        //Finally initializing our adapter
        adapter = new CardAdapter(listSuperHeroes, this);

        //Adding adapter to recyclerview
        recyclerView.setAdapter(adapter);

    }


    @Override
    public void onRefresh() {
        listSuperHeroes.clear();
        getData();
    }

}

CardAdapter.java

/**
 * Created by Belal on 11/9/2015.
 */
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder> {
    private String imageUrl;
    private ImageLoader imageLoader;
    private Context context;
    String Load;
    static int count = 0;
    public static final String uu = "uu";
    String number;
 String  user1;
    public static final String UserNum = "UserNum";
    SharedPreferences sharedPref;


    // JSON parser class
    JSONParser jsonParser = new JSONParser();

    //testing from a real server:
    private static final String LIKE_URL = "myurl";

    //ids
    private static final String TAG_SUCCESS = "success";
    private static final String TAG_MESSAGE = "message";

    //List of superHeroes
    List<SuperHeroes> superHeroes;



    public CardAdapter() {
    }

    public CardAdapter(List<SuperHeroes> superHeroes, Context context) {
        super();
        //Getting all the superheroes
        this.superHeroes = superHeroes;
        this.context = context;
        sharedPref  =context.getSharedPreferences(UserNum, 0);
        number =  sharedPref.getString(uu, "");


    }

    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.superheroes_list, parent, false);
        ViewHolder viewHolder = new ViewHolder(v);
        return viewHolder;


    }


    @Override
    public void onBindViewHolder(ViewHolder holder, final int position) {

        SuperHeroes superHero = superHeroes.get(position);
       Log.d("position", String.valueOf(position));
        Log.d("url", superHero.getImageUrl());
        imageLoader = CustomVolleyRequest.getInstance(context).getImageLoader();
        imageLoader.get(superHero.getImageUrl(), ImageLoader.getImageListener(holder.imageView, R.mipmap.ic_launcher, android.R.drawable.ic_dialog_alert));

        holder.imageView.setImageUrl(superHero.getImageUrl(), imageLoader);
        holder.textViewName.setText(superHero.getName());
        holder.textViewRank.setText(String.valueOf(superHero.getRank()));
        // holder.textViewRealName.setText(superHero.getRealName());
        //  holder.textViewCreatedBy.setText(superHero.getCreatedBy());
        // holder.textViewFirstAppearance.setText(superHero.getFirstAppearance());
        // Load =superHero.getImageUrl();
        // String powers = "";

        //  for(int i = 0; i<superHero.getPowers().size(); i++){
        //    powers+= superHero.getPowers().get(i);
        // }


        View.OnClickListener clickListener = new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                count++;
                ViewHolder h = (ViewHolder) view.getTag();
                //   int p=h.getAdapterPosition();
                SuperHeroes s = superHeroes.get(position);
                //  Toast.makeText(context,s.getImageUrl(),Toast.LENGTH_LONG).show();
                Load = s.getImageUrl();
                Log.d("test", Load);
                String s1 = new Integer(count).toString();
                Log.d("count", s1);
                new LikeIt().execute();
            }
        };
        // holder.textViewPowers.setText(powers);
        holder.like.setOnClickListener(clickListener);

    }


    @Override
    public int getItemCount() {
        return superHeroes.size();
    }



    public class ViewHolder extends RecyclerView.ViewHolder {
        public NetworkImageView imageView;

        public TextView textViewName;
        public TextView textViewRank;
        public TextView textViewRealName;
        public TextView textViewCreatedBy;
        public TextView textViewFirstAppearance;
        public TextView textViewPowers;
        public Button like;

        public ViewHolder(View itemView) {
            super(itemView);
            imageView = (NetworkImageView) itemView.findViewById(R.id.imageViewHero);
            textViewName = (TextView) itemView.findViewById(R.id.textViewName);
            textViewRank = (TextView) itemView.findViewById(R.id.textViewRank);
            // textViewRealName= (TextView) itemView.findViewById(R.id.textViewRealName);
            // textViewCreatedBy= (TextView) itemView.findViewById(R.id.textViewCreatedBy);
            // textViewFirstAppearance= (TextView) itemView.findViewById(R.id.textViewFirstAppearance);
            // textViewPowers= (TextView) itemView.findViewById(R.id.textViewPowers);
            like = (Button) itemView.findViewById(R.id.button_like);

        }


    }

    class LikeIt extends AsyncTask<String, String, String> {

        /**
         * Before starting background thread Show Progress Dialog
         */
        boolean failure = false;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();

        }

        @Override
        protected String doInBackground(String... args) {
            // TODO Auto-generated method stub
            // Check for success tag

             int success;

            String Imgurl = Load;
            Log.d("request!", number);

          //  try {
                // Building Parameters
                HashMap<String, String> Params = new HashMap<String, String>();
                Params.put("Imgurl", Imgurl);
           Params.put("user", number);


                Log.d("request!", "starting");

                //Posting user data to script
               /* JSONObject json = jsonParser.performPostCall(LIKE_URL,Params);

                // full json response
                Log.d("Login attempt", json.toString());

                // json success element
                success = json.getInt(TAG_SUCCESS);
                if (success == 1) {
                    Log.d("User Created!", json.toString());
                    //finish();
                    return json.getString(TAG_MESSAGE);
                }else{
                    Log.d("Login Failure!", json.getString(TAG_MESSAGE));
                    return json.getString(TAG_MESSAGE);

                }
            } catch (JSONException e) {
                e.printStackTrace();
            }

            return null;*/
                String encodedStr = getEncodedData(Params);

                //Will be used if we want to read some data from server
                BufferedReader reader = null;

                //Connection Handling
                try {
                    //Converting address String to URL
                    URL url = new URL(LIKE_URL);
                    //Opening the connection (Not setting or using CONNECTION_TIMEOUT)
                    HttpURLConnection con = (HttpURLConnection) url.openConnection();

                    //Post Method
                    con.setRequestMethod("POST");
                    //To enable inputting values using POST method
                    //(Basically, after this we can write the dataToSend to the body of POST method)
                    con.setDoOutput(true);
                    OutputStreamWriter writer = new OutputStreamWriter(con.getOutputStream());
                    //Writing dataToSend to outputstreamwriter
                    writer.write(encodedStr);
                    //Sending the data to the server - This much is enough to send data to server
                    //But to read the response of the server, you will have to implement the procedure below
                    writer.flush();

                    //Data Read Procedure - Basically reading the data comming line by line
                    StringBuilder sb = new StringBuilder();
                    reader = new BufferedReader(new InputStreamReader(con.getInputStream()));

                    String line;
                    while((line = reader.readLine()) != null) { //Read till there is something available
                        sb.append(line + "\n");     //Reading and saving line by line - not all at once
                    }
                    line = sb.toString();           //Saving complete data received in string, you can do it differently

                    //Just check to the values received in Logcat
                    Log.i("custom_check","The values :");
                    Log.i("custom_check",line);

                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if(reader != null) {
                        try {
                            reader.close();     //Closing the
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }

                //Same return null, but if you want to return the read string (stored in line)
                //then change the parameters of AsyncTask and return that type, by converting
                //the string - to say JSON or user in your case
                return null;
            }

        }
    private String getEncodedData(Map<String,String> data) {
        StringBuilder sb = new StringBuilder();
        for(String key : data.keySet()) {
            String value = null;
            try {
                value = URLEncoder.encode(data.get(key), "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

            if(sb.length()>0)
                sb.append("&");

            sb.append(key + "=" + value);
        }
        return sb.toString();
    }

        /**
         * After completing background task Dismiss the progress dialog
         **/
        protected void onPostExecute() {
            // dismiss the dialog once product deleted

            }
        }

在刷新时滑动时,如果我在刷新后立即向下滚动,应用程序会崩溃,但如果我等到刷新发生,我不会收到不一致错误

Logcat错误

11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: FATAL EXCEPTION: main
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: Process: com.example.tatson.bila, PID: 14987
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{278460a2 position=3 id=-1, oldPos=-1, pLpos:-1 no parent}
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:4247)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4378)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4359)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1961)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1370)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1333)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at android.support.v7.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1161)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at android.support.v7.widget.LinearLayoutManager.scrollVerticallyBy(LinearLayoutManager.java:1018)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at android.support.v7.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:3807)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at android.view.Choreographer.doCallbacks(Choreographer.java:580)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at android.view.Choreographer.doFrame(Choreographer.java:549)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at android.os.Handler.handleCallback(Handler.java:739)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at android.os.Handler.dispatchMessage(Handler.java:95)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at android.os.Looper.loop(Looper.java:135)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at android.app.ActivityThread.main(ActivityThread.java:5253)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Native Method)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Method.java:372)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

当我快速滚动到末尾而不是当我在最后一个项目上向下滚动时,滚动负载也会被激活

提前致谢!!! :)

分页背后的概念:

  1. 您将额外的 variable/value 传递给后端(在您的情况下 PHP)假设 "last_seen"。对于值的初始获取,您会将 last_seen 值作为 0 传递,这意味着 php 将具有在此值达到某个限制后获取值的逻辑(例如 PHP 将发送结果从索引 1 到 20 到 android。
  2. 正如您所知,您的上限是 20,因此下次在 RecyclerView.OnScrollListener 中的页面加载时,您将再次调用 PHP。但这次您的 last_seen 将为 20,而 PHP 将为您提供从 21 到 40 的结果,依此类推。

滑动刷新的概念:

在实现滑动刷新时,它有一个名为 onRefresh() 的方法,您将在此处应用初始 PHP 调用,其中 last_seen 为 0,它将获取初始数据来自后端。

要实现,请访问以下链接:

  1. Endless RecyclerView OnScrollListener
  2. http://android-pratap.blogspot.in/2015/01/endless-recyclerview-onscrolllistener.html
  3. Basic Pagination Tutorial (PHP).

我还写了一个新博客 post 来满足您在这里提出的要求。 检查此 Android Feed Example

您必须在您的服务器上创建一个分页脚本。我使用了以下代码。

<?php 

//Getting the page number which is to be displayed  
$page = $_GET['page'];  

//Initially we show the data from 1st row that means the 0th row 
$start = 0; 

//Limit is 3 that means we will show 3 items at once
$limit = 3; 

//Importing the database connection 
require_once('dbConnect.php');

//Counting the total item available in the database 
$total = mysqli_num_rows(mysqli_query($con, "SELECT id from feed "));

//We can go atmost to page number total/limit
$page_limit = $total/$limit; 

//If the page number is more than the limit we cannot show anything 
if($page<=$page_limit){

    //Calculating start for every given page number 
    $start = ($page - 1) * $limit; 

    //SQL query to fetch data of a range 
    $sql = "SELECT * from feed limit $start, $limit";

    //Getting result 
    $result = mysqli_query($con,$sql); 

    //Adding results to an array 
    $res = array(); 

    while($row = mysqli_fetch_array($result)){
        array_push($res, array(
            "name"=>$row['name'],
            "publisher"=>$row['publisher'],
            "image"=>$row['image'])
            );
    }
    //Displaying the array in json format 
    echo json_encode($res);
}else{
        echo "over";
}

其余相同..另外我添加了一个侦听器以在到达列表底部后加载列表中的更多记录。