仿知乎程序(三)读取webService,解析json,volley以及PullToRefreshListView的使用

       我们已经实现了侧滑菜单的切换与toolbar菜单根据不同页面显示不同工具的功能,今天我们就来完成首页的显示。知乎首页有这么几个功能:
1,列表功能,信息是以列表的形式展示出来的
2,列表要能实现下拉刷新,上拉加载的功能
3,图片与文字并存
4,点击其中一项的不同区域,会跳到不同的详细页面,点击标题会跳动到一个页面,点击下面信息概要又会跳到另一个页面

     好,我们就来实现这四个功能。
     这里的信息,我是通过读取服务器上webService传过来的json数据,进行解析来当信息源的。所以我们先要把信息源从服务器读出来,才能进行下面的操作。在做这之前,我们先看一下这个首页都有哪些项,有一个用户的图片,一个标题,一个信息的大小,和信息的内容。为了能更好的进行将信息读取,我们先建一个model类,把相关的字段先加上。代码如下:

IndexList.java

/**
 * 用于显示在index_fragment中ListView的内容
 * Created by cg on 2015/10/29.
 */
public class IndexList {
    private int questionID;                                                  //问题ID
    private String questionTitle;                                            //问题标题
    private String questionSize;                                             //问题点在字节数
    private String questionContent;                                          //问题内容
    private String userPic;                                                  //发问者头像

    public IndexList() {
    }

    public IndexList(int questionID, String questionTitle, String questionSize, String questionContent, String userPic) {
        this.questionID = questionID;
        this.questionTitle = questionTitle;
        this.questionSize = questionSize;
        this.questionContent = questionContent;
        this.userPic = userPic;
    }

    public int getQuestionID() {
        return questionID;
    }

    public void setQuestionID(int questionID) {
        this.questionID = questionID;
    }

    public String getQuestionTitle() {
        return questionTitle;
    }

    public void setQuestionTitle(String questionTitle) {
        this.questionTitle = questionTitle;
    }

    public String getQuestionSize() {
        return questionSize;
    }

    public void setQuestionSize(String questionSize) {
        this.questionSize = questionSize;
    }

    public String getQuestionContent() {
        return questionContent;
    }

    public void setQuestionContent(String questionContent) {
        this.questionContent = questionContent;
    }

    public String getUserPic() {
        return userPic;
    }

    public void setUserPic(String userPic) {
        this.userPic = userPic;
    }
}

       好,model类我们建好了,现在我们就要从webServies开始取数据了,android读取webServies有很多好的第三方插件,这里我使用的是Ksoap2-android,它的使用网上有很多,我就不多说了,https://github.com/simpligility/ksoap2-android可以去下载,下载之后,我们引入jar.因为这里面我们需要一些常用的变量值,比如说地址什么的,所以我使用一个class,来存这些常用变量
configStatic.java
/**
 * 常量信息
 * Created by cg on 2015/10/29.
 */
public class configStatic {
    /**
     * webServies地址的命名空间,域名
     */
    public static String WEBSERVIESNAMESPACE = "http://tempuri.org/";

    /**
     * webServies明确地址
     */
    public static String WEBSERVIESURL = "http://192.168.0.163:8090/webServices/questionInfo.asmx";

    /**
     *  webServices的方法名_用来提取10条问题
     */
    public static String WEBSERVICES_INDEXLIST = "getQuestionList";
}

    这里的地址是我本地的地址,下面是它传回来的数据格式:
