本系列学习笔记第10章
前言
打算把android基本知识点写一个系列,旨在把android基础书,例如《Android 第一行代码 第2版》、《爱上android》、《疯狂android讲义》等书的一些知识点记录一下,会持续更新内容,为了方便自己复习,也希望可以帮助到大家!
1、HTTP协议
1.1 URL简介
URL的全称是统一资源定位符,通过一个URL能找到互联网上唯一 的一个资源,URL就是资源的地址、位置。
URL的基本格式 = 协议://主机地址/路径
协议:不同的协议,代表不同资源的查找方式、资源传输方式
主机地址:存放资源的主机IP地址或者域名
路径:资源在主机中的具体位置
URL中常见的协议如下:
HTTP:超文本传输协议,访问的是远程网络资源,格式是http://
file:访问的是本机的文件资源,格式是file://
mailto:访问的是电子邮件地址,格式是mailto:
FTP:访问的是共享主机的文件资源,格式是ftp://
1.2 HTTP简介
1.3 GET与POST对比
2、WebView的用法
2.1 加载网络页面的用法
public class MainActivity extends AppCompatActivity {
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = (WebView) findViewById(R.id.web_view);
WebSettings settings = webView.getSettings();
//支持JavaScript脚本
settings.setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient());
webView.loadUrl("http://www.baidu.com");
}
}
2.2 加载本地静态页面的用法
首先先把html等文件放在如下的文件夹中
webView.loadUrl("file:///android_asset/apply_notice.html");
2.3 WebView的设置用法
//支持获取手势焦点,输入用户名、密码或其他
webView.requestFocusFromTouch();
//支持js,这样有潜在的安全隐患,无需要,建议关闭
webSettings.setJavaScriptEnabled(true);
//提高渲染的优先级,高版本废弃了。
webSettings.setRenderPriority(WebSettings.RenderPriority.HIGH);
// 设置自适应屏幕,两者合用
webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小
webSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小
webSettings.setSupportZoom(true); //支持缩放,默认为true。是下面那个的前提。
//若下面是false,则该WebView不可缩放,这个不管设置什么都不能缩放。
webSettings.setBuiltInZoomControls(true); //设置内置的缩放控件。
webSettings.setDisplayZoomControls(false); //隐藏原生的缩放控件
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN); //支持内容重新布局
webSettings.supportMultipleWindows(); //支持多窗口
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存
webSettings.setAllowFileAccess(true); //设置可以访问文件
webSettings.setNeedInitialFocus(true); //当webview调用requestFocus时为webview设置节点
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口
webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片
webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式
//----缓存
//根据网页中cache-control决定是否从网络上取数据。
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);//没网,则从本地获取,即离线加载
webSettings.setDomStorageEnabled(true); // 开启 DOM storage API 功能
webSettings.setDatabaseEnabled(true); //开启 database storage API 功能
webSettings.setAppCacheEnabled(true);//开启 Application Caches 功能
String cacheDirPath = getCacheDir().getAbsolutePath();
//设置 Application Caches 缓存目录
//每个 Application 只调用一次 WebSettings.setAppCachePath()
webSettings.setAppCachePath(cacheDirPath);
//Android 5.0上 Webview 默认不允许加载 Http 与 Https 混合内容,加下下面的配置就解决了.
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
2.4 WebViewClient的介绍
WebViewClient就是帮助WebView 处理各种通知,请求事件的。
WebViewClient mWebViewClient = new WebViewClient() {
//在网页上的所有加载都经过这个方法,这个函数我们可以做很多操作。
//比如获取url,查看url.contains(“add”),进行添加操作
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
// 21版本引入 同上
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
view.loadUrl(request.getUrl().toString());
return true;
}
//这个事件就是开始载入页面调用的,我们可以设定一个loading的页面,告诉用户程序在等待网络响应。
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
}
//在页面加载结束时调用。同样道理,我们可以关闭loading 条,切换程序动作。
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
}
// 在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。
@Override
public void onLoadResource(WebView view, String url) {
super.onLoadResource(view, url);
}
// 拦截替换网络请求数据, API 11开始引入,API 21弃用
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
return super.shouldInterceptRequest(view, url);
}
// 拦截替换网络请求数据, 从API 21开始引入
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
return super.shouldInterceptRequest(view, request);
}
//报告错误信息 API 21 废弃
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
}
//报告错误信息 API 21 引用
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
}
//接收http 错误信息
@Override
public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
super.onReceivedHttpError(view, request, errorResponse);
}
//应用程序重新请求网页数据
@Override
public void onFormResubmission(WebView view, Message dontResend, Message resend) {
super.onFormResubmission(view, dontResend, resend);
}
//更新历史记录
@Override
public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
super.doUpdateVisitedHistory(view, url, isReload);
}
//重写此方法可以让webview处理https请求。
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
super.onReceivedSslError(view, handler, error);
}
//获取返回信息授权请求
@Override
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
super.onReceivedHttpAuthRequest(view, handler, host, realm);
}
@Override
public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {
return super.shouldOverrideKeyEvent(view, event);
}
//Key事件未被加载时调用
@Override
public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
super.onUnhandledKeyEvent(view, event);
}
// WebView发生改变时调用
@Override
public void onScaleChanged(WebView view, float oldScale, float newScale) {
super.onScaleChanged(view, oldScale, newScale);
}
};
webView.setWebViewClient(mWebViewClient);
2.5 WebChromeClient 的介绍
WebChromeClient 是辅助WebView处理JavaScript对话框、网站图标、网站标题、加载进度等,下面方法中的代码都是android端自己处理。
WebChromeClient mWebChromeClient = new WebChromeClient() {
//获得网页的加载进度
@Override
public void onProgressChanged(WebView view, int newProgress) {
}
//获取Web页中的title用来设置自己界面中的title
//当加载出错的时候,比如无网络,这时onReceiveTitle中获取的标题为 找不到该网页,
//因此建议当触发onReceiveError时,不要使用获取到的title
@Override
public void onReceivedTitle(WebView view, String title) {
}
//获取Web页icon
@Override
public void onReceivedIcon(WebView view, Bitmap icon) {
//
}
//创建窗口
@Override
public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
//
return true;
}
//关闭窗口
@Override
public void onCloseWindow(WebView window) {
}
//处理alert弹出框,html 弹框的一种方式
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
//
return true;
}
//处理confirm弹出框
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult
result) {
//
return true;
}
//处理prompt弹出框
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
//
return true;
}
};
mWebView.setWebChromeClient (mWebChromeClient );
2.6 WebView常用的方法
2.6.1 前进、后退
webView.goBack();//后退
webView.goForward();//前进
//以当前的index为起始点前进或者后退到历史记录中指定的steps, 如果steps为负数则为后退,正数则为前进
// webView.goBackOrForward(intsteps);
webView.canGoForward();//判断是否可以前进
webView.canGoBack(); //判断是否可以后退
//按键事件
public boolean onKeyDown(int keyCode, KeyEvent event) {
//当点击的返回键 && webView可以回退
if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
webView.goBack(); //回退界面
return true;
}
//没有点击返回键或者webView不能回退就处理默认的事件
return super.onKeyDown(keyCode, event);
}
2.6.2 清除缓存数据
webView.clearCache(true);//清除网页访问留下的缓存,由于内核缓存是全局的因此这个方法不仅仅针对webview而是针对整个应用程序.
webView.clearHistory();//清除当前webview访问的历史记录,只会webview访问历史记录里的所有记录除了当前访问记录.
webView.clearFormData();//这个api仅仅清除自动完成填充的表单数据,并不会清除WebView存储到本地的数据。
2.6.3 WebView的状态
webView.onResume(); //激活WebView为活跃状态,能正常执行网页的响应
webView.onPause();//当页面被失去焦点被切换到后台不可见状态,需要执行onPause动过, onPause动作通知内核暂停所有的动作,比如DOM的解析、plugin的执行、JavaScript执行。
webView.pauseTimers();//当应用程序被切换到后台我们使用了webview, 这个方法不仅仅针对当前的webview而是全局的全应用程序的webview,它会暂停所有webview的layout,parsing,javascripttimer。降低CPU功耗。
webView.resumeTimers();//恢复pauseTimers时的动作。
webView.destroy();//销毁,关闭了Activity时,音乐或视频,还在播放。就必须销毁
注意点,当destroy调用destroy方法时,destroy仍然绑定在Activity上,这是因为构建自定义的webview时传入了该Activity的Context对象,因此需要从父容器中移除webview,再对webview进行destroy销毁。
3、使用HTTP协议访问网络
3.1 使用HttpURLConnection
3.1.1 GET请求
/**
* Get 请求
* @param mUrl
*/
private void sendRequestWithHttpURLConnection(final String mUrl){
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL(mUrl);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
connection.setDoInput(true);
connection.setDoOutput(true);
InputStream in = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(in));
StringBuilder respond = new StringBuilder();
String line;
while ((line = reader.readLine()) != null){
respond.append(line);
}
//将接口返回的数据处理
} catch (IOException e) {
e.printStackTrace();
}finally {
if (reader != null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (connection != null){
connection.disconnect();
}
}
}
}).start();
}
3.1.2 POST请求
/**
* post 请求
* @param mUrl
*/
private void sendRequestWithHttpURLConnection_post(final String mUrl){
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL(mUrl);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
connection.setDoInput(true);
connection.setDoOutput(true);
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.writeBytes("username=admin&password=123456");
InputStream in = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(in));
StringBuilder respond = new StringBuilder();
String line;
while ((line = reader.readLine()) != null){
respond.append(line);
}
//将接口返回的数据处理
} catch (IOException e) {
e.printStackTrace();
}finally {
if (reader != null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (connection != null){
connection.disconnect();
}
}
}
}).start();
}
3.1.3 HttpURLConnection基本封装工具类
/**HttpURLConnection工具类*/
public class NetUtils {
/**post请求*/
public static String post(String url, String content) {
HttpURLConnection conn = null;
try {
// 创建一个URL对象
URL mURL = new URL(url);
// 调用URL的openConnection()方法,获取HttpURLConnection对象
conn = (HttpURLConnection) mURL.openConnection();
conn.setRequestMethod("POST");// 设置请求方法为post
conn.setReadTimeout(5000);// 设置读取超时为5秒
conn.setConnectTimeout(10000);// 设置连接网络超时为10秒
conn.setDoOutput(true);// 设置此方法,允许向服务器输出内容
// post请求的参数
String data = content;
// 获得一个输出流,向服务器写数据,默认情况下,系统不允许向服务器输出内容
OutputStream out = conn.getOutputStream();// 获得一个输出流,向服务器写数据
out.write(data.getBytes());
out.flush();
out.close();
//获取服务器返回码 调用此方法就不必再使用conn.connect()方法
int responseCode = conn.getResponseCode();
if (responseCode == 200) { //200代表请求成功
InputStream is = conn.getInputStream();
String response = getStringFromInputStream(is);
return response;
} else {
throw new NetworkErrorException("response status is "+responseCode);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null) {
conn.disconnect();// 关闭连接
}
}
return null;
}
/**get请求*/
public static String get(String url) {
HttpURLConnection conn = null;
try {
// 利用string url构建URL对象
URL mURL = new URL(url);
conn = (HttpURLConnection) mURL.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
conn.setConnectTimeout(10000);
int responseCode = conn.getResponseCode();
if (responseCode == 200) {
InputStream is = conn.getInputStream();
String response = getStringFromInputStream(is);
return response;
} else {
throw new NetworkErrorException("response status is "+responseCode);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null) {
conn.disconnect();
}
}
return null;
}
// 把InputStream转换成String
private static String getStringFromInputStream(InputStream is)
throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
// 模板代码 必须熟练
byte[] buffer = new byte[1024];
int len = -1;
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
is.close();
// 把流中的数据转换成字符串,采用的编码是utf-8(模拟器默认编码)
String state = os.toString();
os.close();
return state;
}
}
3.2 使用OkHttp
3.2.1 GET请求
try {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://www.baidu.com")
.build();
Response response = client.newCall(request).execute();
String string = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
3.2.2 POST请求
try {
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.add("username", "admin")
.add("password", "123456")
.build();
Request request = new Request.Builder()
.url("http://www.baidu.com")
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
String string = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
4、解析XML格式数据
4.1 Pull解析方式
private String xml = "<apps>\n" +
"\t<app>\n" +
"\t\t<id>1</id>\n" +
"\t\t<name>1</name>\n" +
"\t\t<version>1</version>\n" +
"\t</app>\n" +
"\t<app>\n" +
"\t\t<id>1</id>\n" +
"\t\t<name>1</name>\n" +
"\t\t<version>1</version>\n" +
"\t</app>\n" +
"\t<app>\n" +
"\t\t<id>1</id>\n" +
"\t\t<name>1</name>\n" +
"\t\t<version>1</version>\n" +
"\t</app>\n" +
"</apps>";
private void parseXMLWithPull(String xmlData){
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();
}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(TAG,"id is:"+id);
Log.d(TAG,"name is:"+name);
Log.d(TAG,"version is:"+version);
}
break;
default:
break;
}
eventType = xmlPullParser.next();
}
} catch (Exception e) {
e.printStackTrace();
}
}
4.2 SAX解析方式
ContentHandler.java文件
public class ContentHandler extends DefaultHandler {
private static final String TAG = ContentHandler.class.getSimpleName();
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 {
super.startElement(uri, localName, qName, attributes);
//记录当前节点名
nodename = localName;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
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 {
super.endElement(uri, localName, qName);
if ("app".equals(localName)){
Log.d(TAG,"id is : "+id.toString().trim());
Log.d(TAG,"name is : "+name.toString().trim());
Log.d(TAG,"version is : "+version.toString().trim());
id.setLength(0);
name.setLength(0);
version.setLength(0);
}
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
private void parseXMLWithSAX(String xmlData){
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
XMLReader xmlReader = factory.newSAXParser().getXMLReader();
ContentHandler handler = new ContentHandler();
xmlReader.setContentHandler(handler);
xmlReader.parse(new InputSource(new StringReader(xmlData)));
} catch (SAXException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
5、解析JSON格式数据
5.1 使用JSONObject
private static final String jsonStr = "[\n" +
"\n" +
"{\"id\":\"5\",\"version\":\"5\",\"name\":\"5\"},\n" +
"{\"id\":\"6\",\"version\":\"6\",\"name\":\"6\"},\n" +
"{\"id\":\"7\",\"version\":\"7\",\"name\":\"7\"}\n" +
"\n" +
"]";
private void parseJSONWithJSONObject(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(TAG,"id is :"+id);
Log.d(TAG,"name is :"+name);
Log.d(TAG,"version is :"+version);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
6.2 使用GSON
可以将一段JSON格式的字符串自动转换成一个对象,从而不需要我们再去手动编写代码去解析了
implementation 'com.google.code.gson:gson:2.2.4'
5.2.1 解析一个json字符串(对象)
例如,{"name":"Tom","age":25}
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Gson gson = new Gson();
Person person = gson.fromJson(json_object, Person.class);
Log.d(TAG,"person.getName()============"+person.getName());
对于如下的数据,例如:
{
"code":"200",
"message":"success",
"data":
[
{"name":"Tom1","age":1},
{"name":"Tom2","age":2},
{"name":"Tom3","age":3}
]
}
上面的方法同样有效
5.2.2 解析一个json数组
例如:
[
{"name":"Tom1","age":1},
{"name":"Tom2","age":2},
{"name":"Tom3","age":3}
]
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Gson gson = new Gson();
List<Person> peoplelsit = gson.fromJson(json_arr,new TypeToken<List<Person>>(){}.getType());
6、网络编程的最佳实践
HttpCallbackListener.java文件
public interface HttpCallbackListener {
void onFinish(String response);
void onError(Exception e);
}
HttpUtil.java文件
public class HttpUtil {
public static void sendHttpRequest(final String address, final HttpCallbackListener listener) {
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
try {
URL url = new URL(address);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
connection.setDoInput(true);
connection.setDoOutput(true);
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);
}
if (listener != null) {
// 回调onFinish()方法
listener.onFinish(response.toString());
}
} catch (Exception e) {
if (listener != null) {
// 回调onError()方法
listener.onError(e);
}
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
}).start();
}
public static void sendOkHttpRequest(final String address, final okhttp3.Callback callback) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(address)
.build();
client.newCall(request).enqueue(callback);
}
}