Android实现网络访问

开发工具:Andorid Studio 1.3
运行环境:Android 4.4 KitKat

工程内容

1) 熟练使用HttpURLConnection访问WebService
2) 熟练使用多线程以及Handler更新UI
3) 熟练使用XmlPullParser解析xml文档数据

代码实现

当用户点击查询按钮的时候,用正则表达式匹配是否是手机号码,若是则调用查询函数,否则用Toast提示用户检查输入

((Button)this.findViewById(R.id.btnSearch)).setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View view) {        if (edtPhoneNumber.getText().toString().matches("^[1-9]\\d{10}$")) {            edtContent.setText("Querying the data");            sendRequestWithHttpURLConnection();        } else {            edtContent.setText("");            Toast.makeText(MainActivity.this, "Please correct the phone number", Toast.LENGTH_SHORT).show();        }    }});

用户输入正确的时候,新开一个线程Thread在后台使用HttpURLConnection建立连接,设置请求方式是POST,设置连接超时和读数据超时为20s。如若超时捕获超时异常,更新UI显示为超时。然后往Http发送请求,给予手机号码,等待回复。接着从Http中读回返回的结果到一个String中。读回来的数据是Xml的字符串内容,需要用XmlPullParserFactory解析xml得到想要的内容。接着把这个得到的内容写入一个Message发出去让主线程的Handler捕获消息。良好习惯是,Http的connection要记得关闭,并且要让线程启动。

private void sendRequestWithHttpURLConnection() {    Thread workThread = new Thread(new Runnable() {        @Override        public void run() {            HttpURLConnection connection = null;            try {                // Create a connection use url                //connection = (HttpURLConnection)((new URL(url.toString()).openConnection()));                connection = (HttpURLConnection)((new URL(getResources().getString(R.string.webService)).openConnection()));                Log.d("myDebug", "successfully open connection");                // Set method                connection.setRequestMethod("POST");                connection.setConnectTimeout(20000);                connection.setReadTimeout(20000);                Log.d("myDebug", "successfully set parameter");                // Write into outputStream                DataOutputStream out = new DataOutputStream(connection.getOutputStream());                // use post method to post our data                out.writeBytes("mobileCode=" + edtPhoneNumber.getText().toString() + "&userID=");                Log.d("myDebug", "successfully write bytes");                // get response data                InputStream in = null;                if (connection.getResponseCode() == 200) {                    in = connection.getInputStream();                } else {                    in = connection.getErrorStream();                }                BufferedReader reader = new BufferedReader(new InputStreamReader(in));                StringBuilder response = new StringBuilder();                String line;                while ((line = reader.readLine()) != null) {                    response.append(line);                }                Log.d("myDebug", "successfully get respone");                Message message = new Message();                message.what = UPDATE_CONTENT;                message.obj = parseXMLWithPull(response.toString());                handler.sendMessage(message);                Log.d("myDebug", "successfully send message");            } catch (java.net.SocketTimeoutException e) {                Message message = new Message();                message.what = TIME_OUT;                handler.sendMessage(message);                e.printStackTrace();                Log.d("myDebug", "Timeout to get the data");            } catch (Exception e) {                e.printStackTrace();                Log.d("myDebug", "Can't not connect to the service");            } finally {                if (connection != null) {                    connection.disconnect();                }            }        }    });    workThread.start();}private String parseXMLWithPull(String xml) {    String str = "";    try {        // use pull to parse xml        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();        XmlPullParser parser = factory.newPullParser();        parser.setInput(new StringReader(xml));        int eventType = parser.getEventType();        while (eventType != XmlPullParser.END_DOCUMENT) {            switch (eventType) {                case XmlPullParser.START_TAG:                    if ("string".equals(parser.getName())) {                        str = parser.nextText();                    }                    break;                case XmlPullParser.END_TAG:                    break;                default:                    break;            }            eventType = parser.next();        }    } catch (Exception e) {        e.printStackTrace();        Log.d("myDebug", "can not parse the xml");    }    return str;}

主线程中需要捕获消息并更新UI,只捕获自己的消息,其余消息交给父类原本的处理

private static final int UPDATE_CONTENT = 0;private static final int TIME_OUT = 1;private Handler handler = new Handler() {    @Override    public void handleMessage(Message message) {        switch (message.what) {            case UPDATE_CONTENT:                edtContent.setText(message.obj.toString());                break;            case TIME_OUT:                edtContent.setText("Time out for getting the data");                break;            default:                super.handleMessage(message);                break;        }    }};

最后需要给程序赋予上网权限和检测网络权限即可

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

效果图

初始化界面->输入错误或不完整手机号码->输入正确并查询->查询结果


一些总结

这个实验中最大的问题就在于免费的东西有使用次数限制,根据网站的说法是24小时内容不超过100次。
然后跟踪Http的进度使用Log方法来调试程序比较快。
对于有些超时的情况,我选择了捕获这个超时异常来更新UI,否则子线程超时后什么内容也没有显示不太符合正常情况。

实际上,在http请求中,直接使用主进程请求数据也是没问题的,为什么android非要使用子线程进行http请求呢?
答:Http请求并不能即时出结果,需要有时间等待,如果在主线程请求数据,那么请求的时候整个程序就会停留在请求的状态,界面卡住不动,因此使用子线程来做这件事比较合适。

为什么不在子线程中直接修改UI,而是需要通过Handler来实现消息的传递,如果直接修改UI会出现什么问题?
答:如果多个子线程同时修改一个UI,那个程序会出现未知的错误。因此每个子线程发送各自的消息,让主线程在消息队列中按到达顺序依次处理消息,是最好的办法。

工程下载

传送门:下载

更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. Volley二次封装,实现网络请求缓存
  3. 关于Android(安卓)webview 的cookie同步的坑
  4. Retrofit 2.0 超能实践,完美支持Https传输
  5. Android(安卓)性能优化、内存优化
  6. Android性能分析和优化之traces.txt(ANR分析)
  7. android之Service(2)IntentService
  8. Android(安卓)线程以及提示消息框
  9. 下载google play apk的方法

随机推荐

  1. android之Task和Back Stack(回退栈)
  2. android获取web服务器端session并验证登
  3. Android(安卓)如何优雅的hook私有方法
  4. Android系统显示原理
  5. Activity 启动模式和 taskAffinity 属性
  6. android试手——通讯录(附源码)
  7. Android(OPhone) 学习笔记 - 记事本实例
  8. Android(安卓)项目实践(五)——基础类和工
  9. Xamarin android 使用RecyclerView结合Sw
  10. Android实现手机游戏隐藏虚拟按键