Android网络框架OKhttp3学习笔记

来源:互联网 发布:淘宝正版av代购 编辑:程序博客网 时间:2024/05/31 05:27
      OKhttp3是一个非常强大的Android网络框架,它是由Square公司开发并开源的,很大Android开发者都会使用到,所以我也要来学学。

服务器

为了方便测试,我们需要一个后台服务器的的应用,下面是一个Java Web的Servlet,它的功能是接收客户端发来的登录数据,判断密码是否正确,并返回结果(JSON格式)

import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.io.Writer;@WebServlet(name = "MyServlet",urlPatterns = {"/MyServlet"})public class MyServlet extends HttpServlet {    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        //获取表单数据        String number = request.getParameter("number");        String pwd = request.getParameter("pwd");        String body;        //判断密码和账号有没有正确        if (number.equals("12345") && pwd.equals("12345")){            body = "{\"result\":\"success\",\"file\":\"/file/123.jpg\"}";        }else {            body = "{\"result\":\"faile\"}";        }        //打印结果        PrintWriter writer = response.getWriter();        writer.write(body);    }    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        this.doPost(request, response);    }}

客户端

使用OKhttp3要添加依赖库,下面的语句会加入两个库,一个是基础包Okio,另一个就是OKhttp

compile 'com.squareup.okhttp3:okhttp:3.8.1'

需要创建两个Activity,一个是登录界面,一个是登录结果界面

然后把activity_main.xml修改成如下,做出一个登录界面

<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"    tools:context="com.example.dell.testokhttp3.MainActivity">    <EditText        android:id="@+id/edit_number"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:hint="请输入账号" />    <EditText        android:id="@+id/edit_pwd"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:hint="请输入密码" />    <LinearLayout        android:orientation="horizontal"        android:layout_width="match_parent"        android:layout_height="wrap_content">        <Button            android:layout_weight="1"            android:layout_width="0dp"            android:layout_height="wrap_content"            android:onClick="getRequest"            android:text="get登录" />        <Button            android:layout_weight="1"            android:layout_width="0dp"            android:layout_height="wrap_content"            android:onClick="postRequest"            android:text="post登录" />    </LinearLayout></LinearLayout>

界面图

之后把activity_main2.xml修改成如下,做出一个登录成功后的界面

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_main2"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context="com.example.dell.testokhttp3.Main2Activity">    <Button        android:text="显示图片"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:id="@+id/showImage"        android:onClick="showImage" />    <Button        android:text="保存图片"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:id="@+id/saveImage"        android:onClick="saveImage" />    <ImageView        android:id="@+id/imageview"        android:layout_width="match_parent"        android:layout_height="wrap_content" /></LinearLayout>

界面图

在MainActivity修改代码

一些初始化操作

    //网址主连接    private String url = "http://10.0.2.2:8080";    private EditText number;    private EditText pwd;    number = (EditText) findViewById(R.id.edit_number);    pwd = (EditText) findViewById(R.id.edit_pwd);

我共使用了两种登录方式,分别是GET和POST这两种提交方式,

GET方式,一般登录不会用这种方式,GET是把数据放在地址上的,很容易就被其他人看到,我这只是测试而已

    //使用GET方法    public void get() {        final String numberStr = number.getText().toString().trim();        final String pwdStr = pwd.getText().toString().trim();        //连接网络要使用线程        new Thread(new Runnable() {            @Override            public void run() {                //GET方法要在路径上写好数据                Request request = new Request.Builder()                        .url(url + "/MyServlet?number=" + numberStr + "&pwd=" + pwdStr)                        .build();                OkHttpClient client = new OkHttpClient.Builder()                        //连接超时                        .connectTimeout(10, TimeUnit.SECONDS)                        //写入超时                        .writeTimeout(20, TimeUnit.SECONDS)                        //读取超时                        .readTimeout(20, TimeUnit.SECONDS)                        .build();                Log.d("MainActivity","GET路径为:"+request.url());                Call call = client.newCall(request);                call.enqueue(new Callback() {                    @Override                    public void onFailure(Call call, IOException e) {                        //失败做的一些处理                    }                    @Override                    public void onResponse(Call call, Response response) throws IOException {                        //获得返回数据                        String res = response.body().string();                        Log.d("MainActivity", "GET方法返回的数据为:" + res);                        parseJSON(res);                    }                });            }        }).start();    }

POST方式,这种方式用处比较多,比如上传文件也是用到POST方式

    //使用POST方法    public void post() {        final String numberStr = number.getText().toString().trim();        final String pwdStr = pwd.getText().toString().trim();        //连接网络要使用线程        new Thread(new Runnable() {            @Override            public void run() {                OkHttpClient client = new OkHttpClient.Builder()                        //连接超时                        .connectTimeout(10, TimeUnit.SECONDS)                        //写入超时                        .writeTimeout(20, TimeUnit.SECONDS)                        //读取超时                        .readTimeout(20, TimeUnit.SECONDS)                        .build();                //打包表单数据                FormBody.Builder formBodyBuild = new FormBody.Builder();                formBodyBuild.add("number", numberStr);                formBodyBuild.add("pwd", pwdStr);                //设置请求头                Request request = new Request.Builder()                        .url(url+"/MyServlet")                        //上传文件的写法                        /*.post(RequestBody.create(MediaType.parse("text/x-markdown; charset=utf-8"),                                new File("/mnt/sdcard/a.png")))*/                        .post(formBodyBuild.build())                        .build();                Log.d("MainActivity","POST路径为:"+request.url());                Call call = client.newCall(request);                request.url();                call.enqueue(new Callback() {                    @Override                    public void onFailure(Call call, IOException e) {                        //失败做的一些处理,比如连接失败                    }                    @Override                    public void onResponse(Call call, Response response) throws IOException {                        //获得返回数据                        String res = response.body().string();                        Log.d("MainActivity", "POST方法返回的数据为:" + res);                        parseJSON(res);                    }                });            }        }).start();    }

 因为返回的数据是json格式,创建一个用于解析json的方法

 

    //解析JSON数据    public void parseJSON(String jsonStr) {        try {            JSONObject jsonObject = new JSONObject(jsonStr);            String resulet = jsonObject.getString("result");            //判断是否成功            if (resulet.equals("success")) {                String fileUrl = jsonObject.getString("file");                final String imageUrl = url + fileUrl;                //操作UI不能在子线程上操作,要在UI线程上操作                runOnUiThread(new Runnable() {                    @Override                    public void run() {                        //登录成功,跳转到另一个Activity                        Intent intent = new Intent(MainActivity.this, Main2Activity.class);                        intent.putExtra("imageUrl", imageUrl);                        startActivity(intent);                        Toast.makeText(getApplicationContext(), "登录成功", Toast.LENGTH_SHORT).show();                    }                });            } else {                //登录失败                runOnUiThread(new Runnable() {                    @Override                    public void run() {                        Toast.makeText(getApplicationContext(), "账号或密码错误", Toast.LENGTH_SHORT).show();                    }                });            }        } catch (JSONException e) {            e.printStackTrace();        }    }

给那两按钮添加点击事件

    public void getRequest(View view) {        get();    }    public void postRequest(View view) {        post();    }

到这里其他就可以进行第一次运行了,因为要联网,还有之后保存图片到SD卡,这都有权限,所以要加上下面的权限

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

可以运行看看了,首先使用GET的提交方式登录

然后是POST提交方式

 

运行没有问题后,接下来是编写登录成功后的功能了

 接收上一个Activity传来的图片的网址

private String url;//获取上一个Activity传来的图片路径Intent intent = getIntent();url = intent.getStringExtra("imageUrl");

一些界面控件的初始化

private ImageView imageView;imageView = (ImageView) findViewById(R.id.imageview);

显示网络图片的操作

    private void showImage(final String ImageUrl) {        //连接网络要使用线程        new Thread(new Runnable() {            @Override            public void run() {                try {                    OkHttpClient client = new OkHttpClient.Builder()                            //使用缓存                            .cache(new Cache(getExternalCacheDir().getAbsoluteFile(), 1024 * 1024 * 2))                            .build();                    Request request = new Request.Builder()                            .url(ImageUrl)                            .build();                    Log.d("Main2Activity","图片路径为:"+request.url());                    Response response = client.newCall(request).execute();                    //获取输入流                    InputStream inputStream = response.body().byteStream();                    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);                    //使用Hander线程修改UI                    Message msg = new Message();                    msg.what = 1;                    msg.obj = bitmap;                    handler.sendMessage(msg);                    inputStream.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }).start();    }

还有一个保存网络图片到本地的SD卡上

    public void saveImage(final String imageUrl) {        //连接网络要使用线程        new Thread(new Runnable() {            @Override            public void run() {                try {                    OkHttpClient client = new OkHttpClient.Builder()                            //使用缓存                            .cache(new Cache(getExternalCacheDir().getAbsoluteFile(), 1024 * 1024 * 2))                            .build();                    Request request = new Request.Builder()                            .url(imageUrl)                            .build();                    Log.d("Main2Activity","图片路径为:"+request.url());                    Response response = client.newCall(request).execute();                    //获取字节数据                    byte[] bytes = response.body().bytes();                    //获取文件名                    String[] urls = url.split("/");                    String filename = urls[urls.length - 1];                    //保存文件                    File file = new File(Environment.getExternalStorageDirectory(), filename);                    FileOutputStream fos = new FileOutputStream(file);                    fos.write(bytes);                    fos.flush();                    fos.close();                    //弹出Toast                    Message msg = new Message();                    msg.what = 2;                    msg.obj = "保存成功";                    handler.sendMessage(msg);                } catch (IOException e) {                    e.printStackTrace();                    Log.e("Main2Activity", "图片保存失败");                    Message msg = new Message();                    msg.what = 2;                    msg.obj = "图片保存失败";                    handler.sendMessage(msg);                }            }        }).start();    }

在上面两种方法中都可以看到我使用了Handle更新UI,下面就是Handle的实现

    private Handler handler = new Handler() {        @Override        public void handleMessage(Message msg) {            switch (msg.what) {                case 1:                    //设置图片                    imageView.setImageBitmap((Bitmap) msg.obj);                    break;                case 2:                    //一些提示                    Toast.makeText(getApplicationContext(), (String) msg.obj, Toast.LENGTH_SHORT).show();                    break;            }        }    };

最后就是把刚才的操作添加到按钮的点击事件上,因为作者是在Android6.0上测试的,而读写SD卡的权限在Android6.0后要动态申请,所以加了申请权限的操作,这样就大功告成了。

效果图

 

项目源代码:http://download.csdn.net/download/qq_33200967/9935716