目录:
1.WebView组件的使用
2.使用HttpURLConnection协议访问网络
3.通过HttpClient访问
4.解析XML格式数据
5.解析JSON格式数据
————————————————————————《第一行代码》笔记之网络技术
1.WebView组件的使用
该组件的使用需要在AndroidManifest.xml添加网络权限,如下:
<uses-permission android:name="android.permission.INTERNET"/>
1.1用法一:
布局文件:只添加一个WebView的控件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
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" />
</LinearLayout>
MainActivity文件中的代码:
public class MainActivity extends Activity {
//声明组件
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取实例
webView = (WebView) findViewById(R.id.web_view);
//通过Setting()方法调整一些属性,此处以设置JS功能可用为例
webView.getSettings().setJavaScriptEnabled(true);
/*此步比较重要调用了WebView的setWebViewClient()方法,并传入了WebViewClient的匿名类作为参数,然后重写了shouldOverrideUrlLoading()方法,这就表明当需要从一个网页跳转到另一个网页时,我们希望目标网页仍然在当前WebView中显示,而不是打开系统浏览器。*/
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url); // 根据传入的参数再去加载新的网页
return true; // 表示当前WebView可以处理打开新网页的请求,不用借助系统浏览器
}
});
//调用WebView的loadUrl()方法,并将网址传入,即可展示相应网页的内容
webView.loadUrl("http://www.baidu.com");
}
}
1.2用法二:
该用法实现了通过百度进行关键词搜索,并将搜索到页面显示在WebView中
布局的设计与用法一有所不同,此布局中多加入了Button、EditText等插件
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.a14553.webview.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/txv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请输入关键词:" />
<EditText
android:id="@+id/edt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName" />
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="search"
android:text="Button" />
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="@+id/wv"
android:layout_width="match_parent"
android:layout_height="match_parent">
</WebView>
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-7dp"
tools:layout_editor_absoluteX="135dp"
tools:layout_editor_absoluteY="0dp" />
</RelativeLayout>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
MainActivit.java中的代码如下
package com.example.a14553.webview;
import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.EditText;
import android.widget.ProgressBar;
public class MainActivity extends AppCompatActivity {
WebView wv;
ProgressBar pb;
EditText edt;
String keyword;
String baseURL = "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd=";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//实例化
wv = (WebView)findViewById(R.id.wv);
pb = (ProgressBar)findViewById(R.id.progressBar);
edt = (EditText)findViewById(R.id.edt);
//使JS功能可用
wv.getSettings().setJavaScriptEnabled(true);
//避免打开浏览器
wv.setWebViewClient(new WebViewClient());
//创建网页加载进度接口
wv.setWebChromeClient(new WebChromeClient(){
public void onProgressChanged(WebView view,int progress){
//为菜单条绑定加载进度
pb.setProgress(progress);
pb.setVisibility(progress<100?View.VISIBLE:View.GONE);
}
});
}
//点击按钮触发事件
public void search(View v){
//将单个或连续的空格置换成+
keyword = edt.getText().toString().replaceAll("\\s+","+");
wv.loadUrl(baseURL+keyword);
}
//返回上一页的功能,按返回键触发
public void onBackPressed(){
if(wv.canGoBack()){
wv.goBack();
return;
}
super.onBackPressed();
}
//通过首选项将参数字符串存储起来
public void onPause(){
super.onPause();
SharedPreferences.Editor editor = getPreferences(MODE_PRIVATE).edit();
//写入字符串
editor.putString("关键词",keyword);
//提交,也可使用editor.commit()方法
editor.apply();
}
//读取首选项
public void onResume(){
super.onResume();
//获取首选项对象
SharedPreferences myPref = getPreferences(MODE_PRIVATE);
//读取存储的字符串项,若不存在则默认返回welcome
keyword = myPref.getString("关键字","welcome");
if(wv.getUrl()==null)
wv.loadUrl(baseURL+keyword);
}
}
2.使用HttpURLConnection协议访问网络
使用HTTP协议访问网络的时候需要使用到多线程,Android中使用多线程更多的是使用匿名类的方式:
new Thread(new Runnable() {
@Override
public void run() {
// 处理具体的逻辑
}
}).start();
而在子线程中是不可以修改UI界面的内容的,也就是说在子线程从网络中获得的数据无法直接输出到EditText中的,所以需要使用异步处理:
①其中一个方法是可以通过Handler来实现
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_TEXT:
// 在这里可以进行UI操作
text.setText("Nice to meet you");
break;
default:
break;
}
}
};
//与之配套的是在子线程中返回信息
//子线程内:
Message message = new Message();
message.what = SHOW_RESPONSE;
// 将服务器返回的结果存放到Message中
message.obj = response.toString();
handler.sendMessage(message);
②另一种方法是通过AsyncTask抽象类来实现
一个简单的自定义的AsyncTask如下
class DownloadTask extends AsyncTask<Void, Integer, Boolean> {
//第一个参数为传入的参数,这里为void
//第二个参数是处理的进度,这里用int类型的数据
//第三个参数是返回的结果,这里返回Boolean类型的结果
@Override
protected void onPreExecute() {
progressDialog.show(); // 显示进度对话框
}
//在此方法中不能进行UI操作,如果需要UI操作则使用publishProcess调用下面的函数
@Override
protected Boolean doInBackground(Void... params) {
try {
while (true) {
int downloadPercent = doDownload(); // 这是一个虚构的方法
publishProgress(downloadPercent);
if (downloadPercent >= 100) {
break;
}
}
} catch (Exception e) {
return false;
}
return true;
}
//在此方法中可以进行UI操作
@Override
protected void onProgressUpdate(Integer... values) {
// 在这里更新下载进度
progressDialog.setMessage("Downloaded " + values[0] + "%");
}
//此方法最后返回结果
@Override
protected void onPostExecute(Boolean result) {
progressDialog.dismiss(); // 关闭进度对话框
// 在这里提示下载结果
if (result) {
Toast.makeText(context, "Download succeeded", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, " Download failed", Toast.LENGTH_SHORT).show();
}
}
}
如果想要启动这个任务,只需编写以下代码即可:
new DownloadTask().execute();
本处将使用第一种方法
2.1.首先实例化一个可以异步修改UI的对象handler
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case SHOW_RESPONSE:
String response = (String) msg.obj;
// 在这里进行UI操作,将结果显示到界面上
responseText.setText(response);
}
}
};
2.2.相应鼠标的事件
public void onClick(View v){
if (v.getId() == R.id.send_request) {
sendRequestWithHttpURLConnection();
}
}
2.3.新建线程读取文件流并通过message传回
private void sendRequestWithHttpURLConnection() {
// 开启线程来发起网络请求
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
try {
URL url = new URL(path);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
InputStream in = connection.getInputStream();
// 下面对获取到的输入流进行读取
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
Message message = new Message();
message.what = SHOW_RESPONSE;
// 将服务器返回的结果存放到Message中
message.obj = response.toString();
handler.sendMessage(message);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
}).start();
}
3.通过HttpClient访问
HttpClient是一个接口,所以不能实例化,一般用DefaultHttpClient()去实例化
HttpClient也有GET和POST两种方法:
其中GET方法较简单:
//创建一个HttpGet对象,并传入目标的网络地址
HttpGet httpGet = new HttpGet("http://www.baidu.com");
//调用HttpClient的execute()方法
httpClient.execute(httpGet);
POST方法较复杂:
//创建一个HttpPost对象,并传入目标的网络地址
HttpPost httpPost = new HttpPost("http://www.baidu.com");
//通过一个NameValuePair集合来存放待提交的参数
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("username", "admin"));
params.add(new BasicNameValuePair("password", "123456"));
//将这个参数集合传入到一个UrlEncodedFormEntity中
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "utf-8");
//调用HttpPost的setEntity()方法将构建好的UrlEncodedFormEntity传入
httpPost.setEntity(entity);
//调用HttpClient的execute()方法
httpClient.execute(httpPost);
执行execute()方法之后会返回一个HttpResponse对象,服务器所返回的所有信息就会包含在这里面。通常情况下我们都会先取出服务器返回的状态码,如果等于200就说明请求和响应都成功了:
if (httpResponse.getStatusLine().getStatusCode() == 200) {
// 请求和响应都成功了
//调用getEntity()方法获取到一个HttpEntity实例
HttpEntity entity = httpResponse.getEntity();
//用EntityUtils.toString()这个静态方法将HttpEntity转换成字符串
String response = EntityUtils.toString(entity,"UTF-8");
}
与使用HttpURLConnection相比,使用HttpClient只需要添加一个方法,并在点击按钮时使用本方法即可:
PS:Android6.0+已经不再支持该类。
private void sendRequestWithHttpClient() {
new Thread(new Runnable() {
@Override
public void run() {
try {
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet("http://www.baidu.com");
HttpResponse httpResponse = httpClient.execute(httpGet);
if (httpResponse.getStatusLine().getStatusCode() == 200) {
// 请求和响应都成功了
HttpEntity entity = httpResponse.getEntity();
String response = EntityUtils.toString(entity, "utf-8");
Message message = new Message();
message.what = SHOW_RESPONSE;
// 将服务器返回的结果存放到Message中
message.obj = response.toString();
handler.sendMessage(message);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
4.解析XML格式数据
解析XML格式的数据的方式:DOM解析、Pull解析、Sax解析等。
4.1通过DOM解析
先通过sendRequestWithHttpURLConnectionXmlPull()方法连接网络并打开文件流
public void sendRequestWithHttpURLConnectionXmlPull(){
// 开启线程来发起网络请求
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
try {
URL url = new URL(path_json);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
InputStream in = connection.getInputStream();
String temp=parseXmlByDom(in);
Message message = new Message();
message.what = SHOW_RESPONSE;
// 将服务器返回的结果存放到Message中
message.obj = temp;
handler.sendMessage(message);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
}).start();
}
具体的解析方法parseXmlByDom():
public String parseXmlByDom(InputStream inputStream){
String result = "";
//
DocumentBuilderFactory bdf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
Document doc = null;
try{
//
builder = bdf.newDocumentBuilder();
}catch (ParserConfigurationException e){
e.printStackTrace();
}
try{
//解析字符流
doc = builder.parse(inputStream);
}catch (SAXException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
Element ele = doc.getDocumentElement();
//获取所有的fruit节点
NodeList nl = ele.getElementsByTagName("fruit");
if(nl!=null&&nl.getLength()!=0){
for(int i=0;i<nl.getLength();i++){
Element entry = (Element)nl.item(i);
//
result += "name:"+entry.getAttribute("name")+"-->"+entry.getTextContent()+"\n";
}
}
return result;
}
4.2Pull解析
此处使用HttpURLConnection协议访问网络,程序与2中的程序相同,有差别的是修改了2中的sendRequestWithHttpURLConnection()方法,并且将按钮绑定的事件修改为调用新方法,新方法如下:
public void sendRequestWithHttpURLConnectionXmlPull(){
// 开启线程来发起网络请求
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
try {
URL url = new URL(path);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
InputStream in = connection.getInputStream();
// 下面对获取到的输入流进行读取
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
String res = response.toString();
String temp=parseXMLWithPull(res);
Message message = new Message();
message.what = SHOW_RESPONSE;
// 将服务器返回的结果存放到Message中
message.obj = temp;
handler.sendMessage(message);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
}).start();
}
private String parseXMLWithPull(String xmlData) {
String res = "";
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser = factory.newPullParser();
xmlPullParser.setInput(new StringReader(xmlData));
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();
res+="id="+id+"\n";
} else if ("name".equals(nodeName)) {
name = xmlPullParser.nextText();
res+="name"+name+"\n";
} else if ("version".equals(nodeName)) {
version = xmlPullParser.nextText();
res+="version="+version+"\n";
}
break;
}
// 完成解析某个结点
case XmlPullParser.END_TAG: {
if ("app".equals(nodeName)) {
Log.d("MainActivity", "id is " + id);
Log.d("MainActivity", "name is " + name);
Log.d("MainActivity", "version is " + version);
}
break;
}
default:
break;
}
eventType = xmlPullParser.next();
}
} catch (Exception e) {
e.printStackTrace();
}
return res;
}
本程序使用的示例为:
get_data.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>
4.3Sax解析
与4.2的程序相比,本程序新建了一个ContentHandler 类负责解析,并新建一个方法负责该类的调用,最后便是修改sendRequestWithHttpURLConnectionXmlPull()方法中一个调用,修改如下:
//String temp=parseXMLWithPull(res);
String temp=parseXMLWithSAX(res);
ContentHandler 类内容如下:
package com.example.a14553.httpconntest;
import android.util.Log;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* Created by 14553 on 2018/3/8.
*/
public class ContentHandler extends DefaultHandler {
public String res="";
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 {
// 根据当前的结点名判断将内容添加到哪一个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);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if ("app".equals(localName)) {
res += "id"+id.toString()+"\n";
res += "name"+name.toString()+"\n";
res += "version"+version.toString()+"\n";
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清空掉
//res = id.toString()+name.toString()+version.toString();
id.setLength(0);
name.setLength(0);
version.setLength(0);
}
}
public String backString(){
return res;
}
@Override
public void endDocument() throws SAXException {
}
}
新建的方法parseXMLWithSAX()为:
private String parseXMLWithSAX(String xmlData) {
String res="";
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(xmlData)));
res = handler.backString();
} catch (Exception e) {
e.printStackTrace();
}
return res;
}
5.解析JSON格式数据
解析JSON的方式:通过JSONObject、通过GSON
5.1.使用JSONObject
仍使用上面的项目,区别在于新增一个方法parseJSONWithJSONObject(),修改了sendRequestWithHttpURLConnectionXmlPull()方法中调用解析方式的地方:
//String temp=parseXMLWithSAX(res);
//String temp=parseXMLWithPull(res);
String temp=parseJSONWithJSONObject(res);
parseJSONWithJSONObject()方法内容如下:
private String parseJSONWithJSONObject(String jsonData) {
String res="JSON\n";
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("MainActivity", "id is " + id);
Log.d("MainActivity", "name is " + name);
Log.d("MainActivity", "version is " + version);
res+="id="+id+"\n";
res+="name="+name+"\n";
res+="version="+version+"\n";
}
} catch (Exception e) {
e.printStackTrace();
}
return res;
}
用于测试的文件:get_data.json
[{"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"}]
5.2.使用GSON解析JSON数据
GSON没有被添加到Android官方的API中,因此如果想要使用这个功能的话,则必须要在项目中添加一个GSON的Jar包。首先需要将GSON的资源压缩包下载下来(gson-2.8.2.jar),下载地址是:http://repo1.maven.org/maven2/com/google/code/gson/gson/2.8.2/。
将gson-2.8.2.jar复制进项目的libs文件夹中,右击,Add As Library即可。
之后新建App类:
package com.example.a14553.httpconntest;
/**
* Created by 14553 on 2018/3/8.
*/
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类中添加方法parseJSONWithGSON(),并修改了sendRequestWithHttpURLConnectionXmlPull()方法中调用解析方式的地方:
String temp=parseJSONWithGSON(res);
//String temp=parseJSONWithJSONObject(res);
//String temp=parseXMLWithSAX(res);
//String temp=parseXMLWithPull(res);
parseJSONWithGSON()方法如下:
private String parseJSONWithGSON(String jsonData) {
String res="";
Gson gson = new Gson();
List<App> appList = gson.fromJson(jsonData, new TypeToken<List<App>>() {}.getType());
for (App app : appList) {
Log.d("MainActivity", "id is " + app.getId());
Log.d("MainActivity", "name is " + app.getName());
Log.d("MainActivity", "version is " + app.getVersion());
res+="id="+app.getId()+"\n";
res+="name="+app.getName()+"\n";
res+="version="+app.getVersion()+"\n";
}
return res;
}