zoukankan      html  css  js  c++  java
  • 安卓权威编程指南 挑战练习 23章

    23.10 挑战练习:Gson

    无论什么平台,把JSON数据转化为Java对象都是应用开发的常见任务,如代码清单23-12所
    做的那样。于是,聪明的开发者就创建了一些工具库,希望能简化JSON数据和Java对象的互转。
    Gson就是这样的一个工具库(https://github.com/google/gson)。不用写任何解析代码,Gson
    就能自动把JSON数据映射为Java对象。因为这个特性,Gson现在是开发者最喜爱的JSON解析库。
    挑战自己,在应用中整合Gson库,简化 FlickrFetchr 中的JSON解析代码。

    要使用GSON,首先要添加GSON库的依赖。在dependencies闭包中添加如下内容:

      compile 'com.google.code.gson:gson:2.7'

    GSON可以将一段JSON格式的字符串自动映射成一个对象。

    编写GalleryItemBean类,代码如下:

     1 public class GalleryItemBean {
     2 
     3     @SerializedName("photos")
     4     public Photos mPhotos;
     5 
     6 
     7     public static class Photos{
     8         @SerializedName("photo")
     9         public List<GalleryItem> photo;
    10 
    11         public List<GalleryItem> getPhoto() {
    12             return photo;
    13         }
    14 
    15         public void setPhoto(List<GalleryItem> photo) {
    16             this.photo = photo;
    17         }
    18     }
    19 
    20     public Photos getPhotos() {
    21         return mPhotos;
    22     }
    23 
    24     public void setPhotos(Photos photos) {
    25         mPhotos = photos;
    26     }
    27 }

    这里没有去重写GalleryItem类,而是在类中使用了GalleryItem类。

    GSON要求类属性和JSON字段里面的KEY一模一样,但是可以通过在类属性的上面增加@SerializedName(String)来为属性添加注解。

    JSON数据中的photo字段里面的内容是用[]括起来的。所以应在CalleryItemBean类中将photo字段定义为List集合。

    接着修改GalleryItem类,为其添加注解:

     1 public class   GalleryItem {
     2 
     3     @SerializedName("title")
     4     private String mCaption;
     5 
     6     @SerializedName("id")
     7     private String mId;
     8 
     9     @SerializedName("url_s")
    10     private String mUrl;
    11 
    12     @Override
    13     public String toString(){
    14         return mCaption;
    15     }
    16 
    17     public String getCaption() {
    18         return mCaption;
    19     }
    20 
    21     public void setCaption(String caption) {
    22         mCaption = caption;
    23     }
    24 
    25     public String getId() {
    26         return mId;
    27     }
    28 
    29     public void setId(String id) {
    30         mId = id;
    31     }
    32 
    33     public String getUrl() {
    34         return mUrl;
    35     }
    36 
    37     public void setUrl(String url) {
    38         mUrl = url;
    39     }
    40 }

    最后修改FlickrFetcher类中的代码,增加如下方法:

     1 private void parseItems(List<GalleryItem> items, String jsonData){
     2         Gson gson = new Gson();
     3         GalleryItemBean gib = gson.fromJson(jsonData,GalleryItemBean.class); //GSON解析。将json数据传入到CalleryItemBean类中。
     4         List<GalleryItem> photoList = gib.getPhotos().getPhoto();
     5 
     6         for(int i=0; i<photoList.size(); i++){
     7             GalleryItem  photoItem = photoList.get(i);
     8             items.add(photoItem);
     9         }
    10     }

    增加了一个通过GSON方式解析json数据的方法。

    最后在fetchItems()方法中调用即可。

     parseItems(items,jsonString);

    23.11 挑战练习:分页

    getRecent 方法默认返回一页包含100个结果的数据。不过,该方法还有个叫作 page 的参数,
    可以用它返回第二页、第三页等更多页数据。
    请实现一个 RecyclerView.OnScrollListener 方法,只要用户看完当前页,就使用下页返
    回结果替换当前页。想更有挑战的话,可以尝试把后续结果页添加到当前结果页后面。

    修改FlickrFetcher中的fetchItems()方法,为其增加一个int 参数,作为页面的切换数。并且增加一个appenQueryParameter("page",String.valueOf(count))用来切换页面。

    public List<GalleryItem> fetchItems(int count){
    
            List<GalleryItem> items = new ArrayList<>();
            try{
                String url = Uri.parse("https://api.flickr.com/services/rest/")
                        .buildUpon()
                        .appendQueryParameter("page",String.valueOf(count))  //显示传进来的参数的页面。
                        .appendQueryParameter("method", "flickr.photos.getRecent")
                        .appendQueryParameter("api_key", API_KEY)
                        .appendQueryParameter("format", "json")
                        .appendQueryParameter("nojsoncallback", "1")
                        .appendQueryParameter("extras", "url_s")
                        .build().toString();
            ......
    }

    接下来在PhotoGalleryFragment中增加一个全局变量,用来传入fetchItems()方法。

      private int mCount = 1;

    修改doInBackground()方法

    protected List<GalleryItem> doInBackground(Void... parms){
                mCount++; // 页码数加一 
                return  new FlickrFetcher().fetchItems(mCount); 
            }

    最后一步设置RecyclerView的滑动监听事件。

    在onCreateView()方法中增加一下代码。

     //设置滑动监听事件
            mPhotoRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    int lastVisibleItem = mGridLayoutManager.findLastCompletelyVisibleItemPosition(); //最后位置
                    int totalItemCount = mGridLayoutManager.getItemCount(); //总位置
    
                    // 判断是否滚动到底部
                    if (lastVisibleItem == (totalItemCount - 1)) {
                        //开启新的AsyncTask,因为一个AsyncTask只能execute()一次。
                        new FetchItemsTask().execute();
    
                        Log.d(TAG, "滑倒底部了");
                    }
                }
            });

    将后续结果页添加到当前结果页后面。

    在PhotoGalleryFragment定义一个全局变量,用来添加所有的出现过的数据。

     private List<GalleryItem> mGalleryItemList = new ArrayList<>();

    修改PhotoAdapter的构造方法

            public PhotoAdapter(List<GalleryItem> galleryItems){
                for(GalleryItem item : galleryItems){
                    mGalleryItemList.add(item);
                }
            }

    之后将PhotoAdapter类中的mGalleryItems全部替换为mGalleryItemList即可。

    代码如下:

      private class PhotoAdapter extends RecyclerView.Adapter<PhotoHolder>{
    
            private List<GalleryItem> mGalleryItems;
    
            public PhotoAdapter(List<GalleryItem> galleryItems){
                for(GalleryItem item : galleryItems){
                    mGalleryItemList.add(item);
                }
            }
    
            @Override
            public PhotoHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                TextView textView = new TextView(getActivity());
                return new PhotoHolder(textView);
            }
    
            @Override
            public void onBindViewHolder(PhotoHolder photoHolder, int position) {
                GalleryItem galleryItem = mGalleryItemList.get(position);
                photoHolder.bindGalleryItem(galleryItem);
            }
    
            @Override
            public int getItemCount() {
                return mGalleryItemList.size();
            }
        }

    23.12 挑战练习:动态调整网格列

    当前,显示图片标题的网格固定有3列。编写代码动态调整网格列数,实现在横屏或大屏幕
    设备上显示更多的标题列。
    实现这个目标有个简单方法:分别为不同的设备配置或屏幕尺寸提供整数修饰资源。这实际
    和第17章中为不同尺寸屏幕提供不同布局的方式差不多。整数修饰资源应放置在res/values目录
    中。具体实施细节可参阅Android开发者文档。
    提供整数修饰资源的方式不太好确定网格列细分粒度(只能凭经验预先定义列数)。下面再
    介绍一个颇具挑战的方法:在fragment的视图创建时就计算并设置好网格列数。显然,这种方式
    更加灵活实用。基于 RecyclerView 的当前宽度和预定义网格列宽,就可以计算出列数。
    实施前还有个问题要解决:我们不能在 onCreateView() 方法中计算网格列数,因为这个时
    候 RecyclerView 还没有改变。不过,可以实现 ViewTreeObserver.OnGlobalLayoutListener
    监听器方法和计算列数的 onGlobalLayout() 方法,然后使用 addOnGlobalLayoutListener()
    把监听器添加给 RecyclerView 视图。

     在PhotoGalleryFragment的onCreateView()方法增加如下代码即可:

    mPhotoRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    //根据最大的值来计算列数
                    int width = getActivity().getWindowManager().getDefaultDisplay().getWidth();
                    int height = getActivity().getWindowManager().getDefaultDisplay().getHeight();
                    int scale = 0;
                    if(width > height)
                        scale = width;
                    else
                        scale = height;
    
                    int columns = scale / 200;
                    mPhotoRecyclerView.setLayoutManager(new GridLayoutManager(getActivity(),columns));
                    setupAdapter();
                    mPhotoRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);//移除掉。。
                }
            });

    完整代码如下:

    @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
            final View v = inflater.inflate(R.layout.fragment_photo_gallery, container, false);
            
            mPhotoRecyclerView = (RecyclerView)v.findViewById(R.id.fragment_photo_gallery_recycler_view);
            mGridLayoutManager = new GridLayoutManager(getActivity(), mRows);
            mPhotoRecyclerView.setLayoutManager(mGridLayoutManager);
            //设置滑动监听事件
            mPhotoRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    int lastVisibleItem = mGridLayoutManager.findLastCompletelyVisibleItemPosition(); //最后位置
                    int totalItemCount = mGridLayoutManager.getItemCount(); //总位置
    
                    // 判断是否滚动到底部
                    if (lastVisibleItem == (totalItemCount - 1)) {
                        //开启新的AsyncTask,因为一个AsyncTask只能execute()一次。
                        new FetchItemsTask().execute();
    
                        Log.d(TAG, "滑倒底部了");
                    }
                }
            });
            setupAdapter();
            //要写在mPhotoRecyclerView实例化之后
            mPhotoRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    //根据最大的值来计算列数
                    int width = getActivity().getWindowManager().getDefaultDisplay().getWidth();
                    int height = getActivity().getWindowManager().getDefaultDisplay().getHeight();
                    int scale = 0;
                    if(width > height)
                        scale = width;
                    else
                        scale = height;
    
                    int columns = scale / 200;
                    mPhotoRecyclerView.setLayoutManager(new GridLayoutManager(getActivity(),columns));
                    setupAdapter();
                    mPhotoRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);//移除掉。。
                }
            });
    
            return v;
        }
  • 相关阅读:
    杂谈
    xss bypass 学习记录
    小结--dns注入
    在CentOS 7 安装没有mysql
    备份WordPress
    php留言
    基于mysq搭建的l许愿墙
    http服务的安装与配置
    centos 7忘记密码重置
    安装centos 7 桌面
  • 原文地址:https://www.cnblogs.com/chase1/p/7206213.html
Copyright © 2011-2022 走看看