okhttp请求远程数据并在ListView显示

1.我在本地搭建的服务端,基于springmvc,hibernate和注解,写了一个简单查询方法:

    @RequestMapping(value="/topicjson.do",method=RequestMethod.GET)
    @ResponseBody   
    public void topicjson(HttpSession session,HttpServletRequest request,HttpServletResponse response){
        Listtopiclist=this.topicservice.getAllTopic();
        for (TBaseTopic tBaseTopic : topiclist) {
            tBaseTopic.setPublishdatestr(DateUtil.formatDate(tBaseTopic.getPublishdate(), "yyyy-MM-dd HH:mm"));
        }
        JSONArray array=JSONArray.fromObject(topiclist);
        response.setContentType("text/json;charset=utf-8");//设置编码
        PrintWriter out=null;
        try {
            out = response.getWriter();
        } catch (Exception e) {
        }
        out.print(array.toString());
    }

将查询出来的数据集合转成jsonArray,然后out.print(array.toString());将结果打印出来,要注意的是需要设置下数据格式和编码,不然中文会出现乱码问题。
先通过浏览器访问这个方法:http://192.168.56.1/springtest/topicaction/topicjson.do
ip是我们手机端访问我们本地服务器的ip,cmd,ipconfig,以太网IPv4
然后可以看到页面上的json格式的数据:

[{"comment":0,"heart":3,"id":"1","image":"","nickname":"管理员","publishdate":{"date":8,"day":4,"hours":7,"minutes":0,"month":11,"nanos":0,"seconds":0,"time":1481151600000,"timezoneOffset":-480,"year":116},"publishdatestr":"2016-12-08 07:00","topic":"如果再给你一次回去的机会,你想回到什么时候?","userid":"1001"},{"comment":0,"heart":22,"id":"2","image":"","nickname":"管理员","publishdate":{"date":28,"day":2,"hours":0,"minutes":0,"month":1,"nanos":0,"seconds":0,"time":1488211200000,"timezoneOffset":-480,"year":117},"publishdatestr":"2017-02-28 00:00","topic":"薛之谦的歌总能莫名其妙的戳中泪点","userid":"1001"},{"comment":0,"heart":221,"id":"3","image":"","nickname":"管理员","publishdate":{"date":28,"day":2,"hours":0,"minutes":0,"month":1,"nanos":0,"seconds":0,"time":1488211200000,"timezoneOffset":-480,"year":117},"publishdatestr":"2017-02-28 00:00","topic":"致陪伴我们每天的网易云音乐","userid":"1001"},{"comment":0,"heart":1,"id":"4","image":"","nickname":"管理员","publishdate":{"date":28,"day":2,"hours":0,"minutes":0,"month":1,"nanos":0,"seconds":0,"time":1488211200000,"timezoneOffset":-480,"year":117},"publishdatestr":"2017-02-28 00:00","topic":"说说你童年时候给你印象深刻的一件事","userid":"1001"},{"comment":7,"heart":0,"id":"5","image":"","nickname":"管理员","publishdate":{"date":1,"day":3,"hours":0,"minutes":0,"month":2,"nanos":0,"seconds":0,"time":1488297600000,"timezoneOffset":-480,"year":117},"publishdatestr":"2017-03-01 00:00","topic":"高中时候的你有没有曾为理想奋斗过","userid":"1001"},{"comment":6,"heart":6,"id":"6","image":"","nickname":"管理员","publishdate":{"date":1,"day":3,"hours":0,"minutes":0,"month":2,"nanos":0,"seconds":0,"time":1488297600000,"timezoneOffset":-480,"year":117},"publishdatestr":"2017-03-01 00:00","topic":"杭漂的日子里都有谁陪你度过","userid":"1001"},{"comment":0,"heart":7,"id":"7","image":"","nickname":"管理员","publishdate":{"date":1,"day":3,"hours":0,"minutes":0,"month":2,"nanos":0,"seconds":0,"time":1488297600000,"timezoneOffset":-480,"year":117},"publishdatestr":"2017-03-01 00:00","topic":"七八十年代那时候年轻人的娱乐方式","userid":"1001"},{"comment":0,"heart":4,"id":"8","image":"","nickname":"管理员","publishdate":{"date":1,"day":3,"hours":0,"minutes":0,"month":2,"nanos":0,"seconds":0,"time":1488297600000,"timezoneOffset":-480,"year":117},"publishdatestr":"2017-03-01 00:00","topic":"七八十年代那时候年轻人的娱乐方式","userid":"1001"},{"comment":0,"heart":2,"id":"9","image":"","nickname":"管理员","publishdate":{"date":1,"day":3,"hours":0,"minutes":0,"month":2,"nanos":0,"seconds":0,"time":1488297600000,"timezoneOffset":-480,"year":117},"publishdatestr":"2017-03-01 00:00","topic":"七八十年代那时候年轻人的娱乐方式","userid":"1001"}]

