android 头像利用okhttp上传到服务器部分----萌新成长之路

来源:互联网 发布:凸优化数学基础 编辑:程序博客网 时间:2024/05/22 02:29

上一篇博客我们成功完成了从照相机拍摄和相册里选择图片并在app中显示出来。我们也完成了初步的裁剪。今天我们来把用户的数据上传到服务器,模拟一个用户在游戏内部修改自己头像,点击确定以后的保存过程。

步骤1:布局以及基础代码

这里我们在上一篇博客的基础上再加一个按钮用来表示用户确定选择当前图片作为头像。

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context="com.example.choosephoto.MainActivity">    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center_horizontal"        android:onClick="choosePicture"        android:text="选择头像" />    <ImageView        android:id="@+id/headPicture"        android:layout_width="match_parent"        android:layout_height="300dp" />    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center_horizontal"        android:onClick="confirm"        android:text="确定" /></LinearLayout>

这里写图片描述

private String url;//上传图片到指定的网址public void confirm(View view){    //点击以后上传用户id和用户图片到服务器} 

步骤2:编写一个okhttp的工具类

由于我们在项目中肯定不止一个地方要上传数据,如果不复用代码的话会大大提高代码量(虽然okhttp相比于HttpConnection已经简便了许多)。

我们新建一个java类叫做OkhttpUtils.java,还要新建一个接口用于处理服务器的返回值。

