WebView简单体验——可内嵌在应用程序的浏览器
WebView是一个封装了网络请求,数据解析的这么一个控件,可作为程序的内置浏览器使用
注意声明网络访问权限:android.permission.INTERNET
1 <WebView
2 android:id="@+id/webview"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent" />
1 protected void onCreate(Bundle savedInstanceState) {
2 super.onCreate(savedInstanceState);
3 setContentView(R.layout.activity_main);
4 WebView webView = (WebView) findViewById(R.id.webview);
5 // step1 设置支持js
6 webView.getSettings().setJavaScriptEnabled(true);
7 // step2 设置客户端本页根据传入的url打开网页,不需要调用系统浏览器
8 webView.setWebViewClient(new WebViewClient() {
9
10 @Override
11 public boolean shouldOverrideUrlLoading(WebView view, String url) {
12 // 根据url访问网络
13 view.loadUrl(url);
14 // 设置成true,表示跳转网页时在本页打开
15 return true;
16 }
17
18 });
19 // 默认访问百度,测试简写不可用
20 webView.loadUrl("http://www.baidu.com");
21 // 注意访问网络需要权限
22 }
http网络请求
方式一:HttpURLConnection
网络请求是比较耗时的操作,如果直接在主线程中使用的话,可能会出现ANR问题,所以通常是要开启一个子线程进行操作的
下面是常见写法,但是存在着一些弊端=》通常应用程序里面网络请求不止一个,所以应当封装成一个工具类,当需要请求的时候,直接用工具类传入地址进行访问
注:用模拟器调试的话,可以开启本地apache服务器,请求 10.0.2.2/xxx.xml
1 private void sendRequestWithHttpURLConnection() {
2 // 发送网络请求,必须开启子线程,否则可能阻塞主线程,ANR
3 new Thread(new Runnable() {
4
5 @Override
6 public void run() {
7 // 注意别写成HttpsURLConnection
8 HttpURLConnection connection = null;
9 try {
10 // 1.得到HttpURLConnection实例——通过url的open..获得
11 URL url = new URL("http://www.ytslf.com/get_data.xml");
12 connection = (HttpURLConnection) url.openConnection();
13
14 // 2.设置请求方式以及请求延时
15 connection.setRequestMethod("GET");// GET表示需要从服务器得到数据,POST表示需要向服务器提交数据
16 connection.setConnectTimeout(8000);
17 connection.setReadTimeout(8000);
18
19 // 3.获取InputStream流,读取服务器返回的数据
20 InputStream in = connection.getInputStream();
21 BufferedReader bufr = new BufferedReader(
22 new InputStreamReader(in));
23 String line = null;
24 StringBuilder sb = new StringBuilder();
25 while ((line = bufr.readLine()) != null) {
26 sb.append(line);
27 }
28 // 4.将获取到的数据交给Handler处理
29 Message msg = new Message();
30 msg.what = SHOW_RESPONSE;
31 msg.obj = sb.toString(); // 可以直接传入StringBuilder,但为了统一,传String
32 handler.sendMessage(msg);
33 } catch (IOException e) {
34 e.printStackTrace();
35 } finally {
36 if (connection != null) {
37 // 关闭连接
38 connection.disconnect();
39 }
40 }
41
42 }
43 }).start();
44 }
方式二:HttpClient
HttpClient算是HttpURLConnection的升级版把
1 private void sendRequestWithHttpClient() {
2 new Thread(new Runnable() {
3
4 @Override
5 public void run() {
6 try {
7 // 1.得到HttpClient实例
8 HttpClient httpClient = new DefaultHttpClient();
9 // 2.发送一个GET请求
10 // HttpGet httpGet = new HttpGet("http://www.ytslf.com/get_data.xml");
11 HttpGet httpGet = new HttpGet("http://www.ytslf.com/get_data.json");
12 // 通过execute方法执行请求,可以得到服务器反馈的数据,都封装在HttpResponse对象中
13 HttpResponse httpResponse = httpClient.execute(httpGet);
14
15 /*
16 * 发送Post请求较GET复杂,需要提交参数
17 * 1.新建一个HttpPost对象
18 * HttpPost httpPost = new HttpPost("http://www.baidu.com");
19 * 2.通过NameValuePair集合存放需要提交的参数
20 * List<NameValuePair> params =
21 * new ArrayList<NameValuePair>();
22 * params.add(newBasicNameValuePair("username", "admin"));
23 * params.add(newBasicNameValuePair("password", "123456"));
24 * UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "utf-8");
25 * httpPost.setEntity(entity);
26 * // 之后就和GET一样的操作
27 * httpClient.execute(httpPost);
28 */
29 // 3.接下来就是要得到服务器返回的数据了
30 if (httpResponse.getStatusLine().getStatusCode() == 200) {
31 // 如果返回的状态码为200,则表示请求和响应都成功了
32 HttpEntity httpEntity = httpResponse.getEntity();
33 String response = EntityUtils.toString(httpEntity,
34 "utf-8");
35 // /*请求测试
36 // 将数据发送到Message队列中
37 Message msg = new Message();
38 msg.what = SHOW_RESPONSE;
39 msg.obj = response;
40 handler.sendMessage(msg);
41 // */
42 // 解析测试——Pull方式
43 // Log.d("test", "response ok");
44 // parseXMLWithPull(response);
45 // Log.d("test", "parse over");
46
47
48 }
49
50 } catch (Exception e) {
51 e.printStackTrace();
52 }
53 }
54 }).start();
55 }
XML解析
<apps>
<app>
1</id>
Google Maps</name>
1.0</version>
</app>
<app>
2</id>
Chrome</name>
2.1</version>
</app>
<app>
3</id>
Google Play</name>
2.3</version>
</app>
</apps>
方式一:Pull解析
1 private void parseXMLWithPull(String xmdData){
2 try {
3 // 1.获取XML的PULL解析工厂实例
4 XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
5 // 2.通过工厂获取XML解析器实例
6 XmlPullParser xmlPullParser = factory.newPullParser();
7 // 3.XML解析器设置要解析的XML数据
8 xmlPullParser.setInput(new StringReader(xmdData));
9 // go go go!
10 int eventType = xmlPullParser.getEventType();
11 String id = "";
12 String name = "";
13 String version = "";
14
15 // 开始解析
16 while(eventType != XmlPullParser.END_DOCUMENT){
17 String nodeName = xmlPullParser.getName();
18 switch (eventType) {
19 // 开始解析某个节点
20 case XmlPullParser.START_TAG:
21 if("id".equals(nodeName)){
22 id = xmlPullParser.nextText();
23 }
24 else if("name".equals(nodeName)){
25 name = xmlPullParser.nextText();
26 }
27 else if ("version".equals(nodeName)) {
28 version = xmlPullParser.nextText();
29 }
30 break;
31
32 // 完成解析某个节点
33 case XmlPullParser.END_TAG:
34 if("app".equals(nodeName)){
35 Log.d("test", "id:"+id);
36 Log.d("test", "name:"+name);
37 Log.d("test", "version:"+version);
38 responseText.append(id+"::"+name+"::"+version+"\n");
39 }
40 break;
41
42 default:
43 break;
44 }
45 eventType = xmlPullParser.next();// 解析下一个
46 }
47
48
49 } catch (Exception e) {
50 e.printStackTrace();
51 }
52 }
方式二:SAX解析
1 // SAX解析XML
2 private void parseXMLWithSAX(String xmlData){
3 try {
4 SAXParserFactory factory = SAXParserFactory.newInstance();
5 XMLReader xmlReader = factory.newSAXParser().getXMLReader();
6 // 创建自定义的Handler实例
7 ContentHandler handler = new ContentHandler();
8 // 将实例设置到XMLReader中
9 xmlReader.setContentHandler(handler);
10 // 开始解析
11 xmlReader.parse(new InputSource(new StringReader(xmlData)));
12 } catch (Exception e) {
13 e.printStackTrace();
14 }
15 }
1 package com.example.networktest;
2
3 import org.xml.sax.Attributes;
4 import org.xml.sax.SAXException;
5 import org.xml.sax.helpers.DefaultHandler;
6
7 import android.util.Log;
8
9 public class ContentHandler extends DefaultHandler {
10
11 private String nodeName;
12 private StringBuilder id;
13 private StringBuilder name;
14 private StringBuilder version;
15
16 /**
17 * 开始解析xml时调用
18 */
19 @Override
20 public void startDocument() throws SAXException {
21 id = new StringBuilder();
22 name = new StringBuilder();
23 version = new StringBuilder();
24 }
25
26 /**
27 * 开始解析某个节点的时候调用
28 */
29 @Override
30 public void startElement(String uri, String localName, String qName,
31 Attributes attributes) throws SAXException {
32 // 记录当前节点的名字
33 nodeName = localName;
34 }
35
36 /**
37 * 具体解析内容时调用
38 */
39 @Override
40 public void characters(char[] ch, int start, int length)
41 throws SAXException {
42 // TODO Auto-generated method stub
43 if ("id".equals(nodeName)) {
44 id.append(ch, start, length);
45 } else if ("name".equals(nodeName)) {
46 name.append(ch, start, length);
47 } else if ("version".equals(nodeName)) {
48 version.append(ch, start, length);
49 }
50 }
51
52 /**
53 * 解析完某个节点的时候调用
54 */
55 @Override
56 public void endElement(String uri, String localName, String qName)
57 throws SAXException {
58 if("app".equals(localName)){
59 // StringBuilder读取到的内容可能会有多余的空格或换行符等,通过String的trim()方法去掉
60 Log.d("test", "id:"+id.toString().trim());
61 Log.d("test", "name:"+name.toString().trim());
62 Log.d("test", "version:"+version.toString().trim());
63
64 // 清空StringBuilder
65 id.setLength(0);
66 name.setLength(0);
67 version.setLength(0);
68 }
69 }
70
71 /**
72 * xml全部解析完成时调用
73 */
74 @Override
75 public void endDocument() throws SAXException {
76 }
77
78 }
ContentHandler
JSON解析
json格式如:[{"id":"5","name":"hh","version":"2.1"},{……}]
方式一:JSONObject解析
1 // JSONObject解析json
2 private void parseJSONWithJSONObject(String jsonData){
3 try {
4 JSONArray jsonArray = new JSONArray(jsonData);
5 for(int i=0;i<jsonArray.length();i++){
6 JSONObject jsonObject = jsonArray.getJSONObject(i);
7 String id = jsonObject.getString("id");
8 String name = jsonObject.getString("name");
9 String version = jsonObject.getString("version");
10 Log.d("test", "id:"+id);
11 Log.d("test", "name:"+name);
12 Log.d("test", "version:"+version);
13 responseText.append(id+"::"+name+"::"+version+"\n");
14 }
15 } catch (Exception e) {
16 e.printStackTrace();
17 }
18 }
方式二:GSON解析
利用GSON解析,需要用到GSON的jar包,将jar包拷贝至项目的libs文件夹即可
利用GSON,可以将json数据直接解析成一个对象,利用该对象就能的到相应的数据,这一点是极好的
例如:要解析{"name":"Tom","age":"20"}
可以定义一个具有name和age字段的Person类,解析如下
Gson gson = new Gson();
Person person = gson.fromJson(jsonData,Person.class);
TypeToken,将期望解析成的数据类型传入到fromJson的参数当中
List<Person> people = gson.fromJson(jsonData,new TypeToken<List<Person>>(){}.getType());
解析:
[{"id":"5","version":"5.5","name":"Angry Birds"},
{"id":"6","version":"7.0","name":"Clash of Clans"},
{"id":"7","version":"3.5","name":"Hey Day"}]
1 package com.example.networktest;
2
3 public class App {
4 private String id;
5 private String name;
6 private String version;
7
8 public String getId() {
9 return id;
10 }
11
12 public void setId(String id) {
13 this.id = id;
14 }
15
16 public String getName() {
17 return name;
18 }
19
20 public void setName(String name) {
21 this.name = name;
22 }
23
24 public String getVersion() {
25 return version;
26 }
27
28 public void setVersion(String version) {
29 this.version = version;
30 }
31
32 }
App.java
1 // GSON第三方jar包解析json
2 private void parseJSONWithGSON(String jsonData){
3 try {
4 Gson gson = new Gson();
5 List<App> appList = gson.fromJson(jsonData, new TypeToken<List<App>>() {}.getType());
6 for(App app : appList){
7 String id = app.getId();
8 String name = app.getName();
9 String version = app.getVersion();
10 Log.d("test", "id:"+id);
11 Log.d("test", "name:"+name);
12 Log.d("test", "version:"+version);
13 // responseText.append(id+"::"+name+"::"+version+"\n");
14 }
15 } catch (Exception e) {
16 e.printStackTrace();
17 }
18 }
Http请求的最佳写法:封装为工具类+利用Java回调监听机制
1.封装,定义一个HttpUtil工具类,将请求的代码封装成静态方法,且需要传入网络地址作为参数
1 public class HttpUtil {
2 public static String sendHttpRequest(String address) {
3 HttpURLConnection connection = null;
4 try {
5 return null;
6 } catch (Exception e) {
7 // TODO: handle exception
8 return null;
9 } finally {
10 if (connection != null) {
11 connection.disconnect();
12 }
13 }
14 }
15 }
细节暂时不写……
这样封装了之后,就可以愉快的调用了
String response = HttpUtil.sendHttpRequest("http://www.baidu.com");
但是仍然存在问题:
1.没有开启线程,则仍然默认是在主线程中执行网络请求,可能导致主线程阻塞
2.如果开启线程,如何能够让子线程执行完之后返回数据?这确实是一个问题!!!
解决方法:利用Java的回调机制
回调机制概述
最佳写法
1.根据需求,定义公用接口HttpCallbackListener
1 public interface HttpCallbackListener {
2 public abstract void onFinish(String response);
3 public abstract void onError(Exception e);
4 }
2.在工具类中转入这个接口参数,在得到需要异步处理的结果后,执行接口中的方法,从而实现数据返回
1 import java.io.BufferedReader;
2 import java.io.InputStream;
3 import java.io.InputStreamReader;
4 import java.net.HttpURLConnection;
5 import java.net.URL;
6
7
8 public class HttpUtil {
9 public static void sendHttpRequest(final String address , final HttpCallbackListener listener) {
10 new Thread(new Runnable() {
11
12 @Override
13 public void run() {
14 HttpURLConnection connection = null;
15 try {
16 // 获取实例
17 URL url = new URL(address);
18 connection = (HttpURLConnection) url.openConnection();
19
20 // 设置访问方式和网络延迟
21 connection.setRequestMethod("GET");
22 connection.setConnectTimeout(8000);
23 connection.setReadTimeout(8000);
24
25 // 设置是否URLConnection是否允许输入输出
26 connection.setDoInput(true);
27 connection.setDoOutput(true);
28
29 // 获取服务器输入流
30 InputStream in = connection.getInputStream();
31
32 // 疯狂的读
33 StringBuilder response = new StringBuilder();
34 BufferedReader bufr = new BufferedReader(new InputStreamReader(in));
35 String line = null;
36 while((line = bufr.readLine())!=null){
37 response.append(line);
38 }
39 // 利用回调,异步返回数据
40 if(listener!=null){
41 // 回调onFinish
42 listener.onFinish(response.toString());
43 }
44
45 } catch (Exception e) {
46 if(listener!=null){
47 // 回调onError
48 listener.onError(e);
49 }
50 } finally {
51 if (connection != null) {
52 connection.disconnect();
53 }
54 }
55 }
56 }).start();
57 }
58 }
3.使用下这个工具类~~
1 String address = "http://www.ytslf.com/get_data.json";
2 HttpUtil.sendHttpRequest(address, new HttpCallbackListener() {
3
4 @Override
5 public void onFinish(String response) {
6 // 根据放回的数据,执行具体的逻辑处理,这里是交给handler,然后让handler解析json
7 Message msg = new Message();
8 msg.what = SHOW_RESPONSE;
9 msg.obj = response;
10 handler.sendMessage(msg);
11 }
12
13 @Override
14 public void onError(Exception e) {
15 // 异常处理,这里就不写了
16
17 }
18 });