Write an infinite list using the PlaceHolderVidew Library

Write an infinite list using the PlaceHolderVidew Library

First, let's look at the picture. Here's what I want to do.

Overview of the objectives of this experiment:

1. Write a json file to store the students'information. The source will simulate loading json data from the Internet and then populate the list item.

2. The list shows the load view at the bottom when the application simulates fetching network data.

3. We will load graphics from the Internet using URL s and set them to the view display, using the Glide library.

4. json data will continue to give students information in the application, forming an infinite list.

This experiment is based on the Android PlaceHolderView library, which has InfinitePlaceHolderView class to help implement this idea.

The PlaceHolderView library provides five different types of views

  1. PlaceHolderView
    It is built on RecyclerView and abstracts most of the templates.It provides API s through comments.
  2. InfinitePlaceHolderView
    It is built on PlaceHolderView and adds the ability to handle loading more views as users scroll to the bottom of the list.
  3. ExpandablePlaceHolderView
    It is built on the PlaceHolderView and creates an Expandable ListView with a parent-child relationship.
  4. SwipePlaceHolderView
    It is not built on RecyclerView.This is a brand new implementation.We can use this class to create various stacked views of cards.It provides an API that makes it easy to build Tinder classes.
  5. SwipeDirectionalView
    It is built on the SwipePlaceHolderView.It provides sliding direction and callback for touch events.
This experiment uses the InfinitePlaceHolderView library, which is based on PlaceHolderView.It defines more ways to load callbacks and views.

Let's start building:

Step 1: Data preparation and networking rights

Set up a new project in android studio.

stayBuild.gradleAdd dependencies to.

android {
    ...
    sourceSets {
        main {
            assets.srcDirs = ['src/main/assets', 'src/main/assets/']
            res.srcDirs = ['src/main/res', 'src/main/res/drawable']
        }
    }
}

dependencies {
    ...
    compile 'com.mindorks:placeholderview:0.7.1'
    compile 'com.android.support:cardview-v7:25.3.1'
    compile 'com.github.bumptech.glide:glide:3.7.0'
    compile 'com.google.code.gson:gson:2.7'
}

Create a folder assets in the src/main directory to hold the json file (with student information),

In mainfests AndroidManifest.xml Add Internet permission to the Internet, without which you can't access the Internet.

< users-permission  android : name = " android.permission.INTERNET " />

Add it after <application.... </application>.

Notes:

What is JSON: JSON, or JavaScript Object Nation, is a lightweight data exchange format that, like XML, is a widely used solution for client-side and server-side interactions.

Step 2: Create src/layout/activity_main.xml

This xml defines the layout of the list and sets the overall direction of the layout of the list to be vertical.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <com.mindorks.placeholderview.InfinitePlaceHolderView
        android:id="@+id/loadMoreView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

Step 3: Create src/layout/load_more_item_view.xml

The xml defines the layout of each item in the list.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardCornerRadius="4dp"
    app:cardElevation="1dp"
    android:layout_margin="5dp"
    app:cardBackgroundColor="@android:color/holo_blue_dark">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="10dp"
        android:paddingRight="20dp"
        android:paddingTop="10dp"
        android:paddingBottom="20dp"
        android:gravity="left">
        <android.support.v7.widget.CardView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            app:cardCornerRadius="4dp"
            app:cardElevation="1dp">
        <ImageView
            android:id="@+id/imageView"
            android:layout_width="60dp"
            android:layout_height="80dp"
            android:layout_gravity="top"
            android:scaleType="centerCrop"/>
        </android.support.v7.widget.CardView>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:orientation="vertical">
            <TextView
                android:id="@+id/nameTxt"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@android:color/white"
                android:textSize="16sp"
                android:typeface="sans"
                android:textStyle="normal"/>
            <TextView
                android:id="@+id/captionTxt"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:textColor="@android:color/white"
                android:textSize="12sp"
                android:typeface="sans"
                android:textStyle="normal"/>
            <TextView
                android:id="@+id/gradeTxt"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:layout_gravity="right"
                android:textColor="@android:color/white"
                android:textSize="12sp"
                android:typeface="sans"
                android:textStyle="normal"/>
        </LinearLayout>
    </LinearLayout>