[{"questionID":28,"questionTitle":"苍井空老师的个人简介","questionSize":"387","questionContent":"\r\n 苍井空,1983年11月11日出生于日本东京。日本AV女演员、
成人模特,兼电视、电影演员。日本女子组合惠比寿麝香葡萄的初代首领,现成员、OG首领。2010年3月毕业并将组合首领之位交托给麻美由真,同年10月复归。
\r\n 入行前曾是泳装写真女星,2002年进入AliceJapan公司,开始性感影片的拍摄生涯。因为其“童颜巨乳”的特色,开始获得人气,并连续在2003年及2004年蝉联日本
《VideoBoy》杂志年度性感女艺人第一名。[1] 从2003年起,开始参加一般电视戏剧及综艺节目中演出,[2] 2004年11月移籍到S1,成功转型,大牌杂志模特及电影演员。
\r\n","userPic":"http://imgcdn.kdnet.net/UploadSmall/2013/07/21/137438445351976.jpg"},{"questionID":27,"questionTitle":"波多野结衣的故事",
"questionSize":"679","questionContent":"波多野结衣(はたの ゆい),女,1988年5月24日出生于日本京都府,著名日本女演员、AV女优。
2008年,波多野结衣开始从事AV出演,并于11月加入H.M.P公司,成为H.M.P的素人,不久便被H.M.P公司雪藏,随后在BeFree公司发行过两部影片,
又转投ATTACKER公司,后又签约SKY HIGH公司。2012年,波多野结衣出席第九届上海国际成人展开幕和第二届台湾成人博览会。",
"userPic":"http://img1.imgtn.bdimg.com/it/u=1823077414,3028399801\u0026fm=21\u0026gp=0.jpg"}]

好,我们来看一下,如何读取这个webService:
webservicesUntils.java
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;

/**
 * webservice 操作类
 * Created by cg on 2015/10/29.
 */
public class webservicesUntils {
    private static SoapObject rpc = null;
    private static SoapSerializationEnvelope envelope = null;
    private static HttpTransportSE ht = null;

    /**
     * 调用问题信息
     * @param strWhere      查询条件
     * @param orderby       排序字段
     * @param startIndex    开始记录数
     * @param endIndex      结束记录数
     * @return
     * @throws Exception
     */
    public static String getIndexItemList(final String strWhere,final String orderby,final int startIndex,final int endIndex) throws IOException, XmlPullParserException, IOException, XmlPullParserException {

        rpc = new SoapObject(configStatic.WEBSERVIESNAMESPACE, configStatic.WEBSERVICES_INDEXLIST);
        // 设置调用方法参数的值
        rpc.addProperty("strWhere", strWhere);
        rpc.addProperty("orderby", orderby);
        rpc.addProperty("startIndex", startIndex);
        rpc.addProperty("endIndex",endIndex);

        // 生成调用Webservice方法的SOAP请求信息
        envelope = new SoapSerializationEnvelope(SoapEnvelope.VER12);         //这里要注意,这里是webService的版本号,一般是10,11,12这三个值,如果你不确定,可以每个都试一下
        envelope.bodyOut = rpc;
        envelope.dotNet = true;
        envelope.setOutputSoapObject(rpc);
        // 创建HttpTransportSE对象,通过HttpTransportSE类的构造方法可以指定WebService的url
        ht = new HttpTransportSE(configStatic.WEBSERVIESURL);
        ht.debug = true;
        // 使用call方法调用WebService方法

        ht.call(null, envelope);

        String result = "0";

        //检查ht.call是否运行
        //Log.e("city", strWhere + startIndex + endIndex);

        // 判断取到的值是否为空
        if(envelope.getResponse() == null) {
            result = "0";
        }else{
            result = envelope.getResponse().toString();
        }

        return result;
    }
}

要想让它好用,我们还要给它添加
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />权限

