7、Android---网络技术
玩手机不能上网是单机的时代
而且现在的流量也出了无限使用
几乎网络离不开人们的日常生活
7.1、WebView的用法
遇到一些特殊的请求
在程序中展示一些网页
加载和显示网页都是浏览器的任务
在不打开浏览器的情况下先写一个浏览器
在Android中使用WebView控件即可
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <WebView android:id="@+id/web_view" android:layout_width="match_parent" android:layout_height="match_parent"></WebView> </LinearLayout>
在MianActivity中:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); WebView webView = (WebView) findViewById(R.id.web_view); webView.getSettings().setJavaScriptEnabled(true); webView.setWebViewClient(new WebViewClient()); webView.loadUrl("https://www.baidu.com/"); }
使用getSettings()方法可以设置浏览器的属性
此时使用setJavaScriptEnabled()属性
使用setWebViewClient()方法设置当从一个页面跳转到另一个页面希望目标网页依然在当前的的WebView中i西安市
传入一个WebViewClient的实例
使用loadUrl()方法传入网址
同时还需要进行全县的声明:
此时运行:
此时的程序已经具有一个简易的浏览器功能
7.2、HTTP协议访问网络
对于HTTP协议:
工作原理:客户端向网络端发送一条HTTP请求
服务器端接收到请求之后返回一些数据给浏览器
然后客户端对这些数据进行解析和恶处理
WebView已经在后他做好了发送HTTP请求、接收服务的相应、解析返回数据、以及最终显示页面这几个工作
手动发送HTTP请求方式深入了解这一实现
7.2.1、使用HttpURLConnection
在Android上发送HTTP的请求一般有两种方式:
1、HttpURLConnection
2、HttpClient
由于后者存在的API数量过多
Android团队也不建议使用这种方式
在Android6.0系统中,已经将其完全移除
学习使用HttpURLConnection:
首先:获取到HttpURLConnection的实例,一般只需要new 一个URL对象
并传入目标的网络地址
然后再调用openConnection()方法即可:
URL url = new URL("http://www.baidu.com");
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
在得到了HttpURLConnection的实例之后,可以设置HTTP的请求所有方法
常见的方法主要用:GRT、POST
GET:表示希望从服务器洪获取数据
POST:表示提交数据给服务器
写法:conn.serRequestMethod("GET")
接下来就是自由定制:设置超时连接 、读取数据超时的秒数、以及服务器西药得到的一些消息头等
conn.setConnectTimeout(1000)
conn.setReadTimeout(3000)
之后再调用getInputStream()方法就可以获得服务器返回的数据流
InputStream in = conn.getInputStream()
最后可以使用disconnect()方法将这恶HTTP连接关闭
conn.disconnect()
事件测试:
<Button android:id="@+id/send_request" android:text="send" android:layout_width="match_parent" android:layout_height="wrap_content" /> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/response_text" android:layout_width="match_parent" android:layout_height="wrap_content" /> </ScrollView>
<Scrollview>标签是再显示内容较多的情况下将屏幕外面的内容使用滚轮进行显示
public class MainActivity extends AppCompatActivity { TextView response_text; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button send_request = (Button) findViewById(R.id.send_request); response_text = (TextView) findViewById(R.id.response_text); send_request.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sendRequest(); } }); } private void sendRequest(){ //开启线程发起网路请求 new Thread(new Runnable() { @Override public void run() { HttpURLConnection connection = null; BufferedReader reader = null; try { URL url = new URL("https://www.baidu.com"); connection= (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(5000); connection.setReadTimeout(5000); InputStream in = connection.getInputStream(); //获取输入流进行读取 reader = new BufferedReader(new InputStreamReader(in)); StringBuilder response = new StringBuilder(); String line; while ((line = reader.readLine()) != null){ response.append(line); } showResponse(response.toString()); }catch (Exception e){ e.printStackTrace(); }finally { if (reader != null){ try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } if (connection != null){ connection.disconnect(); } } } }).start(); } public void showResponse(final String response){ Log.d("wwww", "showResponse: "); runOnUiThread(new Runnable() { @Override public void run() { response_text.setText(response); } }); } }
这里还是要注册权限的:
点击按钮之后:
服务器返回的是HTML代码
只是通常情况下浏览器会将这些代码解析成网页
如果使用POST进行提交数据
并在输入流之前把要提交的数据写出即可
数据以键值对的形式讯在
只需要再上述中进行修改:
URL url = new URL("https://www.baidu.com"); connection= (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); DataOutputStream date = new DataOutputStream(connection.getOutputStream()); date.writeBytes("username=Mr&pwd=123455"); connection.setConnectTimeout(5000); connection.setReadTimeout(5000); InputStream in = connection.getInputStream();
7.2.2、使用OkHttp
有许多的通信库可以代替原生的HttpURLConnection
使用OkHttp是做的很出色的一个
是由Square公司开发的
再开源事业上贡献显著
除了OkHttp之后还有Picasso、Retrofit等
OkHttp不仅再接口上封装做的简易使用
连底层也是自成一派
现在已经成为很多人的首选网络通信库
首先需要引入:
会自动下载两个库:
1、OkHttp
2、Okio
后者是前者的通信基础
实现:
GET
首先创建一盒OkHttpClient实例
OkHttpClient client = new OkHttpClient();
接下来要想发送一条HTTP请求,就需要创建一盒request对象
Request request = new Request.Builder().build();
可以在最终的build()方法之前连缀很多其他的方法
Request.Builder().url("xxxxx")
.build();
之后调用OkHttpClient的newCall()方法创建一个Call对象
并且调用execute()方法来发送请求并且接收服务器的返回数据
Response response = client.newCall(request).execute();
Response对象就是服务器返回的数据
可以使用起得到返回的具体内容
String responseDate = response.body().string();
如果发送POST请求:
需要构建出一个RequestBody对象存放带提交的数据
然后再Request.Builder中调用post()方法:并且传入RequestBody
然后就是和GET请求一样调用execute()方法发送请求
public class MainActivity extends AppCompatActivity { TextView response_text; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // WebView webView = (WebView) findViewById(R.id.web_view); // webView.getSettings().setJavaScriptEnabled(true); // webView.setWebViewClient(new WebViewClient()); // webView.loadUrl("https://www.baidu.com/"); Button send_request = (Button) findViewById(R.id.send_request); response_text = (TextView) findViewById(R.id.response_text); send_request.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SendOkHttp(); } }); } //OkHttpClient方法 private void SendOkHttp(){ new Thread(new Runnable() { @Override public void run() { try { OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("https://www.baidu.com").build(); Response response = client.newCall(request).execute(); String responseData = response.body().string(); showResponse(responseData); } catch (IOException e) { e.printStackTrace(); } } }).start(); }
public void showResponse(final String response){
Log.d("wwww", "showResponse: ");
runOnUiThread(new Runnable() {
@Override
public void run() {
response_text.setText(response);
}
});
}
}
此时测试的是GET
7.3、解析XML格式数据
正常情况下
每个需要访问网络的应用程序都会有一个自己的服务器
可以向服务器提交数据
也可以向服务器上获取数据
这些数据再网络上传输以什么格式进行传输?
1、XML
2、JSON
从哪能获取获取一段XML格式的数据?
可以搭建一个最简单的WEB服务器用来提供一段XML文本
然后在程序中访问这个服务器
再对得到的XML数据进行解析
使用xampp中的apache服务器进行测试:
新建data.xml文件
在服务器上进行访问:
此时的准别工作已经完成
7.3.1、Pull解析方式
解析xml格式的数据有很多方式
1、Pill解析
2、SAX解析
....
继承上述的实验:
public class MainActivity extends AppCompatActivity { TextView response_text; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // WebView webView = (WebView) findViewById(R.id.web_view); // webView.getSettings().setJavaScriptEnabled(true); // webView.setWebViewClient(new WebViewClient()); // webView.loadUrl("https://www.baidu.com/"); Button send_request = (Button) findViewById(R.id.send_request); response_text = (TextView) findViewById(R.id.response_text); send_request.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SendOkHttp(); } }); } //OkHttpClient方法 private void SendOkHttp(){ new Thread(new Runnable() { @Override public void run() { try { OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("http://192.168.41.xxx/android/data.xml").build(); Response response = client.newCall(request).execute(); String responseData = response.body().string(); //showResponse(responseData); parsrXnmPull(responseData); } catch (IOException e) { e.printStackTrace(); } } }).start(); } private void parsrXnmPull(String xmlDate){ try{ XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser xmlPullParser = factory.newPullParser(); xmlPullParser.setInput(new StringReader(xmlDate)); int eventType = xmlPullParser.getEventType(); String id=""; String name = ""; String version = ""; while (eventType != XmlPullParser.END_DOCUMENT){ String nodeName = xmlPullParser.getName(); switch (eventType){ case XmlPullParser.START_TAG:{ if ("id".equals(nodeName)){ id = xmlPullParser.nextText(); }else if ("name".equals(nodeName)){ name = xmlPullParser.nextText(); }else if ("version".equals(nodeName)){ version = xmlPullParser.nextText(); } break; } case XmlPullParser.END_TAG:{ if ("app".equals(nodeName)){ Log.d("id:", id); Log.d("name:", name); Log.d("version:", version); } break; } default: break; } eventType=xmlPullParser.next(); } }catch (Exception e){ e.printStackTrace(); } }
public void showResponse(final String response){
Log.d("wwww", "showResponse: ");
runOnUiThread(new Runnable() {
@Override
public void run() {
response_text.setText(response);
}
});
Log.d("aaa", response);
}
}
点击事件触发:
将Http请求地址改成服务器的地址即可
首先获取一个XmlPullParserFactory的实例
借助这个实例得到XmlPullParser对象
然后调用XmlPullParser的setInput()方法将服务器返回的xml数据设置进去开始解析
解析过程:
通过getEventType()方法可以得到当前的解析事件
然后再while中进行不断的解析
当前的解析事件不等于XmlPullParser.END_DOCUMENT,说明解析工作还未完成,调用next()方法获得下一个解析事件
再while事件中:
发现节点名等于id、name、version,就调用nextText()方法获取节点的具体内容
没解析玩一个app节点就进行打印测试
7.3.2、SAX解析方式
继承DefaultHandler类,并且重写5个方法
public class ContentHandler extends DefaultHandler { private String nodeName; private StringBuilder id; private StringBuilder name; private StringBuilder version; @Override public void startDocument() throws SAXException { id = new StringBuilder(); name = new StringBuilder(); version = new StringBuilder(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { nodeName = localName; } @Override public void characters(char[] ch, int start, int length) throws SAXException { if ("id".equals(nodeName)){ id.append(ch,start,length); }else if ("name".equals(nodeName)){ name.append(ch,start,length); }else if ("version".equals(nodeName)){ version.append(ch,start,length); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if ("app".equals(localName)){ Log.d("id:", id.toString().trim()); Log.d("name:", name.toString().trim()); Log.d("version:", version.toString().trim()); //将StringBuilder清空 id.setLength(0); name.setLength(0); version.setLength(0); } } @Override public void endDocument() throws SAXException { super.endDocument(); } }
//OkHttpClient方法 private void SendOkHttp(){ new Thread(new Runnable() { @Override public void run() { try { OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("http://192.168.43.59/android/data.xml").build(); Response response = client.newCall(request).execute(); String responseData = response.body().string(); //showResponse(responseData); //parsrXnmPull(responseData); SAXXmlParse(responseData); } catch (IOException e) { e.printStackTrace(); } } }).start(); } private void SAXXmlParse(String xmlDate){ try { SAXParserFactory factory = SAXParserFactory.newInstance(); XMLReader xmlReader = factory.newSAXParser().getXMLReader(); ContentHandler handler = new ContentHandler(); //ContentHandler设置到XMLReader中 xmlReader.setContentHandler(handler); //开始解析
xmlReader.parse(new InputSource(new StringReader(xmlDate)));
}catch (Exception e){ e.printStackTrace(); } }
点击事件触发:
7.4、解析JSON格式数据
json具有体积小、再传送过程中更省流量
缺点:语义性差
private void SendOkHttp(){ new Thread(new Runnable() { @Override public void run() { try { OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("http://10.0.2.2/android/data_json.json").build(); Response response = client.newCall(request).execute(); String responseData = response.body().string(); //showResponse(responseData); //parsrXnmPull(responseData); //SAXXmlParse(responseData); JsonObject(responseData); } catch (IOException e) { e.printStackTrace(); } } }).start(); } private void JsonObject(String jsonData){ try { JSONArray jsonArray = new JSONArray(jsonData); for (int i = 0; i<jsonArray.length();i++){ JSONObject jsonObject = jsonArray.getJSONObject(i); String id = jsonObject.getString("id"); String name = jsonObject.getString("name"); String version = jsonObject.getString("version"); Log.d("id:", id); Log.d("name:", name); Log.d("version:", version); } }catch (Exception e){ e.printStackTrace(); } }
测试:
7.4.2、使用GSON
首先需要引入:
基本使用:
此时新建一个Person类:
public class Person { private String id; private String name; private String version; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } }
//OkHttpClient方法 private void SendOkHttp(){ new Thread(new Runnable() { @Override public void run() { try { OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("http://10.0.2.2/android/data_json.json").build(); Response response = client.newCall(request).execute(); String responseData = response.body().string(); //showResponse(responseData); //parsrXnmPull(responseData); //SAXXmlParse(responseData); //JsonObject(responseData); GsonParse(responseData); } catch (IOException e) { e.printStackTrace(); } } }).start(); } //Gson private void GsonParse(String jsonDate){ Gson gson = new Gson(); List<Person> personList = gson.fromJson(jsonDate,new TypeToken<List<Person>>(){}.getType()); for (Person person : personList){ Log.d("id:", person.getId()); Log.d("name:", person.getName()); Log.d("version:", person.getVersion()); } }
结果:
此时的使用是非常简单的!!!