2.下面就是手机端ListView加载数据这块的开发了,总结一下:
UI线程中不能去加载数据
okhttp请求数据
ListView数据填充

3.新建一个实体类,TBaseUser.java

package com.imooc.forum.entity;

/**
 * Created by lsk on 2017/3/5.
 */

public class TBaseUser {
    private  String id;
    private String topic;

    public TBaseUser(){}

    public TBaseUser(String id,String topic){
        this.id=id;
        this.topic=topic;
    }

    public String getId(){
        return id;
    }

    public void setId(String id){
        this.id=id;
    }

    public String getTopic(){
        return topic;
    }

    public void setTopic(String topic){
        this.topic=topic;
    }

}

4.新建一个请求数据的工具类,MyHttpUtil.java

package com.imooc.forum.httputil;

import com.squareup.okhttp.Call;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;

import java.io.IOException;

/**
 * Created by lsk on 2017/3/9.
 */

public class MyHttpUtil {
    String str="";
    public String httpGet(String url){
        OkHttpClient okHttpClient=new OkHttpClient();
        Request.Builder builder=new Request.Builder();
        Request request=builder.get().url(url).build();
        Call call=okHttpClient.newCall(request);
        //同步GET请求
        try {
            Response response=call.execute();
            if(!response.isSuccessful()) {
                Headers responseHeaders = response.headers();
                for (int i = 0; i < responseHeaders.size(); i++) {
                    System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
                }
            }
            str= response.body().string();
        }catch (Exception e){
            e.printStackTrace();
        }

        //异步GET请求
        /*call.enqueue(new Callback() {
            @Override
            public void onFailure(Request request, IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(Response response) throws IOException {
                str=response.body().toString();
            }
        });*/
        return str;
    }
}

需要在项目中添加okhttp的依赖,打开build.gradle,在dependencies中添加一行:

compile 'com.squareup.okhttp:okhttp:2.6.0'

然后你会看到上面会出现一行提示,Sync Now,点击它会自动给你添加jar包,然后Open Module Setting,dependencies,你会看到我们需要的jar已经添加上了。

通过Request.Builder构造一个request,然后将request当做一个参数传到okHttpClient.newCall()方法中,返回一个call,call执行,返回response,从response的body()获取数据,这里要注意的是用string()方法获得字符串,而不是toString()

4.然后看布局文件,activity_main.xml


<RelativeLayout 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">

    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/mylistview"
        >
    ListView>

RelativeLayout>

我们还要自己定义一个布局文件,用于ListView的每一项的填充布局,mylistitem.xml


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:id="@+id/mylistitem"
    android:paddingBottom="3dp"
    android:paddingLeft="10dp"
    >
    <TextView
        android:layout_height="wrap_content"
        android:layout_width="fill_parent"
        android:id="@+id/ItemTitle"
        android:textSize="30dip">
    TextView>
    <TextView
        android:layout_height="wrap_content"
        android:layout_width="fill_parent"
        android:id="@+id/ItemText">
    TextView>
LinearLayout>

这里只是简单的定义两个TextView显示测试数据

5.基础工作做好后,就要看MainActivity我们的主页面了

package com.imooc.forum;

import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.imooc.forum.entity.TBaseUser;
import com.imooc.forum.httputil.MyHttpUtil;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.RunnableFuture;