这里就不多说了,上面的注解比较清楚,通过webservice我们已经把要得到的数据取回来了,接下来,我们就要把数据显示出来。这种列表形式的显示我们一般都是采用ListView控件来展示,可是我们结合第二点的需求,就是需求一个上拉和下拉的需求,这个功能ListView是没有,我们只能继承ListView自己写控件,可是自己写有点麻烦了,还好有这方面的第三插件,当然了,google也发布了一个官方的SwipeRefreshLayout插件,虽然很不错,可是它只有下拉刷新,没有上拉加载的功能。所以这里我们使用PullToRefreshListView控件,https://github.com/chrisbanes/Android-PullToRefresh,大家可以去这里下载,可惜的是,它没有给android studio提供直接加载的链接,我们直接采用加载project的方式,来加载它。好了,我们来修改一下我们之前的fragment_index.xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!--
       ptr:ptrMode:PullToRefreshListView设置向上拉刷新还是向下拉刷新模式
                PULL_FROM_END: 下拉刷新
              PULL_FROM_START: 上拉加载
                         both: 下拉刷新和上拉加载都有
    -->
    <com.handmark.pulltorefresh.library.PullToRefreshListView
        xmlns:ptr="http://schemas.android.com/apk/res-auto"
        android:id="@+id/pullrefresh_index_list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:cacheColorHint="#00000000"
        android:divider="@color/grey"
        android:dividerHeight="1dp"
        android:fadingEdge="none"
        android:fastScrollEnabled="false"
        android:footerDividersEnabled="false"
        android:headerDividersEnabled="false"
        android:smoothScrollbar="true"
        ptr:ptrMode="both">
    </com.handmark.pulltorefresh.library.PullToRefreshListView>

</LinearLayout>

PullToRefreshListView控件的使用与ListView控件的使用大体相当,没什么特别的地方,就是加载Adapter然后显示出来,但是它多了两个方法,
public void onPullDownToRefresh(PullToRefreshBase<ListView> refreshView) {
                        // 模拟加载任务
                        
                    }

                    @Override
                    public void onPullUpToRefresh(PullToRefreshBase<ListView> refreshView) {
                        
                        
                    }

是用来实现上拉加载,下拉刷新的,而且都是要通过异步来进行加载的。好了,我们来修改一下首页的java代码吧
import android.app.ProgressDialog;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.Toast;

import com.example.cg.zhihu_one.untils.netUntils;
import com.example.cg.zhihu_one.untils.webservicesUntils;
import com.handmark.pulltorefresh.library.PullToRefreshBase;
import com.handmark.pulltorefresh.library.PullToRefreshListView;

/**
 * 首页
 * Created by cg on 2015/10/27.
 */
public class IndexFragment extends Fragment {

    //定义信息等等控件
    private ProgressDialog myProgressDialog;
    private PullToRefreshListView pullrefresh_index_list;                       //定义信息列表
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_index,container,false);
        initControls(view);
        return view;
    }
    /**
     * 对下拉列表控件进行初始化,并初始化进度控件
     * @param view
     */
    private void initControls(View view) {

        pullrefresh_index_list = (PullToRefreshListView)view.findViewById(R.id.pullrefresh_index_list);

        //初始化数据
        initDatas();

        // 设置下拉和上拖监听事件
        pullrefresh_index_list
                .setOnRefreshListener(new PullToRefreshBase.OnRefreshListener2<ListView>() {
                    @Override
                    public void onPullDownToRefresh(PullToRefreshBase<ListView> refreshView) {
                        // 模拟加载任务
                        //new GetDownDataTask().execute();
                    }

                    @Override
                    public void onPullUpToRefresh(PullToRefreshBase<ListView> refreshView) {
                        //Log.e("onPullUpToRefresh","有反应没有啊");
                        //new GetUpDataTask().execute();
                    }

                });

    }

    /**
     * 初始时,加载10条数据上来
     */
    private void initDatas()
    {
        if(netUntils.isNetworkAvailable(getActivity())) {
            // 初始化数据和数据源
            myProgressDialog = new ProgressDialog(getActivity());
            myProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);  //设置风格为圆形进度条
            myProgressDialog.setTitle("提示");                                 //设置标题
            myProgressDialog.setMessage("数据加载中,请稍等...");                 //设置内容
            myProgressDialog.setIndeterminate(false);                         //设置进度是否为不明确
            myProgressDialog.setCancelable(true);                             //设置进度条是否可以按退回键取消
            myProgressDialog.show();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    Message msg = new Message();

                    try {
                        String soapObject = webservicesUntils.getIndexItemList("", "", 1, 10);

                        Log.e("soapObject",soapObject);


                        msg.arg1 = 1;

                        handler.sendMessage(msg);

                    } catch (Exception ex) {
                        msg.arg1 = 2;
                    }
                }
            }).start();
        }else
        {
            Toast.makeText(getActivity(), "请检查您的网络是否打开!", Toast.LENGTH_LONG).show();
        }

    }

    Handler handler = new Handler(){

        @Override
        public void handleMessage(Message msg) {
            if(msg.arg1==1)
            {
                //Log.e("")

            }else
            {
                Toast.makeText(getActivity(), "数据读取失败!", Toast.LENGTH_LONG).show();
            }

            myProgressDialog.dismiss();
        }
    };
}

