利用PlaceHolderVidew库编写无限列表

利用PlaceHolderVidew库编写无限列表


首先来看一下效果图,以下就是我设想要做的事。


本次实验目标概述:

1、编写一个json文件里面存放学生的信息,该源将模拟从Internet加载json数据,然后填充到列表项中。

2、当应用程序模拟获取网络数据的时候,列表才会在底部显示加载视图。

3、我们将从Internet中用URL加载图形并将其设置到视图显示中,这里使用了Glide库。

4、json数据将会在应用程序中不断给予学生信息,形成无限列表。


本实验基于安卓PlaceHolderView库,该库具有InfinitePlaceHolderView类能够帮助实现本次设想。

PlaceHolderView库提供5种不同类型的视图

  1. PlaceHolderView
    它建立在RecyclerView之上,并抽象了大多数样板。它通过注释提供API。
  2. InfinitePlaceHolderView
    它基于PlaceHolderView构建,并添加了在用户滚动到列表底部时处理加载更多视图的功能。
  3. ExpandablePlaceHolderView
    它基于PlaceHolderView构建,并创建具有父类与子类关系的ExpandableListView。
  4. SwipePlaceHolderView
    它不是基于RecyclerView构建的。这是一个全新的实现。我们可以使用此类创建各种卡堆叠视图。它提供了可以轻松构建Tinder类的API。
  5. SwipeDirectionalView
    它建立在SwipePlaceHolderView之上。它提供滑动方向和触摸事件的回调。
本次实验用到其中的InfinitePlaceHolderView库,此类基于PlaceHolderView。它定义了更多加载回调和加载视图的方法。




让我们开始构建


步骤1:数据准备及获取联网权限

在android studio中设立一个新项目。

利用PlaceHolderVidew库编写无限列表_第1张图片

*build.gradle中*添加依赖项。

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'
}

在src/main目录中创建一个文件夹assets,用来存放json文件(内有学生信息),

在这里插入图片描述

在 mainfests中的AndroidManifest.xml中添加Internet权限,没有该权限不能访问因特网。

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

加在的后面即可。

利用PlaceHolderVidew库编写无限列表_第2张图片

笔记:

什么是JSON:JSON即JavaScript Object Natation, 它是一种轻量级的数据交换格式, 与XML一样, 是广泛被采用的客户端和服务端交互的解决方案.




步骤2:创建src/layout/activity_main.xml

该xml定义了列表的布局,设置列表的布局的整体方向为垂直方向。



    




步骤3:创建 src/layout/load_more_item_view.xml

该xml定义了列表的每一项的布局。



    
        
        
        
        
            
            
            
        
    

列表项的布局大致长这样:最上面的是学生名字,中间的是图片,正下方是学生信息,右下角是年级。

利用PlaceHolderVidew库编写无限列表_第3张图片




步骤4:创建 src/layout/load_more_view.xml

该xml是加载界面布,当从json中获取数据时,显示加载图标。



    

布局大致长这样:

利用PlaceHolderVidew库编写无限列表_第4张图片




步骤5:将infinite_list.json文件放入步骤1中创建的assets文件夹中并写入学生信息。

name是学生姓名,image_url是图片地址,caption是学生的信息,grade是年级信息。

json形式放置种子文件非常容易解析为模型。

[
	{
		"name" : "吴家鹏",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "福建师范大学数学与信息学院学生,学号116072017032",
		"grade" : "2017级"
	},
	{
		"name" : "陈彬",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "福建师范大学法学院学生,学号116072017031",
		"grade" : "2017级"
	},
	{
		"name" : "赵文鑫",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "福建师范大学化学院学生,学号116072017001",
		"grade" : "2018级"
	},
	{
		"name" : "王文忠",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"name" : "福建师范大学生命科学学院学生,学号116072017040",
		"grade" : "2016级"
	},
	{
		"name" : "张瑞建",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "福建师范大学法学院研究生,学号116072017030",
		"grade" : "2014级"
	},
	{
		"name" : "闫少奇",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "福建师范大学法学院研究生,学号116072017022",
		"grade" : "2015级"
	},
	{
		"name" : "张少",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "福建师范大学生命科学学院学生,学号116072017040",
		"grade" : "2018级"
	},
	{
		"name" : "何文",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "福建师范大学网络学院学生,学号116072017040",
		"grade" : "2018级"
	},
	{
		"name" : "杨子琪",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "福建师范大学文学院学生,学号116072017040",
		"grade" : "2018级"
	},
	{
		"name" : "陈晨",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "福建师范大学教育学生,学号116072017040",
		"grade" : "2017级"
	},
	{
		"name" : "杨超",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "福建师范大学音乐学院学生,学号116072017040",
		"grade" : "2018级"
	},
	{
		"name" : "林志强",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "福建师范大学生命科学学院学生,学号116072017040",
		"grade": "2018级"
	},
	{
		"name" : "叶存浩",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "福建师范大学物理学院学生,学号116072017040",
		"grade" : "2018级"
	},
	{
		"name": "林振铭",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"caption" : "福建师范大学音乐学院学生,学号116072017040",
		"grade" : "2018级"
	},
	{
		"name" : "林腾翔",
		"image_url" : "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=11813822,2468845429&fm=26&gp=0.jpg",
		"name" : "福建师范大学文学院学生,学号116072017040",
		"grade" : "2018级"
	}
]