</android.support.v7.widget.CardView>

The layout of the list items is roughly this long: the top is the student's name, the middle is the picture, the student information is directly below, and the bottom right is the grade.

Step 4: Create src/layout/load_more_view.xml

The xml is the loading interface cloth that displays the loading icon when data is retrieved from json.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:padding="5dp">
    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</LinearLayout>

The layout is roughly this long:

Step 5: infinite_List.jsonThe file is placed in the assets folder created in step 1 and student information is written.

Name is the student's name, image_The URL is the picture address, the caption is the student's information, and the grade is the grade information.

Placing a seed file in the form of json is very easy to parse into a model.

[
	{
		"name" : "Wu Jiapeng",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "College of Mathematics and Information, Fujian Normal University, No. 116072017032",
		"grade" : "2017 level"
	},
	{
		"name" : "Ksssssss",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "Law School Student, Fujian Normal University, No. 116072017031",
		"grade" : "2017 level"
	},
	{
		"name" : "Zhao Wenxin",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "College of Chemistry, Fujian Normal University, No. 116072017001",
		"grade" : "2018 level"
	},
	{
		"name" : "Wang Wenzhong",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"name" : "College of Life Sciences, Fujian Normal University, No. 116072017040",
		"grade" : "2016 level"
	},
	{
		"name" : "Zhang Ruijian",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "Postgraduate, Law School, Fujian Normal University, No. 116072017030",
		"grade" : "2014 level"
	},
	{
		"name" : "Yan Shaoqi",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "Postgraduate, Law School, Fujian Normal University, No. 116072017022",
		"grade" : "2015 level"
	},
	{
		"name" : "Zhang Shao",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "College of Life Sciences, Fujian Normal University, No. 116072017040",
		"grade" : "2018 level"
	},
	{
		"name" : "Ho Wen",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "Students of Network College, Fujian Normal University, No. 116072017040",
		"grade" : "2018 level"
	},
	{
		"name" : "Yang Ziqi",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "College of Literature, Fujian Normal University, No. 116072017040",
		"grade" : "2018 level"
	},
	{
		"name" : "Chen Chen Chen",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "Educational Student, Fujian Normal University, No. 116072017040",
		"grade" : "2017 level"
	},
	{
		"name" : "Yang Chao",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "Music College Student, Fujian Normal University, No. 116072017040",
		"grade" : "2018 level"
	},
	{
		"name" : "Lin Zhiqiang",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "College of Life Sciences, Fujian Normal University, No. 116072017040",
		"grade": "2018 level"
	},
	{
		"name" : "Ye Cunhao",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "College of Physics, Fujian Normal University, No. 116072017040",
		"grade" : "2018 level"
	},
	{
		"name": "Lin Zhenming",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "Music College Student, Fujian Normal University, No. 116072017040",
		"grade" : "2018 level"
	},
	{
		"name" : "Lin Tengxiang",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"name" : "College of Literature, Fujian Normal University, No. 116072017040",
		"grade" : "2018 level"
	}
]


Notes:

The JSON data is actually a string, but it's just split up by delimiters with different meanings, where

[] represents an array;

{} represents an object;
"" denotes an attribute value;
The colon is preceded by the name of the property, followed by the value of the property, which can be either a basic data type or a reference data type.

Step 6: CreateUtils.java

Utils.javaContains the methods needed to parse the seed json file to populate the modelInfiniteFeedInfo.java

public class Utils {

    private static final String TAG = "Utils";