简单对程序说一下,这里我们只是简单的实现了一下把webservices中的数据取到,然后用log的方式显示出来,并没有对PullToRefreshListView进行设置什么,因为从网络中读取数据,这是需要时间的,所以我们采用了handle的方式。为了给用户一个更好的用户体验,我们加入了ProgressDialog控件,来显示等待的时间。
我们运行一下,你会发现,我们可以在logcat中显示出相应的信息了。
好,这说明我们的数据读取成功了,下面我们来设置一下列表中各item的布局和为PullToRefreshListView编写一个adapter.
在编写布局之前,我要说明一点,以前我们在做web程序的时候,图片我们都是在数据库中存取的图片地址,而不是采用二进制的形式把图片存在数据库中,这里我们也是采用这种方式,我们去看刚才我给的数据格式,我们的图片,也是一个网络地址,这样的话,就需要我们把这个网络图片显示出来,显示网络图片,用我们常用的ImageView是不行了,处非我们把图片下载到本地,然后再进行加载。现在有一个非常好用的volley,为我们提供了网络加载图片的功能。下面这个blog. http://blog.csdn.net/guolin_blog/article/details/17482095,一共是四篇,非常详细的介绍了它的使用,下载地址:http://download.csdn.net/detail/sinyu890807/7152015
这里我们用到的是就是其中的NetworkImageView。先把volley.jar导入我们的程序。好了,我们来看一下,item的布局文件
fragment_index_list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp">

        <TextView
            android:id="@+id/txt_index_item_Cate"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="热门话题"
            android:textSize="@dimen/list_remark_size"
            android:textColor="@color/gray"/>
        <com.android.volley.toolbox.NetworkImageView
            android:id="@+id/netimg_index_item_userpic"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:src="@drawable/img_empty_followers"
            android:layout_alignParentRight="true"
            />
    </RelativeLayout>
    <LinearLayout
        android:id="@+id/linear_index_item_title"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp"
        android:cacheColorHint="#00000000">
        <TextView
            android:id="@+id/txt_index_item_title"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text=" "
            android:textColor="@color/black"
            android:textSize="@dimen/ActionBar_title_size"
            />
    </LinearLayout>
    <LinearLayout
        android:id="@+id/linear_index_item_content"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp"
        android:cacheColorHint="#00000000"
        android:background="@drawable/index_list_item_background">
        <TextView
            android:id="@+id/txt_index_item_size"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:duplicateParentState="true"
            android:background="@drawable/index_list_item_sizebacground"
            android:text="1324K"
            android:textSize="@dimen/list_remark_size"
            android:textColor="@drawable/index_list_item_sizetextcolor"
            android:layout_marginRight="5dp"
            android:gravity="center"
            android:layout_marginTop="2dp"
            />
        <TextView
            android:id="@+id/txt_index_item_content"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text=" "
            android:textSize="@dimen/list_remark_size"
            android:textColor="@drawable/index_list_item_contexttextcolor"
            android:duplicateParentState="true"
            android:lines="3"
            android:ellipsize = "end"
            android:layout_weight="8"
            />
    </LinearLayout>

</LinearLayout>

在这里,我为内容布局设置了动态背景还把文字颜色也设置成了动态的,这个是为了在用户点击的时候,达到相应的变化。虽然这个对于功能来说并没有什么卵用。
在drawable/index_list_item_background.xml 代码:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:state_activated="true"
        android:drawable="@color/titleBlue"
        />
    <item
        android:state_focused="false"
        android:state_pressed="true"
        android:drawable="@color/titleBlue" />
    <item android:drawable="@android:color/transparent" />
