个人笔记整理
使用网络技术
使用Http访问网络
使用HttpURLConnection
// new一个Url对象
URL url = new URL("http://www.baidu.com");
// new HttpURLConnection 新建连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 可设置请求方式 GET/POST
connection.setRequestMethod("GET");
// 设置连接超时毫秒数
connection.setConnectTimeout(8000);
// 设置读取超时毫秒数
connection.setReadTimeout(8000);
// 如果为POST,获取输出流
OutputStream os = connection.getOutputStream();
// 传入post参数
os.write("username=张三&age=20".getBytes());
// 获得输入流
InputStream in = connection.getInputStream();
// 进行字节流读取相关操作
// 关闭流
in.close();
os.close();
// 关闭连接
connection.disconnect();
使用OkHttp
导入依赖
编辑app/build.gradle
,添加依赖
dependencies {
compile 'com.squareup.okhttp3:okhttp:3.10.0'
}
使用
// 创建一个OkHttpClient的实例
OkHttpClient client = new OkHttpClient();
// 创建一个(空)Request 对象:
Request request = new Request.Builder().build();
// 或者在Builder中设置url
Request request = new Request.Builder()
.url("http://www.baidu.com")
.build();
// 之后调用OkHttpClient的newCall() 方法来创建一个Call 对象,并调用它的execute() 方法来发送请求并获取服务器返回的数据
Response response = client.newCall(request).execute();
// 得到Response返回的具体内容
String responseData = response.body().string();
// 如果为POST 我们需要先构建出一个Request Body对象来存放待提交的参数
RequestBody requestBody = new FormBody.Builder()
.add("username", "admin")
.add("password", "123456")
.build();
// Request.Builder中调用一下post() 方法,并将RequestBody 对象传入
Request request = new Request.Builder()
.url("http://www.baidu.com")
.post(requestBody)
.build();
// 调用execute() 方法来发送请求并获取服务器返回的数据即可。
get同步请求
// 创建OkHttpClient对象
OkHttpClient client = new OkHttpClient.Builder()
.cache() // 设置缓存目录(有默认)
.connectTimeout() // 设置连接超时(有默认)
.cookieJar() // cookie的读取,保存(需自己实现)
.build();
// 创建Request对象
Request request = new Request.Builder()
.url(address)
.build();
// 发送请求,获取响应
Call call = client.newCall(request);
// 发送同步请求,需手动创建子线程
new Thread(){
public void run(){
Response response = call.execute();//等待服务端进行响应(等待过程中会阻塞)
// 判断响应状态是否正常
if(response.isSuccessful()){
// 获取服务端响应的内容(文本)
String str = response.body().string();
}
}
}
get异步请求
//发送异步方式的get请求
private void getAsync(){
//2.创建请求对象
Request request = new Request.Builder()
.url(Constant.BASE_URL +
"LoginServlet?username=张三&password=123")
.build();
//3.发送请求,获取响应
Call call = okHttpClient.newCall(request);
//异步请求,不需要手动创建子线程
call.enqueue(new Callback(){
@Override
public void onFailure(Call call, IOException e) {
//请求失败时执行
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//请求成功时执行
Log.e("onResponse",Thread.currentThread().getName());
Log.e("异步get请求的结果",response.body().string());
//执行在子线程中,不能直接修改用户界面
//可以借助Handler实现
//在实现文件下载功能时,如何获取网络文件的数据
// InputStream is = response.body().byteStream();
// FileOutputStream fos = new FileOutputStream(
// getExternalFilesDir(null).getAbsolutePath() + "/a.jpg");
}
});
Log.e("okhttp","异步请求已发送");
}
异步post:发送文本
MIME 参考手册 (w3school.com.cn)
//异步方式的post请求,发送文本数据
private void postAsync(){
//2.创建请求体对象
RequestBody requestBody = RequestBody.create(
MediaType.parse("text/plain;charset=utf-8"), // 根据上传类型选择相应MIME
"username=张三&password=123");
//3.创建请求对象
Request request = new Request.Builder()
.url(Constant.BASE_URL + "LoginServlet")
.post(requestBody)//设置请求方式为POST
.build();
//4.发送请求,获取响应
Call call = okHttpClient.newCall(request);
//异步请求,不需要手动创建子线程
call.enqueue(new Callback(){
@Override
public void onFailure(Call call, IOException e) {
//请求失败时执行
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//请求成功时执行
Log.e("onResponse",Thread.currentThread().getName());
Log.e("异步get请求的结果",response.body().string());
//执行在子线程中,不能直接修改用户界面
//可以借助Handler实现
}
});
}
异步post:发送表单
//2.创建请求体对象
FormBody formBody = new FormBody.Builder()
.add("username","张三")
.add("password","123")
.build();
//3.创建请求对象
Request request = new Request.Builder()
.url(Constant.BASE_URL + "LoginServlet")
.post(formBody)//设置请求方式为POST
.build();
post本地选择文件上传
//文件上传
private void uploadFile(){
Intent intent = new Intent();
intent.setAction(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, 1);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1 && resultCode == RESULT_OK){
ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(data.getData(),
null,null,null,null);
if (cursor.moveToFirst()){
String imagePath = cursor.getString(cursor.getColumnIndex("_data"));
//创建请求体对象
File file = new File(imagePath);
RequestBody requestBody = RequestBody.create(
MediaType.parse("application/octet-stream"),
file);
//创建请求对象
Request request = new Request.Builder()
.url(Constant.BASE_URL + "UploadServlet")
.post(requestBody)
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.e("上传文件的结果",response.body().string());
}
});
}
}
}
post下载远端
@Override
public void onResponse(Call call, Response r) throws IOException{
InputStream is = response.body().byteStream();
File file = new File(Environment.getExternalStorageDirectory(),
"test.txt");
FileOutputStream fos = new FileOutputStream(file);
int len = 0;
byte[] buf = new byte[128];
while ((len = is.read(buf)) != -1){
fos.write(buf, 0, len);
}
}
解析XML格式数据
Pull解析方式
解析的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>
java代码
private void parseXMLWithPull(String xmlData) {
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
// 创建xmlPull解析器
// XmlPullParser parser = Xml.newPullParser();
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("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();
}
}
- 首先要获取到一个XmlPullParserFactory 的实例
- 借助这个实例得到XmlPullParser 对象
- 然后调用XmlPullParser 的setInput() 方法将服务器返回的XML数据设置进去就可以开始解析了。
- 解析的过程也非常简单,通过getEventType() 可以得到当前的解析事件
- 然后在一个while循环中不断地进行解析如果当前的解析事件不等于XmlPullParser.END_DOCUMENT,说明解析工作还没完成,调用next() 方法后可以获取下一个解析事件。
- 在while 循环中,我们通过getName() 方法得到当前节点的名字,如果发现节点名等于id、name或version,就调用nextText() 方法来获取节点内具体的内容,每当解析完一个app节点后就将获取到的内容打印出来。
SAX解析方式
模板
public class MyHandler extends DefaultHandler {
@Override
public void startDocument() throws SAXException {
// startDocument() 方法会在开始XML解析的时候调用
}
@Override
public void startElement(String uri, String localName, String qName, Attributes
attributes) throws SAXException {
// startElement() 方法会在开始解析某个节点的时候调用
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
// characters() 方法会在获取节点中内容的时候调用
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
// endElement() 方法会在完成解析某个节点的时候调用
}
@Override
public void endDocument() throws SAXException {
// endDocument() 方法会在完成整个XML解析的时候调用
}
}
解析上述XML
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 {
// 根据当前的节点名判断将内容添加到哪一个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)) {
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);
}
}
@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();
// 将ContentHandler的实例设置到XMLReader中
xmlReader.setContentHandler(handler);
// 开始执行解析
xmlReader.parse(new InputSource(new StringReader(xmlData)));
} catch (Exception e) {
e.printStackTrace();
}
}
解析JSON格式数据
测试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"}]
使用JSONObject
转成Json字符串
// JSONObject转json字符串
JSONObject jsonObject = new JSONObject();
jsonObject.put(String name,Object value);
jsonObject.put(String name,Object value);
String jsonStr = jsonObject.toString();
// 若是数组,写个循环生成JSONObject,然后用JSONArray对象的put方法
读取JSON字符串
private void parseJSONWithJSONObject(String jsonData) {
try {
// 读入JSON数组字符串 新建JSONArray对象
JSONArray jsonArray = new JSONArray(jsonData);
for (int i = 0; i < jsonArray.length(); i++) {
// 得到json对象
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);
}
} catch (Exception e) {
e.printStackTrace();
}
}
使用Gson
添加依赖
编辑app/build.gradle
文件,在dependencies
闭包中添加
compile 'com.google.code.gson:gson:2.8.5'
使用
Builder设置Gson属性
Gson gson = new GsonBuilder()
.serializeNulls() // 允许导出null
.setPrettyPrinting() // 格式化s
.setDateFormat("yyyy-MM-dd") // 设置日期输出格式
.create(); // 生成配置好的Gson对象
对象转json字符串
Gson gson = new Gson();
String jsonStr = gson.toJson(Object);
字符串直接解析对象
jsonData = """{"name":"Tom","age":20}"""
Gson gson = new Gson();
Person person = gson.fromJson(jsonData, Person.class);
Json字符串为对象数组
List<Person> people = gson.fromJson(jsonData, new TypeToken<List<Person>>() {}.getType());
网络编程实践
定义一个Http工具类
public class HttpUtil {
// 发送Http GET请求
public static String sendHttpRequest(String address) {
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);
}
return response.toString();
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
/**
* 封装好的post请求
*
* @param uri url
* @param parameters 请求参数
* @return post请求
*/
public static String sendPost(String uri, Map<String, String> parameters) {
StringBuffer postUrlSB = new StringBuffer(serverUrl + uri);
if (parameters != null) {
postUrlSB.append("?");
Set<Map.Entry<String, String>> entries = parameters.entrySet();
int count = 1;
int size = parameters.size();
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
if (count++ < size) {
postUrlSB.append(key).append("=").append(value).append("&");
} else {
postUrlSB.append(key).append("=").append(value);
}
}
}
String postUrl = postUrlSB.toString();
URL url = null;
HttpURLConnection connection = null;
String meg = null;
try {
url = new URL(postUrl);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-type", "text/plain;charset=UTF-8");
InputStream is = connection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
meg = br.readLine();
br.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
return meg;
}
}
开启子线程来接收返回值
Java回调机制
1. 定义一个HttpCallbackListener接口
public interface HttpCallbackListener {
void onFinish(String response);
void onError(Exception e);
}
- onFinish() 方法表示当服务器成功响应我们请求的时候调用:onFinish() 方法中的参数代表着服务器返回的数据。
- onError() 表示当进行网络操作出现错误的时候调用:onError() 方法中的参数记录着错误的详细信息。
2.修改原HttpUtil类
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();
}
}
我们首先给sendHttpRequest() 方法添加了一个HttpCallbackListener 参数
并在方法的内部开启了一个子线程,然后在子线程里去执行具体的网络操作。
子线程中是无法通过return语句来返回数据的,因此这里我们将服务器响应的数据传入了HttpCallbackListener的onFinish() 方法中,如果出现了异常就将异常原因传入到onError() 方法中。
现在sendHttpRequest() 方法接收两个参数了,因此我们在调用它的时候还需要将HttpCallbackListener的实例传入
HttpUtil.sendHttpRequest(address, new HttpCallbackListener() {
@Override
public void onFinish(String response) {
// 在这里根据返回内容执行具体的逻辑
}
@Override
public void onError(Exception e) {
// 在这里对异常情况进行处理
}
});
使用OkHttp
使用
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);
}
}
okhttp3.Callback :是OkHttp库中自带的一个回调接口
HttpUtil.sendOkHttpRequest("http://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) {
// 在这里对异常情况进行处理
}
});