public class MainActivity extends AppCompatActivity {
    ListView listView;
    File cache;//缓存文件
    Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            listView.setAdapter(new ContactAdapter(MainActivity.this,(List)msg.obj,R.layout.mylistitem,cache));
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        listView=(ListView)findViewById(R.id.mylistview);
        cache=new File(Environment.getExternalStorageDirectory(), "cache"); // 实例化缓存文件
        if (!cache.exists())cache.mkdirs(); // 如果文件不存在,创建
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    List data =getTBaseUser();
                    // 通过handler来发送消息,通知主线程去更新UI
                    handler.sendMessage(handler.obtainMessage(22, data));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    //加载远程数据
    private ListgetTBaseUser(){
        String url="http://192.168.56.1/springtest/topicaction/topicjson.do";//网络请求路径
        Listlist=new ArrayList<>();
        MyHttpUtil httpUtil=new MyHttpUtil();
        String str=httpUtil.httpGet(url);//获取请求的数据
        Log.d(str,"msg");
        try {
            JSONArray array=new JSONArray(str);
            for(int i=0;i
                JSONObject object=(JSONObject) array.get(i);
                TBaseUser user=new TBaseUser();
                user.setId(object.get("id").toString());
                user.setTopic(object.get("topic").toString());
                list.add(user);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return list;
    }

    @Override
    protected void onDestroy() {
        // 删除缓存
        for (File file : cache.listFiles()) {
            file.delete();
        }
        cache.delete();
        super.onDestroy();
    }
}

getTBaseUser是解析请求数据的方法,将请求的数据转成jsonArray,遍历array获取每一个jsonObject,从object中根据id,topic获取要用的数据,封装到实体类中

new一个新的线程去请求数据,并通过handler发送消息通知UI线程更新数据
handler.sendMessage(handler.obtainMessage(22, data));

在handler中:

listView.setAdapter(new ContactAdapter(MainActivity.this,(List)msg.obj,R.layout.mylistitem,cache));

6.下面就要写我们的填充器ContactAdapter

package com.imooc.forum;

import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.imooc.forum.entity.TBaseUser;

import org.w3c.dom.Text;

import java.io.File;
import java.util.List;

/**
 * Created by lsk on 2017/3/10.
 */

public class ContactAdapter extends BaseAdapter {
    private List data;//缓存数据
    private int listviewItem;//条目id
    private File cache;//缓存文件
    LayoutInflater layoutInflater;

    public ContactAdapter(Context context, List data, int listviewItem, File cache) {
        this.data = data;
        this.listviewItem = listviewItem;
        this.cache = cache;
        layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);//获取布局填充服务
    }

    /**
     * 得到数据的总数
     * @return
     */
    @Override
    public int getCount() {
        return data.size();
    }

    /**
     * 根据数据索引得到集合所对应的数据
     * @param position
     * @return
     */
    @Override
    public Object getItem(int position) {
        return data.get(position);
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        TextView textView = null;
        TextView textView1=null;
        if (convertView == null) {
            convertView = layoutInflater.inflate(listviewItem, null); // 获取条目的view对象
            textView = (TextView) convertView.findViewById(R.id.ItemText);
            textView1=(TextView)convertView.findViewById(R.id.ItemTitle);
            convertView.setTag(new DataWrapper(textView,textView1));
        } else {
            DataWrapper dataWrapper = (DataWrapper) convertView.getTag();
            textView = dataWrapper.textView;
            textView1=dataWrapper.textView1;
        }
        TBaseUser user = data.get(position);
        textView.setText(user.getId());
        textView1.setText(user.getTopic());
        //asyncImageLoad(imageView, contact.image);
        return convertView;
    }

    /*
     private void asyncImageLoad(ImageView imageView, String path) {
        AsyncImageTask asyncImageTask = new AsyncImageTask(imageView);
        asyncImageTask.execute(path);

    }
    private final class AsyncImageTask extends AsyncTask {
        private ImageView imageView;

        public AsyncImageTask(ImageView imageView) {
            this.imageView = imageView;
        }

        protected Uri doInBackground(String... params) {// 子线程中执行的
            try {
                return ContactService.getImage(params[0], cache);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        protected void onPostExecute(Uri result) {// 运行在主线程
            if (result != null && imageView != null)
                imageView.setImageURI(result);
        }
    }
    */


    private final class DataWrapper {
        public TextView textView;
        public TextView textView1;
        public DataWrapper(TextView textView, TextView textView1) {
            this.textView = textView;
            this.textView1=textView1;
        }
    }
}

ContactAdapter继承BaseAdapter,重写父类方法,在getView()方法中,给布局文件绑定数据

7.要在AndroidManifest.xml添加访问网络权限:

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

8.测试时候有可能出现的问题需要注意:
response.body().toString();会报错:

org.json.JSONException: Value com.squareup.okhttp.internal.http.RealResponseBody@536ca2e4 of type java.lang.String cannot be converted to jsonArray

应该用string()方法

当返回的字符串为“”时转jsonArray会报错,所以要做为空处理
org.json.JSONException: End of input at character 0 of

然后启动Genymotion,运行项目,效果如下:
okhttp请求远程数据并在ListView显示_第1张图片
界面是很丑的,不过我们的主要目的是通过okhttp加载远程数据并填充到ListView上,效果已经实现了,还有一些要做的,本地缓存,图片加载处理,界面mylistitem.xml布局的优化

特别感谢下面博主,学习到了很多。
博客地址:
http://blog.csdn.net/true_maitian/article/details/53234458

你可能感兴趣的:(安卓)