</selector>

index_list_item.sizebacground.xml
<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

<!-- 没有焦点时的背景图片 -->
<item android:state_window_focused="false" android:drawable="@color/titleBlue" />

<item android:state_focused="false" android:state_pressed="true" android:drawable="@color/white" />
<!-- 默认时的背景图片-->
<item android:drawable="@color/white" />
</selector>
    这里要注意一点的是,我们一般喜欢设置一下默认的背景图片或是颜色,这里一定要把这个默认的值放在最下面,不然上面的所有变化就都不好用。
index_list_item.contexttextcolor.xml
<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- 没有焦点时的背景图片 -->
    <item android:state_window_focused="false" android:color="@color/gray" />

    <item android:state_focused="false" android:state_pressed="true"   android:color="@color/white" />
    <!-- 默认时的背景图片-->
    <item android:color="@color/gray" />

</selector>

index_list_item_sizetextcolor.xml
<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- 没有焦点时的背景图片 -->
    <item android:state_window_focused="false" android:color="@color/white" />

    <item android:state_focused="false" android:state_pressed="true"   android:color="@color/titleBlue" />
    <!-- 默认时的背景图片-->
    <item android:color="@color/white" />

</selector>

    好,item布局文件搞定,我们来看一下Adapter的代码:
Index_lv_Adapter.java
import android.content.Context;
import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.NetworkImageView;
import com.android.volley.toolbox.Volley;
import com.example.cg.zhihu_one.R;
import com.example.cg.zhihu_one.models.IndexList;
import com.example.cg.zhihu_one.untils.imagesUntils;

import java.util.List;

/**
 * 首页信息列表Adapter
 * Created by cg on 2015/10/30.
 */
public class Index_lv_Adapter extends BaseAdapter {

    private List<IndexList> list_index;                                  //定义显示的信息列表
    private LayoutInflater inflater;

    //定义volley
    private RequestQueue mQueue;
    private ImageLoader imageLoader;
    private Context context;

    public Index_lv_Adapter(Context context,List<IndexList> list_index) {
        this.context = context;
        this.inflater = LayoutInflater.from(context);
        this.list_index = list_index;

        mQueue = Volley.newRequestQueue(context);
        imageLoader = new ImageLoader(mQueue,new imagesUntils.BitmapCache(){
            @Override
            public Bitmap getBitmap(String s) {
                return null;
            }

            @Override
            public void putBitmap(String s, Bitmap bitmap) {

            }
        });
    }

    @Override
    public int getCount() {
        return list_index.size();
    }

    @Override
    public Object getItem(int position) {
        return list_index.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        final index_list_info listclass;
        if(convertView==null)
        {
            listclass = new index_list_info();
            convertView = inflater.inflate(R.layout.fragment_index_list_item,null,false);
            listclass.userpic = (NetworkImageView)convertView.findViewById(R.id.netimg_index_item_userpic);
            listclass.item_title = (TextView)convertView.findViewById(R.id.txt_index_item_title);
            listclass.item_size = (TextView)convertView.findViewById(R.id.txt_index_item_size);
            listclass.item_content = (TextView)convertView.findViewById(R.id.txt_index_item_content);
            listclass.linear_index_item_title = (LinearLayout)convertView.findViewById(R.id.linear_index_item_title);
            listclass.linear_index_item_content = (LinearLayout)convertView.findViewById(R.id.linear_index_item_content);

            convertView.setTag(listclass);
        }
        else
        {
            listclass = (index_list_info)convertView.getTag();
        }

        //为图片控件加载图片,采用NetworkImageView控件。
        //第一项是加载图片控件的默认图片,一般是图片加载中,这样的图片
        //第二项是当发生错误的时候加载的图片,如网络图片路径不对或是加载失败的时候显示的图片
        //第三项就是加载网络图片了
        listclass.userpic.setDefaultImageResId(R.drawable.img_empty_followers);
        listclass.userpic.setErrorImageResId(R.drawable.img_empty_followers);
        listclass.userpic.setImageUrl(list_index.get(position).getUserPic(), imageLoader);

        listclass.item_title.setText(list_index.get(position).getQuestionTitle());
        listclass.item_size.setText(list_index.get(position).getQuestionSize());
        listclass.item_content.setText(list_index.get(position).getQuestionContent());


        // 只所以在这里添加点击事件,而不是为控件添加onitemclistener事件,
        // 是因为,在一个item里,点击上半部分和下半部分将要跳转的页面不同
        listclass.linear_index_item_content.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                /*Intent cIntent = new Intent();
                cIntent.setClass(context, Index_detailActivity.class);
                cIntent.putExtra("questionID", list_index.get(position).getQuestionID());
                cIntent.putExtra("questionTitle",list_index.get(position).getQuestionTitle());
                context.startActivity(cIntent);*/
            }
        });

        return convertView;
    }


    public class index_list_info
    {
        NetworkImageView userpic;
        TextView item_title;
        TextView item_size;
        TextView item_content;
        LinearLayout linear_index_item_title;
        LinearLayout linear_index_item_content;
    }
}

