Android 网络请求登录后更新页面实现 Handler+HTTP请求详解

为了实现登录功能,我们需要一下几步:

1、获取UI数据,并向服务器发送请求

2、等待返回数据,解析

3、将返回数据更新到UI线程中

为了完成以上几步,我根据每步的功能提出自己的解决方法,顺便整理出对应的知识供大家参考。

Handler

众所周知,Android程序运行会开启一个UI线程,也就是主线程,用于处理UI事件。只有在UI线程中才能进行对UI的各种操作,如果在非UI线程中直接对界面元素进行操作,会报错。这是对与获取网络请求并更新UI页面这样的需求来说只能将代码写到UI线程中,这样才能更新UI线程。但是对于这种网络请求或者是耗时的工作,由于执行时间的不可确定性,可能会在执行代码时阻塞。要是将这样的代码写到UI主线程中,就会造成ANR(application not responding,如果UI线程阻塞超过几秒(现在一般是5秒),用户就会看到应用无响应的Dialog)异常,也就是程序无响应,影响客户体验。所以子啊Android 4.0之后,Android就不允许在主线程中访问网络,否则会报NetworkOnMainThreadException异常。这时另一个方法是新开一个子线程,用于网络访问,并将获取的数据发送给主线程。而子线程和UI线程之间进行通信的机制就是Handler。

说起Handler,就不得不提Message、MessageQueue以及Looper。

  • Handler:异步回调机制。作用就是在子线程中发送数据,通过sendMessage()发送数据;在UI线程中接收数据,通过重写handlerMessage方法。如果希望Handler正常工作,在当前线程中要有一个Looper对象
  • Looper:每个线程只能够有一个Looper,管理MessageQueue,不断地从中取出Message分发给对应的Handler处理!
  • MessageQueue:消息队列,先进先出管理Message,在初始化Looper对象时会创建一个与之关联的MessageQueue;
  • Message:Handler接收与处理的消息对象

  通俗一点讲:当我们的子线程想修改Activity中的UI组件时,我们可以新建一个Handler对象,通过这个对象向主线程发送信息;而我们发送的信息会先到主线程的MessageQueue进行等待,由Looper按先入先出顺序取出,再根据message对象的what属性分发给对应的Handler进行处理!

更多关于这四者直接关系,如何调用的可以看这篇博客

反正想要进行网络连接,必须在主线程中使用Handler机制,获取到子线程发来的数据。我们在Android定义一个按钮点击事件,当点击时,向服务器发送请求,并用handler更新UI。代码如下:

 subBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String uname = unameEt.getText().toString().trim();//获取用户名,密码字符数据
                String upwd = upwdEt.getText().toString().trim();
                Handler handler = new Handler() {
                    public void handleMessage(Message msg) {
                        //这里可以进行对UI的操作
                        }
                };
                String url = "http://192.168.0.1:8080/MyDome/jaxrs/userservice/getuser/" + uname + "," + upwd;
                MyHttpClient hc = new MyHttpClient();
                hc.setUrl(url);
                hc.setHandler(handler);
                hc.start(); 
                hc.interrupt();

            }
        });

subBtn是我定义的登录界面的登录按钮,可以看出来点击登录按钮后获取到EditView输入的用户名和密码,并定义了Handler,其中handleMessage(Message msg)方法中的msg就是写完子线程后在子线程中handler的sendMessage(Message msg)所传过来的msg信息,handleMessage方法中就可以对UI线程进行操作了。

之后是我自己定义了一个类,他继承了Thread,可以看到后面有.start()方法。后面是对对象设置两个参数,一个是向服务器发送的请求地址,一个是handler。下面就来看看MyHttpClient类。

HTTP网络请求

Android系统提供一下3种通信接口:

  • 标准Java接口:java.net;
  • Apache接口:org.apache.http;
  • Android网络接口:android.net,http

其中使用最多的是Apache接口,下面就是以这个接口为例

Apache的核心功能是HttpClient,和网络有关的功能几乎都是要用到HttpClient来实现。