    public static List<InfiniteFeedInfo> loadInfiniteFeeds(Context context){
        try{
            GsonBuilder builder = new GsonBuilder();
            Gson gson = builder.create();
            JSONArray array = new JSONArray(loadJSONFromAsset(context, "infinite_news.json"));
            List<InfiniteFeedInfo> feedList = new ArrayList<>();
            for(int i=0;i<array.length();i++){
                InfiniteFeedInfo feed = gson.fromJson(array.getString(i), InfiniteFeedInfo.class);
                feedList.add(feed);
            }
            return feedList;
        }catch (Exception e){
            Log.d(TAG,"seedGames parseException " + e);
            e.printStackTrace();
            return null;
        }
    }

    private static String loadJSONFromAsset(Context context, String jsonFileName) {
        String json = null;
        InputStream is=null;
        try {
            AssetManager manager = context.getAssets();
            Log.d(TAG,"path "+jsonFileName);
            is = manager.open(jsonFileName);
            int size = is.available();
            byte[] buffer = new byte[size];
            is.read(buffer);
            is.close();
            json = new String(buffer, "UTF-8");
        } catch (IOException ex) {
            ex.printStackTrace();
            return null;
        }
        return json;
    }
}

Notes:

If you want to convert a JSON data to an object, you need to use fromJson(String json, Class classOfT) /fromJson(String json, Type typeOfT), according to the String toJson(Object src) method when we convert an object to a String.One thing to note here is ifResponse.bodyError will occur if ().string() is called more than onceJava.lang.IllegalStateException: closed, becauseResponse.body(). string() is called once and the stream is broken and a response needs to be rebuilt.

Step 7: ModelingInfiniteFeedInfo.java

public class InfiniteFeedInfo {

    @SerializedName("name")
    @Expose
    private String name;

    @SerializedName("image_url")
    @Expose
    private String imageUrl;

    @SerializedName("caption")
    @Expose
    private String caption;

    @SerializedName("grade")
    @Expose
    private String grade;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getImageUrl() {
        return imageUrl;
    }

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

    public String getCaption() {
        return caption;
    }

    public void setCaption(String caption) {
        this.caption = caption;
    }

    public String getGrade() {
        return grade;
    }

    public void setGrade(String grade) {
        this.grade = grade;
    }
}

Notes:

1. First, let's talk about the main functions of SerializedName: property renaming, which can change the name of a property in json to our own custom property name. Second, the @SerializedName annotation provides two properties, one of which is used above, and the other is property'alternate': receiving a String array, any property name appearing in the alternate array can beTo convert to a custom property, if more than one occurs, the last one prevails.The @SerializedName annotation belongs to the gson class, reading json file variables and binding them to model variables.

2. @Expose is used to make the variable's resolution of gson readable.

Step 8: Now we will create a class to bind the project view of the list and its operations.

ItemView.java Customize the generation of JavaBean s.

@Layout(R.layout.load_more_item_view)
public class ItemView {

    @View(R.id.nameTxt)
    private TextView nameTxt;

    @View(R.id.captionTxt)
    private TextView captionTxt;

    @View(R.id.gradeTxt)
    private TextView gradeTxt;

    @View(R.id.imageView)
    private ImageView imageView;

    private InfiniteFeedInfo mInfo;
    private Context mContext;

    public ItemView(Context context, InfiniteFeedInfo info) {
        mContext = context;
        mInfo = info;
    }

    @Resolve
    private void onResolved() {
        nameTxt.setText(mInfo.getName());
        captionTxt.setText(mInfo.getCaption());
        gradeTxt.setText(mInfo.getGrade());
        Glide.with(mContext).load(mInfo.getImageUrl()).into(imageView);
    }
}

Notes:

  1. @layout is used to bind an xml layout to this type.

  2. @View is used to bind views to the layout we want to reference.

  3. @Resolve Calls a method when the view is in memory to populate the view with data.

  4. Glide usage inherits the current popular chain call, and his basic usage is as follows.

    /**
     * Basic usage.
     */
    private void baseUsed(){
        Glide.with(this)
                .load(URL)
                .into(mImageView);
    }
    

