1. WebView 的用法
1.1 在布局文件中添加 WebView
控件,使其充满屏幕
1.2 修改 MainActivity 中的代码
-
getSetting()
方法可以设置一些浏览器的属性,在这里只调用了setJavaScriptEnabled()
方法来使 WebView 支持 JavaScript 脚本。 - 接着调用了
setWebViewClient()
方法,并传入一个 WebViewClient 实例。这段代码的作用是,当需要从一个网页跳转到另一个网页时,目标网页仍然在当前 WebView 中显示,而不是打开系统浏览器。 - 最后调用
loadUrl()
方法,将网址传入即可展示相应网页的内容。
WebView webView = findViewById(R.id.web_view);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient());
webView.loadUrl("http://www.baidu.com");
1.3 声明访问网络权限
- 由于程序加入了网络功能,因此需要到
AndroidManifest.xml
中声明权限 <uses-permission android:name="android.permission.INTERNET"/>
2. 使用 HTTP 协议访问网络
-
HTTP 原理:客户端向服务器
发出一条 HTTP 请求
,服务器收到请求后会返回一些数据给客户端
,然后客户端再对这些数据进行解析和处理
即可。如上一节中向百度的服务器发起了一条 HTTP 请求,接着服务器分析出我们想要访问的是百度的首页,于是会把该网址的 HTML 代码进行返回,然后 WebView 再调用手机浏览器的内核对返回的 HTML 代码进行解析,最终将页面展示出来。
2.1 使用 HttpURLConnection:
目标:使用此技术获取数据,并显示到界面上
public class MainActivity extends AppCompatActivity {
private TextView responseText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
responseText = findViewById(R.id.response_text);
Button sendRequest = findViewById(R.id.send_request);
sendRequest.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
sendRequestWithHttpURLConnection();
}
});
}
/**
* 定义一个发送请求方法,具体的逻辑都在里面编写
*/
private void sendRequestWithHttpURLConnection(){
// 因为网络请求是耗时操作,所以开启子线程来发起请求
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
BufferedReader reader = null;
try{
// 首先要获取 HttpURLConnection 实例
URL url = new URL("https://www.baidu.com");
connection = (HttpURLConnection)url.openConnection();
// 设置请求方法,各种超时
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
// 获取服务器返回的输入流,并使用 BufferedReader 进行读取
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{
try{
if(reader != null){
reader.close();
}
}catch(IOException e){
e.printStackTrace();
}
if(connection != null){
connection.disconnect();
}
}
}
}).start();
}
/**
* 定义此方法用于将结果显示在界面上,由于发起请求的逻辑操作
* 是在子线程进行,因此在这里需要将线程切换回主线程来进行
* UI 操作。
*
* @param response 服务器返回的响应结果,声明为 final 是
* 因为参数需要在内部类中使用
*/
private void showResponse(final String response){
runOnUiThread(new Runnable() {
@Override
public void run() {
responseText.setText(response);
}
});
}
}
- 步骤:
- 获取 HTTPURLConnection 实例
- 设置 HTTP 请求方法,GET 表示希望从服务器获取数据,POST 表示希望提交数据给服务器
- 设置连接超时,读取超时等
- 获取返回的输入流,并使用 BufferedReader 进行读取
- 关闭 HTTP 连接
- 发起一条 POST 请求:
connection.setRequestMethod("POST");
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.writeBytes("username=admin&password=123456");
2.2 使用 OkHttp:
- 在
app/build.gradle
中添加依赖:
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
- 接着上一节内容,只需修改
sendRequestWithHttpURLConnection()
方法即可:
private void sendRequestWithOkHttp(){
new Thread(new Runnable() {
@Override
public void run() {
try{
// 创建 OkHttpClient 实例
OkHttpClient client = new OkHttpClient();
// 创建 Request 对象发起请求
Request request = new Request.Builder()
.url("https://www.baidu.com")
.build();
/* 调用 newCall(request) 方法创建一个 Call 对象,再调用 Call 对象
的 execute() 方法来发送请求并并并获取服务器返回的数据,
再赋值给 Response 对象 */
Response response = client.newCall(request).execute();
// 将 Response 对象转换为 String 类型
String responseData = response.body().string();
showResponse(responseData);
}catch(Exception e){
e.printStackTrace();
}
}
}).start();
}
- 发起一条 POST 请求:
RequestBody requestBody = new FormBody.Builder()
.add("username","admin")
.add("password", "123456")
.build();
Request request = new Request.Builder()
.url("https://www.baidu.com")
.post(requestBody)
.build();
3. 解析 XML 格式数据
<apps>
<app>
<id>1</id>
<name>Google Maps</name>
<version>1.0</version>
</app>
<app>
<id>2</id>
<name>Chrome</name>
<version>2.1</version>
</app>
<app>
<id>3</id>
<name>Google Play</name>
<version>2.3</version>
</app>
</apps>
3.1 Pull 解析方式:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button sendRequest = findViewById(R.id.send_request);
sendRequest.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
sendRequestWithHttpURLConnection();
}
});
}
/**
* 定义一个发送请求方法,具体的逻辑都在里面编写
*/
private void sendRequestWithHttpURLConnection(){
// 因为网络请求是耗时操作,所以开启子线程来发起请求
new Thread(new Runnable() {
@Override
public void run() {
try{
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
// 指定访问的服务器地址是电脑本机
.url("http://10.0.2.2/get_data.xml")
.build();
Response response = client.newCall(request).execute();
String responseData = response.body().string();
parseXMLWithPull(responseData);
}catch(IOException e){
e.printStackTrace();
}
}
}).start();
}
private void parseXMLWithPull(String xmlData){
try{
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser parser = factory.newPullParser();
parser.setInput(new StringReader(xmlData));
// 得到当前解析事件
int eventType = parser.getEventType();
String id = null;
String name = null;
String version = null;
while(eventType != XmlPullParser.END_DOCUMENT){
String nodeName = parser.getName();
switch(eventType){
case XmlPullParser.START_TAG:
if("id".equals(nodeName)){
id = parser.nextText();
}else if("name".equals(nodeName)){
name = parser.nextText();
}else if("version".equals(nodeName)){
version = parser.nextText();
}
break;
case XmlPullParser.END_TAG:
if("app".equals(nodeName)){
Log.d(TAG, "id is " + id);
Log.d(TAG, "name is " + name);
Log.d(TAG, "version is " + version);
}
break;
}
// 获取下一个解析事件
eventType = parser.next();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
3.2 SAX 解析方式:
- 新建一个类继承自
DefaultHandler
,并复写父类的 5 个方法
public class ContentHandler extends DefaultHandler{
private String nodeName;
private StringBuilder id;
private StringBuilder name;
private StringBuilder version;
/**
* 此方法在开始 XML 解析时调用
*
* @throws SAXException
*/
@Override
public void startDocument() throws SAXException{
id = new StringBuilder();
name = new StringBuilder();
version = new StringBuilder();
}
/**
* 此方法在开始解析某个节点时调用
*
* @param uri 命名空间
* @param localName 标签名称
* @param qName 带命名空间的标签名称
* @param attributes 存放该标签的所有属性
* @throws SAXException
*/
@Override
public void startElement(String uri, String localName,
String qName, Attributes attributes) throws SAXException {
// 记录当前节点名
nodeName = localName;
}
/**
* 此方法会在获取节点中内容时调用
*
* @param ch 当前读到的 TextNode 字节数组
* @param start 字节开始的位置,如果要读取全部,那就是从 0 开始
* @param length 当前 TextNode 的长度
* @throws SAXException
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException{
/* 根据当前节点名判断将内容添加到哪一个
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);
}
}
/**
* 此方法会在完成解析某个节点时调用
*
* @param uri 命名空间
* @param localName 标签名称
* @param qName 带命名空间的标签名称
* @throws SAXException
*/
@Override
public void endElement(String uri,
String localName, String qName) throws SAXException{
if("app".equals(localName)){
Log.d("ContentHandler", "id is " + id.toString().trim());
Log.d("ContentHandler", "name is " + name.toString().trim());
Log.d("ContentHandler", "version is " + version.toString().trim());
// 最后要将 StringBuilder 清空掉
id.setLength(0);
name.setLength(0);
version.setLength(0);
}
}
/**
* 此方法会在完成整个 XML 解析时调用
*
* @throws SAXException
*/
@Override
public void endDocument() throws SAXException{
super.endDocument();
}
}
- 修改 MainActivity 中的代码:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button sendRequest = findViewById(R.id.send_request);
sendRequest.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
sendRequestWithHttpURLConnection();
}
});
}
/**
* 定义一个发送请求方法,具体的逻辑都在里面编写
*/
private void sendRequestWithHttpURLConnection(){
// 因为网络请求是耗时操作,所以开启子线程来发起请求
new Thread(new Runnable() {
@Override
public void run() {
try{
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
// 指定访问的服务器地址是电脑本机
.url("http://10.0.2.2/get_data.xml")
.build();
Response response = client.newCall(request).execute();
String responseData = response.body().string();
parseXMLWithSAX(responseData);
}catch(IOException e){
e.printStackTrace();
}
}
}).start();
}
private void parseXMLWithSAX(String xmlData){
try{
SAXParserFactory factory = SAXParserFactory.newInstance();
XMLReader reader = factory.newSAXParser().getXMLReader();
ContentHandler handler = new ContentHandler();
// 将 ContentHandler 的实例设置到 XMLReader 中
reader.setContentHandler(handler);
// 开始解析
// public void parse (InputSource input)
// public InputSource (Reader characterStream)
// public StringReader(String s)
reader.parse(new InputSource(new StringReader(xmlData)));
}catch (Exception e){
e.printStackTrace();
}
}
}
4. 解析 JSON 格式数据
[{"id":"5","version":"5.5","name":"Clash of Clans"},
{"id":"6","version":"7.0","name":"Boom Beach"},
{"id":"7","version":"3.5","name":"Clash Royale"}]
4.1 使用 JSONObject:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button sendRequest = findViewById(R.id.send_request);
sendRequest.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
sendRequestWithHttpURLConnection();
}
});
}
/**
* 定义一个发送请求方法,具体的逻辑都在里面编写
*/
private void sendRequestWithHttpURLConnection(){
// 因为网络请求是耗时操作,所以开启子线程来发起请求
new Thread(new Runnable() {
@Override
public void run() {
try{
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
// 指定访问的服务器地址是电脑本机
.url("http://10.0.2.2/get_data.json")
.build();
Response response = client.newCall(request).execute();
String responseData = response.body().string();
parseJSONWithJSONObject(responseData);
}catch(IOException e){
e.printStackTrace();
}
}
}).start();
}
private void parseJSONWithJSONObject(String jsonData){
try{
JSONArray jsonArray = new JSONArray(jsonData);
// 用循环遍历 JSONArray ,从中取出的每一个元素都是一个,JSONObject 对象
for(int i = 0; i < jsonArray.length(); i++){
JSONObject object = jsonArray.getJSONObject(i);
String id = object.getString("id");
String name = object.getString("name");
String version = object.getString("version");
Log.d(TAG, "id is " + id);
Log.d(TAG, "name is " + name);
Log.d(TAG, "version is " + version);
}
}catch(Exception e){
e.printStackTrace();
}
}
}
4.2 使用 GSON:
GSON 可以将一段 JSON 格式的字符串自动映射成一个对象
- 添加
app/build.gradle
依赖库:
implementation 'com.google.code.gson:gson:2.7'
- 定义一个 App类:
public class App {
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;
}
}
- 修改 MainActivity 中的代码:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button sendRequest = findViewById(R.id.send_request);
sendRequest.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
sendRequestWithHttpURLConnection();
}
});
}
/**
* 定义一个发送请求方法,具体的逻辑都在里面编写
*/
private void sendRequestWithHttpURLConnection(){
// 因为网络请求是耗时操作,所以开启子线程来发起请求
new Thread(new Runnable() {
@Override
public void run() {
try{
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
// 指定访问的服务器地址是电脑本机
.url("http://10.0.2.2/get_data.json")
.build();
Response response = client.newCall(request).execute();
String responseData = response.body().string();
parseJSONWithGSON(responseData);
}catch(IOException e){
e.printStackTrace();
}
}
}).start();
}
private void parseJSONWithGSON(String jsonData){
Gson gson = new Gson();
List<App> appList = gson.fromJson(jsonData, new TypeToken<List<App>>(){}.getType());
for(App app : appList){
Log.d(TAG, "id is " + app.getId());
Log.d(TAG, "name is " + app.getName());
Log.d(TAG, "version is " + app.getVersion());
}
}
}
5. 封装一个网络库
当想要发起网络请求时,只需调用里面的静态方法即可
5.1 使用 HttpURLConnection 进行封装
- 定义一个接口用于回调:
public interface HttpCallbackListener {
/**
* 当服务器成功响应请求时调用
* @param response 服务器返回的数据
*/
void onFinish(String response);
/**
* 当进行网络操作出现错误时调用
* @param e 异常对象
*/
void onError(Exception e);
}
- 定义一个公共类用于发起网络请求:
public class HttpUtil {
public static void sendHttpRequest(final String address, final HttpCallbackListener listener){
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
BufferedReader reader = null;
try{
URL url = new URL(address);
connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
// DoInput() 用于 GET,默认是 true,可以不调用
// DoOutput() 用于 POST,默认是 false,用 POST 时一定要调用
connection.setDoInput(true);
connection.setDoOutput(true);
InputStream input = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(input));
StringBuilder response = new StringBuilder();
String line;
while((line = reader.readLine()) != null){
response.append(line);
}
if(listener != null){
// 回调 onFinish() 方法
listener.onFinish(response.toString());
}
}catch(Exception e){
if(listener != null){
// 回调 onError() 方法
listener.onError(e);
}
}finally{
try{
if(reader != null){
reader.close();
}
}catch (IOException e){
e.printStackTrace();
}
if(connection != null){
connection.disconnect();
}
}
}
}).start();
}
}
- 发起请求时:
HttpUtil.sendHttpRequest(address, new HttpCallbackListener(){
@Override
public void onFinish(String response){
// 根据返回内容执行逻辑
}
@Override
public void onError(Exception e){
// 对异常情况进行处理
}
});
5.2 使用 OkHttp 进行封装
- 在
HttpUtil
中加入sendOkHttpRequest()
方法:
public class HttpUtil {
public static void sendOkHttpRequest(String address, okhttp3.Callback callback){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(address)
.build();
client.newCall(request).enqueue(callback);
}
}
- 调用请求方法时:
HttpUtil.sendOkHttpRequest("https://www.baidu.com", new okhttp3.Callback(){
@Override
public void onResponse(Call call, Response response)throws IOException{
// 得到服务器返回的具体内容
String responseData = response.body().string();
}
@Override
public void onFailure(Call call, IOException e){
// 在这里对异常情况进行处理
e.printStackTrace();
}
});
网友评论