HttpClient client = new DefaultHttpClient();

如果想从服务器检索信息,则需要使用HttpGet类的构造器,例如下面的代码:

HttpGet request = new HttpGet(“输入服务器网址”);

然后用HttpClient类的execute()方法中的HttpGet对象来检索HttpResponse对象,例如代码

HttpResponse response = client.execute(request);

更多请看:

HTTP基础与Android之——使用HttpClient和HttpURLConnection

MyHttpClient

public class MyHttpClientUtils extends Thread {
    private String url = "";
    private Handler handler = null;


    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public Handler getHandler() {
        return handler;
    }

    public void setHandler(Handler handler) {
        this.handler = handler;
    }

    @Override
    public void run() {
        HttpGet request = new HttpGet(url);
        HttpResponse response = null;
        Message message = new Message();
        Bundle bundle = new Bundle();
        message.setData(bundle);
        
        ArrayList<Map<String,String>> data = new ArrayList<Map<String, String>>();
        try{
            HttpClient client = new DefaultHttpClient();
            response = client.execute(request);
            if(response.getStatusLine().getStatusCode() == 200){//200服务器返回正常
                String resultStr = EntityUtils.toString(response.getEntity(),"UTF-8");//将获取的数据放到Entity中
                Map<String,String> jsonMap = new HashMap<String,String>();
                JSONObject jsonObject = new JSONObject(resultStr);//
                Iterator<String> keys = jsonObject.keys();//获得key获得对象第一个isRename
                if (keys.hasNext()){
                    String str = jsonObject.getString(keys.next());//获得login后面的数
                    JSONObject temp = new JSONObject(str);//str = {"uid":"6","uname":"a","upwd":"a"}
                    Iterator<String> tempKeys = temp.keys();
                    while(tempKeys.hasNext()){
                         String key = tempKeys.next();
                         jsonMap.put(key,temp.getString(key));
                         }
                        data.add(jsonMap);

                    }
                }
              bundle.putSerializable("res",data);
              handler.sendMessage(message);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
Map<String,String> jsonMap = new HashMap<String,String>();

设置网络超时版本:

@Override
    public void run() {
        //获取地址
        Log.d(TAG,"最大空间:" + Runtime.getRuntime().maxMemory() );
        HttpGet request = new HttpGet(url);
        HttpResponse response = null;
        Message message = new Message();
        Bundle bundle = new Bundle();
        message.setData(bundle);

        Log.d(TAG,"最大空间:" + Runtime.getRuntime().maxMemory() );
        ArrayList<Map<String,String>> data = new ArrayList<Map<String, String>>();
        try{
            //设置网络超时
            int REQUEST_TIMEOUT = 10*1000;//设置请求超时10秒钟
            int SO_TIMEOUT = 10*1000;  //设置等待数据超时时间10秒钟
            BasicHttpParams httpParams = new BasicHttpParams();
            HttpConnectionParams.setConnectionTimeout(httpParams, REQUEST_TIMEOUT);
            HttpConnectionParams.setSoTimeout(httpParams, SO_TIMEOUT);
            HttpClient client = new DefaultHttpClient(httpParams);
            response = client.execute(request);
            if(response.getStatusLine().getStatusCode() == 200){
                String resultStr = EntityUtils.toString(response.getEntity(),"UTF-8");//汉子要转字符集
                System.out.print(resultStr);
                //"{\"isReName\":[{\"state\":\"1\"}]}"
                /*
                * {"reUser":
                * [{"uid":"1","uname":"w","upwd":"w"},
                * {"uid":"2","uname":"1","upwd":"1"},
                * {"uid":"3","uname":"qssss","upwd":"qasd"},
                * {"uid":"4","uname":"qq","upwd":"qq"},
                * {"uid":"5","uname":"e","upwd":"e"},
                * {"uid":"6","uname":"a","upwd":"a"},
                * {"uid":"7","uname":"d","upwd":"d"}]
                * }
                * */
                JSONObject jsonObject = new JSONObject(resultStr);//
                Iterator<String> keys = jsonObject.keys();//获得key获得对象第一个isRename....keys会有很多
                if (keys.hasNext()){//有第一个key
                    String str = jsonObject.getString(keys.next());//坐标移到第一个key上,keys。next()获取key值。获取第一个key的值

                    if(str.indexOf("[") == 0){
                        JSONArray jsonArray = new JSONArray(str);//[{"uid":"6","uname":"a","upwd":"a"},{"uid":"6","uname":"a","upwd":"a"}]
                        for(int i = 0;i < jsonArray.length() ; i++){
                            Map<String,String> jsonMap = new HashMap<String, String>();
                            JSONObject temp = new JSONObject(jsonArray.get(i).toString());//获得values里的key值
                            Iterator<String> tempKeys = temp.keys();
                            while(tempKeys.hasNext()){
                                String key = tempKeys.next();
                                jsonMap.put(key,temp.getString(key));//获得数组里面的values值
                            }
                            data.add(jsonMap);
                        }
                    }else{
                        //{"reUser":{"uid":"6","uname":"a","upwd":"a"}}
                        Map<String,String> jsonMap = new HashMap<String,String>();
                        JSONObject temp = new JSONObject(str);//str = {"uid":"6","uname":"a","upwd":"a"}
                        Iterator<String> tempKeys = temp.keys();
                        while(tempKeys.hasNext()){
                            String key = tempKeys.next();
                            jsonMap.put(key,temp.getString(key));
                        }
                        data.add(jsonMap);
                    }



                }
              // System.out.println("sssss ----" + data.get(0).get("state").toString());
              //  System.out.println(" state------- " + data.get("state").toString());
                bundle.putSerializable("res",data);
                handler.sendMessage(message);
                //result有值
            }
        }catch (Exception ex){
            Map<String,String> info = new HashMap<String, String>();
            info.put("connectInfo","null");
            data.add(info);

            bundle.putSerializable("res",data);
            handler.sendMessage(message);

            Log.d(TAG,"连接超时");
        }
    }

类中定义两个属性一个url一个handler用于获取信息。整个类继承Thread,在run()方法中进行网络访问

Message message = new Message();
Bundle bundle = new Bundle();
message.setData(bundle);

定义Message用于handler的传输,使用Bundle来放置键值对值,使用Message的setData()方法来关联到bundle

String resultStr = EntityUtils.toString(response.getEntity(),"UTF-8");//汉子要转字符集
获取resulStr就是网络Get请求后返回来的值,我写的服务器是返回Json字符串。根据resulStr来解析Json字符串就可以得到返回信息。返回的字符串样式是

{"reUser":{"uid":"1","uname":"w","upwd":"w"}}

JSONObject jsonObject = new JSONObject(resultStr);//将字符串变为json对象
                Iterator<String> keys = jsonObject.keys();//获得这个对象中的所有key,这里只有一个key就是reUser
                if (keys.hasNext()){//是否存在key
                    String str = jsonObject.getString(keys.next());//获得第一个key的值,这里就是{"uid":"1","uname":"w","upwd":"w"}
                    JSONObject temp = new JSONObject(str);//str ={"uid":"1","uname":"w","upwd":"w"}。再将他转为json对象
                  Map<String,String> jsonMap = new HashMap<String,String>();
                 Iterator<String> tempKeys = temp.keys();//获取所有key,这里是uid uname
while(tempKeys.hasNext()){ String key = tempKeys.next(); jsonMap.put(key,temp.getString(key));     } data.add(jsonMap);//将数据放入Bundle中 } }
bundle.putSerializable("res",data);
              handler.sendMessage(message);

最后利用bundle将数据转Serializable序列化,通过handle.sendMessage将数据传到UI线程中

 
在Handler的handleMessage方法中使用 
ArrayList<Map<String, String>> data = (ArrayList<Map<String, String>>) msg.getData().getSerializable("res");
进行msg的解析
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值