一·、WebView的用法
1、借助WebView可以在自己的应用程序里嵌入一个浏览器,从而轻松的展示各种各样的网页。
2、WebView基本用法
《1》、修改Activity_main.xml中的代码,Android提供了一个WebView控件,借助它我们可以在自己的应用程序里嵌入一个浏览器。用来显示网页。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/web_view"/>
</LinearLayout>
《2》、修改MainActivity中的代码。
(1)、首先使用findViewById()获取到WebView的实例,然后调用WebView的getSettings()方法可以去设置一些浏览器的属性,这里调用了setJavaScriptEnable()方法来让WebView支持JavaScript脚本。
(2)、调用WebView的setWebViewClient()方法,并传入了一个WebViewClient的实例,这段代码的作用是,当需要从一个网页跳转到另一个网页时,希望目标网页仍然在当前WebView中显示,而不是打开系统浏览器。
(3)、调用WebView的loadUrl()方法,并将网址传入,即可展示相应网页的内容。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView webView=findViewById(R.id.web_view);
//设置浏览器的属性 让浏览器支持javaScript脚本
webView.getSettings().setJavaScriptEnabled(true);
//当一个网页跳转到另一个网页 目标网页还在这个WenView中显示,不使用系统浏览器
webView.setWebViewClient(new WebViewClient());
//传入跳转的HTTP协议
webView.loadUrl("http://www.baidu.com");
}
}
《3》、注意:由于本程序用到了网络功能·,而访问网络是需要声明权限的,在AndroidManifest.xml文件中添加权限声明。
<uses-permission android:name="android.permission.INTERNET"/>
二、使用HTTP协议访问网络
1、HTTP协议工作原理:就是客户端向服务端发出一条HTTP协议,服务器接收到请求之后会返回一些数据给客户端,然后客户端对这些数据进行解析和处理。
2、Android发送HTTP请求一般有两种方式:HttpURLConnection和HttpClient,由于HttpClient存在API数量过多、扩展困难等缺点,Android6.0系统以后HttpClient的功能就被完全移除了。标志着此功能被正是废弃。
使用HttpURLConnection的用法
1、首先需要获取到HttpURLConnection的实例,一般需要new出一个URL对象,并传入目标的网络地址,然后调用一下openConnection()方法即可。
URL url=new URL("http://baidu.com");
HttpURLConnection connection= (HttpURLConnection) url.openConnection();
2、得到HttpURLConnection的实例后,通过setRequestMethod()方法设置HTTP请求所使用的方法。通常有两种:GET,表示希望从服务器那里获取数据;POST,表示希望提交数据给服务器。
connection.setRequestMethod("GET");
3、可以设置一些自由的定制,比如设置连接超时、读取超时的毫秒数,以及服务器希望得到的一些消息头等。
4、调用getInputStream()方法就可以获取到服务器返回的输入流了,对输入流进行读取。
InputStream in=connection.getInputStream();
5、调用disconnect()方法将这个HTTP连接关闭。
connection.disconnect();
创建一个例子体验HttpURLConnection的用法
ScrollView控件:它是可以通过滚动的形式查看屏幕外的那部分内容。
《1》、新建一个NetworkTest项目,首先修改activity_main.xml中的代码。使用了一个新的控件ScrollView。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/send_request"
android:text="Send Request"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/response_text"
android:text="Hello World!" />
</LinearLayout>
《2》、修改ManiAvtivity中的代码。
(1)、在按钮点击事件里调用了 方法,在这个方法里开启一个子线程。在子线程里使用HttpURLConnection发送一条HTTP请求,请求的目标地址就是百度首页。
(2)、利用BufferedReader对服务器返回的流进行读取,并将结果传入到showResponse()方法中。
(3)、在showResponse()方法里调用runOnUiThread()方法,然后在这个方法的匿名类参数中进行操作,将返回的数据显示到界面中。
注意:调用runOnUiThread()方法,是因为Android是不允许在子线程进行UI操作的,通过这个方法将线程切换到主线程然后再更新UI元素。
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
TextView responseText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button sendRequest=findViewById(R.id.send_request);
responseText=findViewById(R.id.response_text);
sendRequest.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId()==R.id.send_request){
sendRequestWithHttpURLConnection();
}
}
private void sendRequestWithHttpURLConnection() {
//开启线程来发起网络请求
new Thread(new Runnable() {
HttpURLConnection connection=null;
BufferedReader reader;
@Override
public void run() {
try {
//1.创建一个URL对象传入要请求的网址
URL url=new URL("http://baidu.com");
//2.创建HttpURLConnection实例
connection= (HttpURLConnection) url.openConnection();
//设置提交请求方式
connection.setRequestMethod("GET");
//设置连接、读取的延迟时间
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
//获取返回的输入流
InputStream in=connection.getInputStream();
//对获取到的输入流进行读取
reader = new BufferedReader(new InputStreamReader(in));
//接收获取到的输入流
StringBuilder response=new StringBuilder();
String line;
while((line=reader.readLine())!=null){
reader.readLine();
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();
}
private void showResponse(final String response) {
runOnUiThread(new Runnable() {
@Override
public void run() {
//在这里进行 UI 操作,将结果显示到界面上。
responseText.setText(response);
}
});
}
}
(4)、声明网络权限,修改AndroidManifest.xml中的代码。
<uses-permission android:name="android.permission.INTERNET"/>
6、想要提交数据给服务器,只需要将HTTP请求的方法改成POST,并在获取输入流之前把要提交的数据写出即可,注意每条数据都要以键值对的形式存在,数据与数据之间用&符号隔开。
比如说向服务器提交用户名和密码。
connection.setRequestMethod("POST");
DataOutputStream out=new DataOutputStream(connection.getOutputStream());
out.writeBytes("username=admin$password=123456");
三、使用OkHttp
1、OkHttp网络通信库可以替代原生HttpURLConnrction,现在已成为Android开发者首选的网络通信库。
2、OkHttp的项目主页地址是:http://github.com/square/okhttp.
3、在使用OkHttp之前,需要在项目中添加OkHttp库的依赖。编辑app/build.gradle文件,在dependencies闭包中添加如下内容。添加依赖会自动下载两个库,一个是OkHttp,一个是Okio库,后者是前者的通信基础。
//compile 'com.squareup.okhttp3:okhttp:3.4.1'
implementation 'com.squareup.okhttp3:okhttp:4.2.2'
OkHttp的使用:
1、创建一个OkHttpClient的实例
OkHttpClient client=new OkHttpClient();
2、发起一条HTTP请求,就需要创建一个Request对象。build()方法之前连缀很多其他方法来丰富这个Request对象,比如可以通过url()方法来设置目标的网路地址。
Request request=new Request.Builder().url("http://baidu.com").build();
3、调用OkHttpClient的newCall()方法来创建一个Call对象,并调用它的execute()方法来发送请求并获得服务器返回的数据。
Response response=client.newCall(request).execute();
其中Response对象就是服务器返回的数据了,使用以下写法来得到返回的具体内容。
String responseData=response.body().string();
4、如果发起一条POST请求,需要先构建出一个RequestBody对象来存放待提交的参数。
RequestBody requestBody=new FormBody.Builder().add("username","admin").add("password","123").build();
然后在Request.Builder中调用一下post()方法,并将RequestBody对象传入。接下来的操作就和GET请求一样了,调用execute()方法来发送请求并获取服务器返回的数据即可。
Request request=new Request.Builder().url("http://baidu.com"),post(requestBody).build();
5、把NetworkTest这个项目改为OkHttp的方式在实现一遍:直接修改ManiActivity中的代码。
public class MainActivity2 extends AppCompatActivity implements View.OnClickListener {
TextView responseText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button sendRequest = findViewById(R.id.send_request);
responseText = findViewById(R.id.response_text);
sendRequest.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.send_request) {
sendRequestWithOkHttp();
}
}
private void sendRequestWithOkHttp() {
//开启线程来发起网络请求
new Thread(new Runnable() {
OkHttpClient client;
@Override
public void run() {
try {
//1.创建OkHttp实例
OkHttpClient client = new OkHttpClient();
//发出一条HTTP请求,
Request request = new Request.Builder().url("http://baidu.com").build();
//发送请求并获取服务器返回的数据
Response response = client.newCall(request).execute();
//获取服务器返回的具体数据内容
String responseData = response.body().string();
//让showResponse()将服务器返回的数据显示到界面上
showResponse(responseData);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
private void showResponse(final String response) {
runOnUiThread(new Runnable() {
@Override
public void run() {
//在这里进行 UI 操作,将结果显示到界面上。
responseText.setText(response);
}
});
}
}
三、解析XML格式数据
1、每个需要访问网络的应用程序都会有一个自己的服务器,我们可以向服务器提交内容,也可以从服务器上获取数据。
2、在网路上传输数据时最常用的格式有两种:XML和JSON
搭建Web服务器
1、首先去下载一个Apache服务器的安装包。官方下载地址是:http://httpd.apache.org/download.cgi.
2、解析XML格式的数据其实有很多,常用的两种Pull解析和SAX解析。
Pull解析
在NetworkTest项目的基础上继续开发。
1、首先将HTTP请求的地址改成本机地址,得到服务器返回的数据后,调用parseXMLWithPull()方法来解析服务器返回的数据。
2、获取XmlPullParerFactory的实例,并借助它得到XmlPullParser对象。
3、调用XmlPullParser的setInput()将服务器返回的XML数据设置进去就可以开始解析了
4、通过getEventType()可以得到当前的解析事件,在while循环里进行解析。
5、在while循环中若解析事件不等于XmlPullParser.END_DOCUMENT,说明解析还没完成。
6、通过getName()得到当前节点的名字。
7、开始解析某个节点,若发现节点名等于id、name或version,就调用nextText()获取节点内具体的内容。
8、完成解析某个节点,并打印出来它的内容。
9、通过next()获取下一个解析事件。
public class MainActivity2 extends AppCompatActivity implements View.OnClickListener {
TextView responseText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button sendRequest = findViewById(R.id.send_request);
responseText = findViewById(R.id.response_text);
sendRequest.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.send_request) {
sendRequestWithOkHttp();
}
}
private void sendRequestWithOkHttp() {
//开启线程来发起网络请求
new Thread(new Runnable() {
OkHttpClient client;
@Override
public void run() {
try {
//1.创建OkHttp实例
OkHttpClient client = new OkHttpClient();
//发出一条HTTP请求,指定访问的服务器地址是电脑本机
Request request = new Request.Builder().url("http://192.168.211.154/get_data.xml").build();
//发送请求并获取服务器返回的数据
Response response = client.newCall(request).execute();
//获取服务器返回的具体数据内容
String responseData = response.body().string();
// //让showResponse()将服务器返回的数据显示到界面上
// showResponse(responseData);
//进行解析服务器返回的数据
parseXMLWithPull(responseData);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
protected void parseXMLWithPull(String xmlData) {
try {
//获取XmlPullParerFactory的实例,并借助它得到XmlPullParser对象
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser = factory.newPullParser();
//调用XmlPullParser的setInput()将服务器返回的XML数据设置进去就可以开始解析了
xmlPullParser.setInput(new StringReader(xmlData));
//通过getEventType()可以得到当前的解析事件,在while循环里进行解析。
int eventType = xmlPullParser.getEventType();
String id = "";
String name = "";
String version = "";
//若解析事件不等于XmlPullParser.END_DOCUMENT,说明解析还没完成。
while (eventType != XmlPullParser.END_DOCUMENT) {
//通过getName()得到当前节点的名字,
String nodeName = xmlPullParser.getName();
switch (eventType) {
//开始解析某个节点,若发现节点名称等于id、name或version,就调用nextText()获取节点内具体的内容。
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("AAAAAA", "parseXMLWithPull: id is" + id);
Log.d("AAAAAA", "parseXMLWithPull: name is" + name);
Log.d("AAAAAA", "parseXMLWithPull: version is" + version);
}
break;
}
default:
break;
}
//获取下一个解析事件
eventType = xmlPullParser.next();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
SAX解析方式
SAX解析是XML解析方式。
1、新建一个类继承自DefaultHandler,并重写父类的5个方法
《1》、startDocument()方法会在开始XML解析的时候调用。
《2》、startElement()方法会在开始解析某个节点的时候调用。
《3》、characters()方法会在获取节点中内容的时候被调用。
《4》、endElement()方法会在完成解析某个节点的时候调用。
《5》、endDocument()方法会在完成整个XML解析的时候调用。
2、startElement()、characters()、endElement()3个方法是有参数的,从XML中解析出来的数据就会以参数的形式传入到这些方法中。
注意:在获取节点内容时,characters()可能被调用多次,一些换行符也被当作内容解析出来。
SAX解析的实例
1、创建一个类ContenDandler继承DefaultHandler ,重写5个方法。
public class ContenDandler extends DefaultHandler {
private String nodeName;
private StringBuilder id;
private StringBuilder name;
private StringBuilder version;
@Override
public void startDocument() throws SAXException {
super.startDocument();
id = new StringBuilder();
name = new StringBuilder();
version = new StringBuilder();
}
//开始解析某个节点startElement()被调用,其中localName参数记录着当前节点的名字
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
//记录当前节点名字
nodeName = localName;
}
//解析节点中的具体内容characters()被调用,根据当前的节点名进行判断,将解析出的内容添加到一个StringBuilder对象中
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
//根据当前的节点名判断内容添加到哪一个StringBuilder对象中
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);
}
}
//app节点已被解析完成,打印出id、name、version内容,
// 注意:id、name、version可能包括换行符或回车,打印之前需要调用一下trim(),并且打印完成后还要将StringBuilder的内容清空。
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
if ("app".equals(localName)) {
Log.d("ContenDandler", "endElement: id is" + id.toString().trim());
Log.d("ContenDandler", "endElement: name is" + name.toString().trim());
Log.d("ContenDandler", "endElement: version is" + version.toString().trim());
//最后将StringBuilder清空
id.setLength(0);
name.setLength(0);
version.setLength(0);
}
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
}
2、修改MainActivity中的代码
public class MainActivity2 extends AppCompatActivity implements View.OnClickListener {
TextView responseText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button sendRequest = findViewById(R.id.send_request);
responseText = findViewById(R.id.response_text);
sendRequest.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.send_request) {
sendRequestWithOkHttp();
}
}
private void sendRequestWithOkHttp() {
//开启线程来发起网络请求
new Thread(new Runnable() {
OkHttpClient client;
@Override
public void run() {
try {
//1.创建OkHttp实例
OkHttpClient client = new OkHttpClient();
//发出一条HTTP请求,指定访问的服务器地址是电脑本机
Request request = new Request.Builder().url("http://192.168.211.154/get_data.xml").build();
//发送请求并获取服务器返回的数据
Response response = client.newCall(request).execute();
//获取服务器返回的具体数据内容
String responseData = response.body().string();
//进行SAX解析服务器返回的数据
parseXMLWithSAX(responseData);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
//进行SAX解析
private void parseXMLWithSAX(String responseData) {
try {
SAXParserFactory factory=SAXParserFactory.newInstance();
XMLReader xmlReader=factory.newSAXParser().getXMLReader();
ContenDandler contentHandler=new ContenDandler();
//将ContentHandler的实例设置到XMLReader中。
xmlReader.setContentHandler(contentHandler);
//开始执行解析
xmlReader.parse(new InputSource(new StringReader(responseData)));
} catch (Exception e) {
e.printStackTrace();
}
}
}
DOM解析方式
四、解析JSON数据格式
1、JSON主要优势在于它的体积小,在网络上传输的时候可以更省流量。缺点:他的语义性差,不如XML直观
2、在开始之前需要在C:\Apache\htdocs,目录中新建一个get_data.json的文件,然后编辑添加如下内容:
3、在浏览器中访问http://127.0.0.1/get_data.json这个网址,这样就把json格式的数据也准备好了。
4、使用官方提供的JSONObject、谷歌开源的库GSON、另外一些第三方的开源库如Jackson、FastJSON等进行解析JSON数据。
使用JSONObject进行解析
1、在NetworkTest这个项目中,修改MainActivity中的代码。
2、首先将HTTP的请求的地址改成本机,然后得到服务器返回的数据后调用方法进行解析。
3、由于我们在服务器中定义的是一个JSON数组,因此首先是将服务器返回的数据传入到了一个JSONArray对象中,然后循环遍历JSONArray,从中取出的每一个元素都是一个JSONObject对象,每个JSOPNObject对象中的又会包含id、name、和version这些数据。
4、调用getString()方法将这些数据取出打印。
/**
* @author admin
*/
public class MainActivity2 extends AppCompatActivity implements View.OnClickListener {
TextView responseText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button sendRequest = findViewById(R.id.send_request);
responseText = findViewById(R.id.response_text);
sendRequest.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.send_request) {
sendRequestWithOkHttp();
}
}
private void sendRequestWithOkHttp() {
//开启线程来发起网络请求
new Thread(new Runnable() {
OkHttpClient client;
@Override
public void run() {
try {
//1.创建OkHttp实例
OkHttpClient client = new OkHttpClient();
//发出一条HTTP请求,指定访问的服务器地址是电脑本机
// Request request = new Request.Builder().url("http://192.168.211.154/get_data.xml").build();
Request request = new Request.Builder().url("http://192.168.211.154/get_data.json").build();
//发送请求并获取服务器返回的数据
Response response = client.newCall(request).execute();
//获取服务器返回的具体数据内容
String responseData = response.body().string();
//进行JSONObject解析服务器返回的JSON数据
parseJSONWithJSONObject(responseData);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
/**
* 进行JSONObject解析
*/
private void parseJSONWithJSONObject(String responseData) {
try {
//将服务器返回的数据传入到一个JSONArray对象中。
JSONArray jsonArray=new JSONArray(responseData);
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("MainActivity2", "parseJSONWithJSONObject: id is"+id);
Log.d("MainActivity2", "parseJSONWithJSONObject: name is"+name);
Log.d("MainActivity2", "parseJSONWithJSONObject: version is"+version);
}
} catch (Exception e) {
e.printStackTrace();
}
}
使用GSON解析
GSON可以将一段JSON格式的字符串自动映射成一个对象,不需要我们手动去编写代码进行解析。
比如说:
《1》、一段JSON格式的数据{“name:“Tom”,“age”:20”}
《2》、可以定义一个Person类,并加入name,age这两个字段,主需要调用一下代码就能把JSON数据自动解析成一个Person对象。
Gson gson=new Gson;
Person person=gson.fromJson(jsonData,Person.class);
《3》、解析数组需要借助TypeToken将期望解析成的数据类型传入到fromJson()方法中。
List<Person> pepole=gson.fromJson(jsonData,new TypeToken<List<Person>>);
GSON解析实例
1、需要添加GSON库的依赖,编辑app/build.gradle文件,在dependencies闭包中添加如下内容
implementation 'com.gogle.code.gson:gson:2.7'
2、修改MainActivity2 中的代码。
public class MainActivity2 extends AppCompatActivity implements View.OnClickListener {
TextView responseText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button sendRequest = findViewById(R.id.send_request);
responseText = findViewById(R.id.response_text);
sendRequest.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.send_request) {
sendRequestWithOkHttp();
}
}
private void sendRequestWithOkHttp() {
//开启线程来发起网络请求
new Thread(new Runnable() {
OkHttpClient client;
@Override
public void run() {
try {
//1.创建OkHttp实例
OkHttpClient client = new OkHttpClient();
//发出一条HTTP请求,指定访问的服务器地址是电脑本机
// Request request = new Request.Builder().url("http://192.168.211.154/get_data.xml").build();
Request request = new Request.Builder().url("http://192.168.211.154/get_data.json").build();
//发送请求并获取服务器返回的数据
Response response = client.newCall(request).execute();
//获取服务器返回的具体数据内容
String responseData = response.body().string();
//进行GSON解析服务器返回的JSON数据
pareJSONWithGSON(responseData);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
/**
*进行GSON解析
*/
private void pareJSONWithGSON(String responseData) {
Gson gson=new Gson();
List<App> appList=gson.fromJson(responseData,new TypeToken<List<App>>(){}.getType());
for (App app:appList
) {
Log.d("aaaaa", "pareJSONWithGSON: id is"+app.getId());
Log.d("aaaaa", "pareJSONWithGSON: name is"+app.getName());
Log.d("aaaaa", "pareJSONWithGSON: version is"+app.getVersion());
}
}
}