笔记:

其实JSON数据就是一段字符串,只不过有不同意义的分隔符将其分割开来而已,其中

[] 代表的是一个数组;

{} 代表的是一个对象;
“ ” 表示的是属性值;
:代表的是前后之间的关系,冒号前面是属性的名称,后面是属性的值,这个值可以是基本数据类型,也可以是引用数据类型。




步骤6:创建Utils.java

utils.java包含解析种子json文件填充模型所需的方法InfiniteFeedInfo.java

public class Utils {

    private static final String TAG = "Utils";

    public static List loadInfiniteFeeds(Context context){
        try{
            GsonBuilder builder = new GsonBuilder();
            Gson gson = builder.create();
            JSONArray array = new JSONArray(loadJSONFromAsset(context, "infinite_news.json"));
            List feedList = new ArrayList<>();
            for(int i=0;i

笔记:

如果要将一个json数据转换为对象的话需要使用fromJson(String json, Class classOfT) /fromJson(String json, Type typeOfT),当我们将对象转换为String的时候根据String toJson(Object src)方法。这里需要注意一点,如果response.body().string()调用大于一次的话,就会报错java.lang.IllegalStateException: closed,因为response.body().string()调用一次之后流就断掉了,需要重新构建一个response。




步骤7:建立模型InfiniteFeedInfo.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;
    }
}

笔记:

1、首先说一下SerializedName的主要作用:属性重命名,可以将json中的属性名转为我们自己自定义的属性名其次@SerializedName注解提供了两个属性,上面用到了其中一个’value’,别外还有一个属性’alternate’:接收一个String数组,alternate数组中出现任意一个属性名都可以转换为自定义的属性,如果出现多个则以最后一个为准。@SerializedName 注解属于gson类,读取json文件变量并将其绑定到模型变量。

2、@Expose用于使变量对于gson的解析变为可读。




步骤8:现在,我们将创建类以绑定列表及其操作的项目视图。

ItemView.java 自定义生成JavaBean。

@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);
    }
}

笔记:

  1. @layout 用于将xml布局与此类绑定。

  2. @View 用于将视图绑定到我们要引用的布局中。

  3. @Resolve当视图位于内存中时调用一个方法,以便用数据填充该视图。

  4. Glide 用法传承目前流行的链式调用,他的基础用法如下。

    /**
     * 基础用法.
     */
    private void baseUsed(){
           
        Glide.with(this)
                .load(URL)
                .into(mImageView);
    }
    




步骤9:现在,我们将创建类以绑定并定义“加载更多”视图。

创建LoadMoreView.java类,为了模拟从Internet延迟加载数据,我定义了ForcedWaitedLoading类。此类创建一个新线程,然后在2秒后,在UI线程中添加更多数据视图列表,该视图应始终从UI线程更新。

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

    public static final int LOAD_VIEW_SET_COUNT = 6;

    private InfinitePlaceHolderView mLoadMoreView;
    private List mFeedList;

    public LoadMoreView(InfinitePlaceHolderView loadMoreView, List 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();
                }
            });
        }
    }
}

笔记:

  1. @LoadMore当列表滚动到最后一项时,将调用此注释。任何获取更多数据的请求都会调用此带注释的方法。
  2. mLoadMoreView.loadingDone()当所有数据都已获取并且视图已填充新数据时,需要调用此方法。它将删除加载视图。
  3. mLoadMoreView.noMoreToLoad()提取数据后,应调用此方法。它将停用加载功能。




步骤10:创建 MainActivity.java

我们获取的实例使用InfiniteFeedInfo模型列表中的数据添加视图。

使用setLoadMoreResolver方法添加LoadMoreView要用作加载指示符的对象。

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 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));
    }
}



然后我们点击运行。

这样我们就完成了!!!






参考资料:

PlaceHolderView库介绍文献:https://janishar.com/PlaceHolderView/docs/introduction.html

json数据解析:https://www.open-open.com/bbs/view/1319448346593

网络图片获取:https://blog.csdn.net/qq_42777804/article/details/103515640

你可能感兴趣的:(android)