Android网络框架OKhttp3学习笔记

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后要动态申请,所以加了申请权限的操作,这样就大功告成了。

效果图

时间: 2024-10-12 20:10:56

Android网络框架OKhttp3学习笔记的相关文章

Android Mina框架的学习笔记

Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络应用程序提供了非常便利的框架.当前发行的 MINA 版本支持基于 Java NIO 技术的 TCP/UDP 应用程序开发.串口通讯程序(只在最新的预览版中提供),MINA 所支持的功能也在进一步的扩展中.目前正在使用 MINA 的软件包括有:Apache Directory Project.Asyn

Android 网络框架 android-async-http

转载请注明出处:明桑Android 这是Android网络框架系列的最后一篇了~~, 文章主要介绍第三方库 android-async-http的使用,之后作为Android网络框架系列的完结,对在开发中如何学习和使用第三方框架做个总结! 1,Android Asynchronous Http Client简介 android-async-http是封装了HttpClient的顶层实现,它所发起的Request全部运行于不同于UI线程的其它线程中,但它回调的处理逻辑和使用Handler发送mes

Mina框架的学习笔记——Android客户端的实现

Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络应用程序提供了非常便利的框架.当前发行的 MINA 版本支持基于 Java NIO 技术的 TCP/UDP 应用程序开发.串口通讯程序(只在最新的预览版中提供),MINA 所支持的功能也在进一步的扩展中.目前正在使用 MINA 的软件包括有:Apache Directory Project.Asyn

Android(java)学习笔记204:自定义SmartImageView(继承自ImageView,扩展功能为自动获取网络路径图片)

1.有时候Android系统配置的UI控件,不能满足我们的需求,Android开发做到了一定程度,多少都会用到自定义控件,一方面是更加灵活,另一方面在大数据量的情况下自定义控件的效率比写布局文件更高. 2.下面我们是自定义一个SmartImageView继承自ImageView,扩展了ImageView的功能:     步骤: • 新建一个SmartImageView类,让继承自ImageView(放置特定的包下): • 实现SmartImageView类下的构造方法,最好全部实现,这个不容易出

android 网络框架 源码分析

android 网络框架 源码分析 导语: 最近想开发一个协议分析工具,来监控android app 所有的网络操作行为, 由于android 开发分为Java层,和Native层, 对于Native层我们只要对linux下所有网络I/O接口进行拦截即可,对于java 层,笔者对android 网络框架不是很了解,所以这个工具开发之前,笔者需要对android 的网络框架进行一个简单的分析. 分析结论: 1. android 的网络框架都是基于Socket类实现的 2. java 层Socket

Android(java)学习笔记205:网易新闻客户端应用编写逻辑过程

1.我们的项目需求是编写一个新闻RSS浏览器,RSS(Really Simple Syndication)是一种描述和同步网站内容的格式,是使用最广泛的XML应用.RSS目前广泛用于网上新闻频道,blog和wiki,主要的版本有0.91, 1.0, 2.0.使用RSS订阅能更快地获取信息,网站提供RSS输出,有利于让用户获取网站内容的最新更新.网络用户可以在客户端借助于支持RSS的聚合工具软件,在不打开网站内容页面的情况下阅读支持RSS输出的网站内容. 例如如下的网易RSS订阅: 2.由于我们这

Android(java)学习笔记233: 远程服务的应用场景(移动支付案例)

一. 移动支付:       用户需要在移动终端提交账号.密码以及金额等数据 到 远端服务器.然后远端服务器匹配这些信息,进行逻辑判断,进而完成交易,返回交易成功或失败的信息给移动终端.用户提交账号.密码以及金额等数据都是比较敏感的数据,这些数据不能让外界获取.       阿里等等支付宝平台把支付的逻辑封装起来,只给我们提供一个方法去调用,这样提高了安全性.当我们用户提交账号.密码以及金额等数据,点击"支付"的时候,支付宝平台已经调用方法加密数据(这个支付逻辑是远程服务,为了安全,防

ym—— Android网络框架Volley(体验篇)

<a target=_blank href="https://android.googlesource.com/platform/frameworks/volley" style="font-family: Arial, Helvetica, sans-serif; box-sizing: border-box; background-image: initial; background-attachment: initial; background-color: rg

Android网络框架Volley

Volley是Google I/O 2013推出的网络通信库,在volley推出之前我们一般会选择比较成熟的第三方网络通信库,如: android-async-http retrofit okhttp 他们各有优劣,之前个人则比较喜欢用Android-async-http, 如今Google推出了官方的针对Android平台上的网络通信库,能使网络通信更快,更简单,更健壮,Volley在提供了高性能网络通讯功能的同时,对网络图片加载也提供了良好的支持,完全可以满足简单REST客户端的需求, 我们