这里我把volley处理图片,防止OOM的代码单独拿出来,放到一个公共类里面,供以后的程序的调用。
imagesUntils.java
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.LruCache;

import com.android.volley.toolbox.ImageLoader;
/**
 * 各种对图片进行操作的通用方法
 * Created by cg on 2015/10/30.
 */
public class imagesUntils {
    /**
     * 显示保存在手机中的图片,加入了缩小图片的功能,防止OOM
     *
     * @param imgPath            文件路径
     * @param screenWidth        手机宽
     * @param screenHeight       手机高
     * @return                   Bitmap类型
     */
    public static Bitmap viewPic(String imgPath,int screenWidth,int screenHeight)
    {

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;                                //不去真的解析图片 获取图片头部信息
        Bitmap mitmap = BitmapFactory.decodeFile(imgPath, options);       //取得图片的信息
        int height = options.outHeight;                                   //图片的高
        int width = options.outWidth;                                     //图片的宽

        // 得到手机屏幕宽高比
        int scaleX=width/screenHeight;
        int scaleY=height/screenWidth;
        int scale=1;                                                      //默认缩小比例是1
        // 如果高的比例大,并且比例大于1,也就是图片的高要大于手机的高
        if(scaleX>scaleY && scaleY>=1)
        {
            scale=scaleX;
        }

        if(scaleY>scaleX && scaleX>=1)
        {
            scale=scaleY;
        }

        options.inJustDecodeBounds=false;                                  //真的去解析图片
        options.inSampleSize=scale;                                        //按比例缩小图片
        Bitmap bm = BitmapFactory.decodeFile(imgPath, options);
        return bm;
    }


    /**
     * 对图片进行防OOM处理
     */
    public static class BitmapCache implements ImageLoader.ImageCache{

        private LruCache<String,Bitmap> mCache;

        public BitmapCache(){
            int maxSize = 10*1024*1024;
            mCache = new LruCache<String, Bitmap>(maxSize){
                protected int sizeOf(String key,Bitmap bitmap)
                {
                    return bitmap.getRowBytes() * bitmap.getHeight();
                }
            };
        }

        @Override
        public Bitmap getBitmap(String url) {
            return mCache.get(url);
        }

        @Override
        public void putBitmap(String url, Bitmap bitmap) {
            mCache.put(url,bitmap);
        }
    }
}

Adapter程序完成,我们来修改首页的程序,为PullToRefreshListView控件绑定数据。修改后的代码如下:

import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.Toast;

import com.example.cg.zhihu_one.Adapters.Index_lv_Adapter;
import com.example.cg.zhihu_one.models.IndexList;
import com.example.cg.zhihu_one.untils.netUntils;
import com.example.cg.zhihu_one.untils.webservicesUntils;
import com.handmark.pulltorefresh.library.PullToRefreshBase;
import com.handmark.pulltorefresh.library.PullToRefreshListView;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 首页
 * Created by cg on 2015/10/27.
 */