Step 9: Now we will create a class to bind and define the Load More view.

Establish LoadMoreView.java Class, to simulate delayed loading of data from the Internet, I defined the ForcedWaitedLoading class.This class creates a new thread, then after 2 seconds, adds more lists of data views to the UI thread that should always be updated from the UI thread.

@Layout(R.layout.load_more_view)
public class LoadMoreView {

    public static final int LOAD_VIEW_SET_COUNT = 6;

    private InfinitePlaceHolderView mLoadMoreView;
    private List<InfiniteFeedInfo> mFeedList;

    public LoadMoreView(InfinitePlaceHolderView loadMoreView, List<InfiniteFeedInfo> feedList) {
        this.mLoadMoreView = loadMoreView;
        this.mFeedList = feedList;
    }

    @LoadMore
    private void onLoadMore(){
        Log.d("DEBUG", "onLoadMore");
        new ForcedWaitedLoading();
    }

    class ForcedWaitedLoading implements Runnable{

        public ForcedWaitedLoading() {
            new Thread(this).start();
        }

        @Override
        public void run() {

            try {
                Thread.currentThread().sleep(2000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    int count = mLoadMoreView.getViewCount();
                    Log.d("DEBUG", "count " + count);
                    for (int i = count - 1;
                         i < (count - 1 + LoadMoreView.LOAD_VIEW_SET_COUNT) && mFeedList.size() > i;
                         i++) {
                        mLoadMoreView.addView(new ItemView(mLoadMoreView.getContext(), mFeedList.get(i)));

                        if(i == mFeedList.size() - 1){
                            mLoadMoreView.noMoreToLoad();
                            break;
                        }
                    }
                    mLoadMoreView.loadingDone();
                }
            });
        }
    }
}

Notes:

  1. @LoadMore calls this comment when the list scrolls to the last item.Any request for more data invokes this annotated method.
  2. mLoadMoreView.loadingDone() This method needs to be called when all data has been acquired and the view has been populated with new data.It will delete the load view.
  3. mLoadMoreView.noMoreToLoad() This method should be called after the data has been extracted.It will disable the load function.

Step 10: CreateMainActivity.java

The instance we get uses the data in the InfiniteFeedInfo model list to add a view.

Use the setLoadMoreResolver method to add the object LoadMoreView will use as the load indicator.

public class MainActivity extends AppCompatActivity {

    private InfinitePlaceHolderView mLoadMoreView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mLoadMoreView = (InfinitePlaceHolderView)findViewById(R.id.loadMoreView);
        setupView();
    }

    private void setupView(){

        List<InfiniteFeedInfo> feedList = Utils.loadInfiniteFeeds(this.getApplicationContext());
        Log.d("DEBUG", "LoadMoreView.LOAD_VIEW_SET_COUNT " + LoadMoreView.LOAD_VIEW_SET_COUNT);
        for(int i = 0; i < LoadMoreView.LOAD_VIEW_SET_COUNT; i++){
            mLoadMoreView.addView(new ItemView(this.getApplicationContext(), feedList.get(i)));
        }
        mLoadMoreView.setLoadMoreResolver(new LoadMoreView(mLoadMoreView, feedList));
    }
}

Then we click Run.

So we're done!!!

Reference material:

PlaceHolderView Library Introduction: https://janishar.com/PlaceHolderView/docs/introduction.html

json data parsing: https://www.open-open.com/bbs/view/1319448346593

Web Picture Acquisition: https://blog.csdn.net/qq_42777804/article/details/103515640

Author: Wu Jiapeng
Original Link: https://blog.csdn.net/qq_41855439/article/details/106695183

Keywords: Android JSON xml Java

Added by dianaqt on Thu, 11 Jun 2020 19:15:23 +0300