public interface HttpResponseCallBack {    void response(String response);//处理服务器返回成功    void error(Exception e);//处理异常}
public static void doPost(final String url, final File file, JSONObject jsonObject, final HttpResponseCallBack httpResponseCallBack){//上传操作}

我先讲一下我的设计吧。定义一个doPost方法,里面所做的操作自然就是把我们要穿的数据都传到服务器上去。那么必然需要传进来的参数是:服务器网址url,图片文件file(没有就传null),需要上传的json数据(id之类的信息),最后就是我们自定义的接口。
下面先开始写上传json数据的部分。
那么根据我的研究发现okhttp的post大概流程是这个样子滴(把这个看做是导弹去打目标):

  1. 定义一个okhttpClient。这是无论用什么方式和服务器交互都必须的第一步,相当于导弹的控制台;
  2. 定义一个RequestBody(字面意思是请求体)。大概意思就是我要把一大坨东西扔到服务器上去,RequestBody就是用来放这一大坨东西的容器,相当于导弹的弹药。
  3. 定义一个Request。这里面放的是我要和谁交互(服务器的url),和我要上传的信息(RequestBody),相当于导弹的瞄准系统。
  4. 定义一个Call。消息的发送点(暂时这么理解吧),相当于导弹的基座。同一个导弹可以有不同基座,也可以有不同的控制台
  5. 执行Call。控制台说:“导弹发射!”,然后就成功发出了消息。
    接下来是代码部分:
    //定义一个JSON的MediaType(互联网媒体类型)    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");    //1.定义一个OkhttpClient    private static OkHttpClient client = new OkHttpClient();    public static void doPost(final String url, final File file, JSONObject jsonObject, final HttpResponseCallBack httpResponseCallBack)    {        //建立body,然后设置这个body里面放的数据类型是什么。        RequestBody body = RequestBody.create(JSON,jsonObject.toString());        //建立请求        Request request = new Request.Builder().post(body).url(url).build();        //定义Call        Call call = client.newCall(request);        //执行Call        call.enqueue(new Callback() {            @Override            public void onFailure(Call call, IOException e) {                httpResponseCallBack.error(e);            }            @Override            public void onResponse(Call call, Response response) throws IOException {                httpResponseCallBack.response(response.body().string());            }        });    }

大家记一下写法,当然我这里写的不是很详细。大家可以去看看OkHttp源码或者专门详解OkHttp的博客~
上面的代码完成了Json的上传,那接下来我们在写一个方法专门用来上传图片。

/参数为要上传的网址,本地照片在本地的地址,我们自己定义的接口    public static void doPostPicture(String url, File file,final HttpResponseCallBack httpResponseCallBack) {        //OkHttpClient作为全局静态变量已经定义过了        //2.创建一个请求体        RequestBody body;        //3.创建一个请求体建造器        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);        builder.addFormDataPart("headPicture", "headPicture.jpg", RequestBody.create(MediaType.parse("image/jpg"), file));        body = builder.build();        //3.创建一个请求,利用构建器方式添加url和请求体。        Request request = new Request.Builder().post(body).url(url).build();        //4.定义一个call,利用okhttpclient的newcall方法来创建对象。因为Call是一个接口不能利用构造器实例化。        Call call = client.newCall(request);        //5.这是异步调度方法,上传和接受的工作都在子线程里面运作,如果要使用同步的方法就用call.excute(),此方法返回的就是Response        call.enqueue(new Callback() {            @Override            public void onFailure(Call call, IOException e) {                httpResponseCallBack.error(e);//错误发生时的处理            }            @Override            public void onResponse(Call call, Response response) throws IOException {                httpResponseCallBack.response(response.body().string());//把服务器发回来的数据response解析成string传入方法            }        });    }

相信大家也能看懂,大致上代码还是差不多的就细微的地方有差距(别问我为什么不分析一下为什么要这么写,因为我也不清楚。。。)
然后我们把这两个方法有机结合一下下:

            @Override            public void onResponse(Call call, Response response) throws IOException {                httpResponseCallBack.response(response.body().string());                if (file!=null)//如果有文件需要传输的话                {                    doPostPicture(url, file, new HttpResponseCallBack() {                        @Override                        public void response(String response) {                            //做操作                        }                        @Override                        public void error(Exception e) {                            //做操作                        }                    });                }            }

我们在上面上传json并成功返回之后做个判断,如果需要上传file则再调用doPostPicture上传图片。
之后就是我们在点击按钮以后调用doPost方法:

    public void confirm(View view)    {        //点击以后上传用户id和用户图片到服务器        JSONObject jsonObject = new JSONObject();        try {            jsonObject.put("id","test");            jsonObject.put("phoneNum","111111");        } catch (JSONException e) {            e.printStackTrace();        }        OkhttpUtils.doPost(url, file, jsonObject, new HttpResponseCallBack() {            @Override            public void response(String response) {                Toast.makeText(MainActivity.this,"上传成功",Toast.LENGTH_SHORT).show();            }            @Override            public void error() {                Toast.makeText(MainActivity.this,"上传失败",Toast.LENGTH_SHORT).show();            }        });    }

注意由于要联网所以别忘了加权限

TIPS

1、为什么要写接口?考虑一下这种情况:我们在不同的地方都要向服务器传输不同的数据。在登录的时候要上传手机号和密码,在修改头像的时候要上传用户的游戏id和头像等等。这个的不同我们通过在方法中传入不同的参数解决,而服务器对于每个不同的客户端请求的相应是不同的,我们要解析每个服务器的相应并在客户端里面做出相应的动作(比如登录失败就要提示用户,登录成功就要从登录界面跳转到游戏界面等等)。okhttp自身提供onResponse方法表示服务器相应以后的调用,而我们在里面写的东西却是不一样的。最好的办法就是在我们定义的方法里面传入一个接口,也就是java的回调机制。
2、因为在call.enqueue()方法的回调里面是出于子线程的,所以我们不能在里面修改UI布局,也不能Toast。这个需要注意下。
3、在onResponse回调里面,response参数只能解析一次。也就是说如果你这么写

                String s = response.body().string();                String ss = response.body().string();

是要报异常的。大概意思好像是说这个东西解析一次以后就关掉了不让解析了。
FATAL EXCEPTION: OkHttp Dispatcher
Process: com.example.choosephoto, PID: 9638
java.lang.IllegalStateException: closed……
4、https://github.com/dlovetco/ChoosePhoto github

相关知识:

http://blog.csdn.net/lmj623565791/article/details/47911083 okhttp详解
http://blog.csdn.net/blueheart20/article/details/45174399 Http中的Content-type

7 0
原创粉丝点击