public class IndexFragment extends Fragment {

    //定义信息等等控件
    private ProgressDialog myProgressDialog;
    private PullToRefreshListView pullrefresh_index_list;                       //定义信息列表

    private List<IndexList> list_index;                                         //定义显示数据的list
    private Index_lv_Adapter indexAdapter;                                      //定义Adapter

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_index,container,false);
        initControls(view);
        return view;
    }
    /**
     * 对下拉列表控件进行初始化,并初始化进度控件
     * @param view
     */
    private void initControls(View view) {

        pullrefresh_index_list = (PullToRefreshListView)view.findViewById(R.id.pullrefresh_index_list);

        list_index = new ArrayList<>();

        //初始化数据
        initDatas();

        // 设置下拉和上拖监听事件
        pullrefresh_index_list
                .setOnRefreshListener(new PullToRefreshBase.OnRefreshListener2<ListView>() {
                    @Override
                    public void onPullDownToRefresh(PullToRefreshBase<ListView> refreshView) {
                        // 模拟加载任务
                        new GetDownDataTask().execute();
                    }

                    @Override
                    public void onPullUpToRefresh(PullToRefreshBase<ListView> refreshView) {
                        //Log.e("onPullUpToRefresh","有反应没有啊");
                        new GetUpDataTask().execute();
                    }

                });

    }

    /**
     * 初始时,加载10条数据上来
     */
    private void initDatas()
    {
        if(netUntils.isNetworkAvailable(getActivity())) {
            // 初始化数据和数据源
            myProgressDialog = new ProgressDialog(getActivity());
            myProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);  //设置风格为圆形进度条
            myProgressDialog.setTitle("提示");                                 //设置标题
            myProgressDialog.setMessage("数据加载中,请稍等...");                 //设置内容
            myProgressDialog.setIndeterminate(false);                         //设置进度是否为不明确
            myProgressDialog.setCancelable(true);                             //设置进度条是否可以按退回键取消
            myProgressDialog.show();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    Message msg = new Message();

                    try {

                        //得到数据
                        String soapObject = webservicesUntils.getIndexItemList("", "", 1, 10);

                        //判断如果数据返回的不是错误代码0,则对返回的json数据进行解析,将数据存入List中
                        if (soapObject != "0") {
                            try {

                                JSONArray jsonArray = new JSONArray(soapObject);

                                for (int i = 0; i < jsonArray.length(); i++) {
                                    JSONObject jsonObject2 = (JSONObject) jsonArray.opt(i);

                                    IndexList comm = new IndexList();
                                    comm.setUserPic(jsonObject2.getString("userPic"));
                                    comm.setQuestionTitle(jsonObject2.getString("questionTitle"));
                                    comm.setQuestionSize(jsonObject2.getString("questionSize"));
                                    comm.setQuestionContent(jsonObject2.getString("questionContent"));
                                    comm.setQuestionID(jsonObject2.getInt("questionID"));

                                    list_index.add(comm);
                                }
                            } catch (JSONException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                        }



                        msg.arg1 = 1;

                        handler.sendMessage(msg);

                    } catch (Exception ex) {
                        msg.arg1 = 2;
                    }
                }
            }).start();
        }else
        {
            Toast.makeText(getActivity(), "请检查您的网络是否打开!", Toast.LENGTH_LONG).show();
        }

    }

    Handler handler = new Handler(){

        @Override
        public void handleMessage(Message msg) {
            if(msg.arg1==1)
            {
                if(list_index!=null)
                {
                    //设置适配器
                    indexAdapter = new Index_lv_Adapter(getActivity(),list_index);
                    pullrefresh_index_list.setAdapter(indexAdapter);
                }else
                {
                    Toast.makeText(getActivity(), "无数据加载!", Toast.LENGTH_LONG).show();
                }

            }else
            {
                Toast.makeText(getActivity(), "数据读取失败!", Toast.LENGTH_LONG).show();
            }

            myProgressDialog.dismiss();
        }
    };

    /**
     * 下拉时,更新数据,从list中提取第一条数据也就是最新的一条,传回,以供判断是否有新的数据,如果有,则对listView进行刷新
     * 通过return将得到的数据返回给protected void onPostExecute(String result),以便在前台显示
     */
    private class GetDownDataTask extends AsyncTask<Void, Void, String>
    {

        //异步取数据
        @Override
        protected String doInBackground(Void... params)
        {
            try
            {
                //这里调用一个webServices取新添加的数据
                //原理:取现在list中最新的数据,去后台数据中进行对比,如果有比这个新的数据,就取,没有则返回0
                String soapObject = webservicesUntils.getIndexItemList_refresh(String.valueOf(list_index.get(0).getQuestionID()));

                return soapObject;
            }  catch (XmlPullParserException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "" ;
        }

        //将数据显示在前台
        @Override
        protected void onPostExecute(String result)
        {
            if(!result.equals("0"))
            {
                try {

                    //我们采用了.add(location,comm)方法,指定了插入的位置,这样就把新的数据直接插入到前面
                    //list_index.clear();                //清空List<>中的数据

                    JSONArray jsonArray = new JSONArray(result);

                    for (int i = 0; i < jsonArray.length(); i++) {
                        JSONObject jsonObject2 = (JSONObject) jsonArray.opt(i);

                        IndexList comm = new IndexList();
                        comm.setUserPic(jsonObject2.getString("userPic"));
                        comm.setQuestionTitle(jsonObject2.getString("questionTitle"));
                        comm.setQuestionSize(jsonObject2.getString("questionSize"));
                        comm.setQuestionContent(jsonObject2.getString("questionContent"));
                        comm.setQuestionID(jsonObject2.getInt("questionID"));

                        list_index.add(0,comm);

                    }
                    indexAdapter.notifyDataSetChanged();
                    //num=1;
                } catch (JSONException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            //刷新结束,必须加上此句,不然下面的加载图标一下在
            pullrefresh_index_list.onRefreshComplete();
        }
    }

    /**
     * 向上刷新加载更多的数据
     */
    public class GetUpDataTask extends AsyncTask<Void, Void, String> {

        @Override
        protected String doInBackground(Void... params) {

            try {

                String soapObject = webservicesUntils.getIndexItemList("", "", list_index.size() + 1, 10);

                return soapObject;

            } catch (Exception ex) {
                return "0";
            }

        }

        @Override
        protected void onPostExecute(String result) {
            if (result != "0") {
                try {

                    JSONArray jsonArray = new JSONArray(result);

                    for (int i = 0; i < jsonArray.length(); i++) {
                        JSONObject jsonObject2 = (JSONObject) jsonArray.opt(i);

                        IndexList comm = new IndexList();
                        comm.setUserPic(jsonObject2.getString("userPic"));
                        comm.setQuestionTitle(jsonObject2.getString("questionTitle"));
                        comm.setQuestionSize(jsonObject2.getString("questionSize"));
                        comm.setQuestionContent(jsonObject2.getString("questionContent"));
                        comm.setQuestionID(jsonObject2.getInt("questionID"));

                        list_index.add(comm);
                    }

                    indexAdapter.notifyDataSetChanged();
                } catch (JSONException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            //刷新结束,必须加上此句,不然下面的加载图标一下在
            pullrefresh_index_list.onRefreshComplete();
        }

    }
}

显示的结果图:

在这里,要说明的一点是PullToRefreshListView控件的setOnRefreshListener方法, 它里面有两个实现方法, 一个是我们在程序中所使用的
new PullToRefreshBase.OnRefreshListener2<ListView>()方法, 这个是既有上拉,又有下拉的方法,还有一个是
new PullToRefreshBase.OnRefreshListener<ListView>()方法,这个是只有上拉
可通过http://blog.csdn.net/lmj623565791/article/details/38238749这个blog了解更细的使用说明


你可能感兴趣的:(仿知乎程序(三)读取webService,解析json,volley以及PullToRefreshListView的使用)