Android中的访问网络
一.Android如何访问网络?
1.自带的HttpClientConnction,简称HttpClient
- 5.0之前一直使用的网络框架,但是5.0之后谷歌大爷就不推荐使用了,推荐了谁呢?就行下面那位.
2.自带的HttpUrlConnection
- 现在谷歌官网建议使用HttpUrlConnction框架,HttpURLConnection 原则上要比 httpclient快 ,但是httpclient分装了很多很好的东东,可以拿来就用,无需重复制造轮子。
1.Android使用HttpUrlConnection进行GET请求
1.Android使用HttpUrlConnection进行POST请求
二.如何解析服务器传来的JSON文件?
在我们的tomcat服务器里的Root目录放入我们的文件夹和文件:
1.解析Json对象
过程:
1.访问网络;
2.get或者post获取流文件;
3.流文件转成字符串形式;
4.通过JsonObject(JsonStr)得到对象;
5.再通过对象get("键")就能获取到想要的值;
- json名字是student.json,内容为:
{"name":"XiaoMing", "age":18, "city":"ShenZheng"}
- 解析代码
private void parseJson() {
new Thread(new Runnable() {
@Override
public void run() {
// student: {"name":"XiaoMing", "age":18, "city":"ShenZheng"}
try {
// url
URL url = new URL("http://10.0.2.2:8080/json/json/student.json");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// time
conn.setConnectTimeout(3000);
conn.setReadTimeout(3000);
// getOrPost
conn.setRequestMethod("GET");
InputStream is = conn.getInputStream();
// 刘变成字符串后续处理
String JsonStr = DataUtils.Stream2String(is);
/*--------------JsonObject--------------*/
//变成对象JsonObject
JSONObject object = new JSONObject(JsonStr);
String name = object.getString("name");
int age = object.getInt("age");
String city = object.getString("city");
System.out.println("name = " + name + ", age = " + age + ", city = " + city);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
输出结果:
System.out: name = XiaoMing, age = 18, city = ShenZheng
2.解析Json数组,及数组中对象
- 文件名字为students.json,内容如下
[
{"name":"XiaoMing", "age":18, "city":"ShenZheng"},
{"name":"XiaoMing2", "age":19, "city":"ShenZheng2"},
{"name":"XiaoMing3", "age":20, "city":"ShenZheng3"}
]
- 解析过程和上面的区别:
得到字符串后通过JsonArray(jsonStr)得到数组,数组里是一个一个对象.
想更改路径:
URL url = new URL("http://10.0.2.2:8080/json/json/student.json");
- 代码如下
/*--------------JsonArray--------------*/
// 变成JsonArray
JSONArray array = new JSONArray(JsonStr);
// 获取第几组对象
for (int i = 0; i < array.length(); i++) {
JSONObject object = array.getJSONObject(i);
System.out.println(
" name : " + object.get("name") +
", age : " + object.get("age") +
", city : " + object.get("city"));
}
输出结果:
System.out: name : XiaoMing, age : 18, city : ShenZheng
System.out: name : XiaoMing2, age : 19, city : ShenZheng2
System.out: name : XiaoMing3, age : 20, city : ShenZheng3
2.解析Json数组里的Json对象,再解析Json对象里的Json数组,再得到对象.
- json的名字为studentss.json,内容如下(格式必须要正确,括号逗号):
[
{"name":"XiaoMing", "age":18, "city":"ShenZheng"},
{"name":"XiaoMing2", "age":19, "city":"ShenZheng2"},
{"name":"XiaoMing3", "age":20, "city":"ShenZheng3"},
{"money":
[
{"area":"A","totalmoney":16000,"before":15000,"other":1000},
{"area":"B","totalmoney":16000,"before":16000,"other":1000},
{"area":"C","totalmoney":15000,"before":14000,"other":1000}
]
}
]
- 解析过程:
通过观察发现:
- 1.数组的长度是4,前三组一样都是json对象,所以可以做相同出来
- 2.第四组特殊,先获取数组的第四个对象,然后获取对象里的数组,然后再循环数组里的对象在解析即可.
代码如下
/*--------------JsonArray++ --------------*/
// 获取数组中的数组(有4组,前三组一样,第四组不同)
JSONArray array = new JSONArray(JsonStr);
//先解析同样的前三组
for (int i = 0; i < array.length() - 1; i++) {
JSONObject object = array.getJSONObject(i);
System.out.println(
" name : " + object.get("name") +
", age : " + object.get("age") +
", city : " + object.get("city"));
}
//从数组中获取"对象"最后一个
JSONObject obj = array.getJSONObject(array.length() - 1);
//有从"对象中获取数组"
JSONArray arrayy = obj.getJSONArray("money");
for (int a = 0; a < arrayy.length(); a++) {
JSONObject object = arrayy.getJSONObject(a);
System.out.println(
" area = " + object.get("area") +
", totalmoney = " + object.get("totalmoney") +
", before = " + object.get("before") +
", other = " + object.get("other"));
}
输出结果:
System.out: name : XiaoMing, age : 18, city : ShenZheng
System.out: name : XiaoMing2, age : 19, city : ShenZheng2
System.out: name : XiaoMing3, age : 20, city : ShenZheng3
System.out: area = A, totalmoney = 14000, before = 15000, other = 1000
System.out: area = B, totalmoney = 15000, before = 16000, other = 1000
System.out: area = C, totalmoney = 13000, before = 14000, other = 1000
三.如何生成的JSON文件?
1.生成json对象-通过Map:
过程:
- 1.通过一个 Map添加不同的键和值.
- 2.json对象构造传入即可
2.生成json对象-直接put添加:
- 过程:
- 直接通过json对象put键和值即可
3.生成json数组-Map结合List
- 过程:
- 1.通过多个 Map添加不同 的键和值
- 2.新建一个 List,并添加这多个 Map
代码如下:
/**
* 生成Json
*/
private void createJson() {
new Thread(new Runnable() {
@Override
public void run() {
try {
/*--------------生成json对象:通过HashMap--------------*/
HashMap<String, String> hm = new HashMap<>();
hm.put("name", "小何");
hm.put("age", "18");
hm.put("score", "99");
// Json对象构造传入
JSONObject object = new JSONObject(hm);
System.out.println(
"name = " + object.get("name") +
", age = " + object.get("age") +
", score = " + object.get("score"));
/*------------生成json对象:直接通过对象.put----------------*/
JSONObject objec = new JSONObject();
objec.put("name", "小何");
objec.put("age", "18");
objec.put("score", "99");
System.out.println(
"name = " + objec.get("name") +
", age = " + objec.get("age") +
", score = " + objec.get("score"));
/*------生成Json数组:通过HashMap生成对象,再通过ArrayList添加过个对象,最终Json数组构造传入------*/
Map<String, String> m1 = new HashMap<>();
m1.put("name", "小何");
m1.put("age", "18");
m1.put("score", "99");
Map<String, String> m2 = new HashMap<>();
m2.put("name", "小路");
m2.put("age", "18");
m2.put("score", "99");
Map<String, String> m3 = new HashMap<>();
m3.put("name", "小高");
m3.put("age", "18");
m3.put("score", "99");
List<Map<String, String>> list = new ArrayList<>();
list.add(m1);
list.add(m2);
list.add(m3);
JSONArray array = new JSONArray(list);
for (int i = 0; i < array.length(); i++) {
JSONObject obj = array.getJSONObject(i);
System.out.println(
obj.get("name") + ", " +
obj.get("age") + ", " +
obj.get("score"));
}
/*---------------增强版,添加对象,以及包含数组的对象-------------*/
//lis先放前两个对象
List<Map> lis = new ArrayList<Map>();
Map h1 = new HashMap();
h1.put("name", "小明");
h1.put("age", 11);
Map h2 = new HashMap();
h2.put("name", "小明");
h2.put("age", 11);
lis.add(h1);
lis.add(h2);
//有数组的对象
Map h3 = new HashMap();
h3.put("info", lis);
//listAll放三个对象,第三个对象里有数组
List listAll = new ArrayList();
listAll.add(h1);
listAll.add(h2);
listAll.add(h3);
JSONArray jsonArray = new JSONArray(listAll);
//通过toString 就能得到json内容;
String s = jsonArray.toString();
System.out.println(s);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
打印结果:
/*--------------生成json对象:通过HashMap--------------*/
07-11 03:33:03.420 30275-30289/? I/System.out: name = 小何, age = 18, score = 99
/*------------生成json对象:直接通过对象.put----------------*/
07-11 03:33:03.420 30275-30289/? I/System.out: name = 小何, age = 18, score = 99
/*---------生成Json数组:通过HashMap生成对象,再通过ArrayList添加过个对象,最终Json数组构造传入---------*/
07-11 03:33:03.424 30275-30289/? I/System.out: 小何, 18, 99
07-11 03:33:03.424 30275-30289/? I/System.out: 小路, 18, 99
07-11 03:33:03.424 30275-30289/? I/System.out: 小高, 18, 99
07-11 03:33:03.424 30275-30289/?
/*---------------增强版,添加对象,以及包含数组的对象-------------*/
I/System.out:
[
{"name":"小明","age":11},
{"name":"小明","age":11},
{"info":
[
{"name":"小明","age":11},
{"name":"小明","age":11}
]
}
]
四.如何解析服务器传来的XML格式的数据?
(在服务器放好文件,然后get/post请求获取数据,接着解析)
- 1.获取pull解析对象.
- 2.设置读取流,以及格式
- 2.获取解析对象的类型.
- 4.循环从头部开始,即while循环不等于最后文档/文件类型.
- 5.获取标签名,然后如果等于自己想要的内容,就输出下一个文本
- 6.然后解析完一个类型接着下一个类型:type = pull.next();
xml文件名为sutdent.xml,内容如下
<students>
<student>
<name>zhangsan</name>
<age>18</age>
<score>98</score>
</student>
<student>
<name>lishi</name>
<age>29</age>
<score>97</score>
</student>
</students>
解析的代码如下:
/*--------------解析XML--------------*/
try {
// 1.获取Pull解析工具对象
XmlPullParser pull = Xml.newPullParser();
// 2.设置输入流,编码
pull.setInput(is, "utf-8");
//3.获取类型
int type = pull.getEventType();
//解析循环到底
while (type != XmlPullParser.END_DOCUMENT) {//不是最后一个文件
//<name>zhangsan</name>只考虑第name后面取
//5.获取标签名
if ("name".equals(pull.getName())) {
//获取下一个文本
String name = pull.nextText();
System.out.println(name);
} else if ("age".equals(pull.getName())) {
String age = pull.nextText();
System.out.println(age);
} else if ("score".equals(pull.getName())) {
String score = pull.nextText();
System.out.println(score);
}
//4.解析下一个事件,来到了开头,如果忘记写就不能往下了,一个都读不到.死循环
type = pull.next();
}
} catch (Exception e) {
e.printStackTrace();
}
输出结果为:
System.out: zhangsan
System.out: 18
System.out: 98
System.out: lishi
System.out: 29
System.out: 97
五.如何生成的XML文件?
步骤:
- 1.获取序列化对象
- 2.设置输出流以及格式
- 3.声明开始文档/文件
- 4.开始写开始标签和结束标签(有多少写多少,只要对应即可)
- 5.最后声明一个结束文档即可
需求:
想要生成一个如下的xml
<?xml version="1.0" encoding="UTF-8"?>
<students>
<student>
<name>zhangsan</name>
<age>18</age>
<score>98</score>
</student>
<student>
<name>lishi</name>
<age>29</age>
<score>97</score>
</student>
</students>
代码如下:
private void createXML() {
/*--------------生成xml--------------*/
try {
//1.生成序列化对象,刚才是解析,这里是序列化
XmlSerializer ser = Xml.newSerializer();
//2.设置输出流
File dir = new File("data/data/" + getPackageName() + "/" + "xml/");
if (!dir.exists()) {
dir.mkdir();
}
File file = new File(dir, "create.xml");
FileOutputStream fos = new FileOutputStream(file);
//先指定输出位置,否则下面的开始文档会空指针.
ser.setOutput(fos, "utf-8");
//3.声明开始文件(包含编码格式,还有是否独立)
ser.startDocument("utf-8", true);
/*
<?xml version="1.0" encoding="UTF-8"?>
<students>
<student>
<name>zhangsan</name>
<age>18</age>
<score>98</score>
</student>
<student>
<name>lishi</name>
<age>29</age>
<score>97</score>
</student>
</students>
*/
//4.开始标签
ser.startTag("", "students");
ser.startTag("", "student");
ser.startTag("", "name");
//内容:text
ser.text("zhangshan");
ser.endTag("", "name");
//5.结束标签
ser.startTag("", "age");
ser.text("18");
ser.endTag("", "age");
ser.startTag("", "score");
ser.text("98");
ser.endTag("", "score");
ser.endTag("", "student");
ser.startTag("", "student");
ser.startTag("", "name");
ser.text("lishi");
ser.endTag("", "name");
ser.startTag("", "age");
ser.text("29");
ser.endTag("", "age");
ser.startTag("", "score");
ser.text("97");
ser.endTag("", "score");
ser.endTag("", "student");
ser.endTag("", "students");
//6.结束文件:加上结束文档,否则输出不了
ser.endDocument();
} catch (IOException e) {
e.printStackTrace();
}
}
生成文件:
文件内容为:
<?xmlversion='1.0'encoding='utf-8'standalone='yes'?>
<students>
<student>
<name>zhangshan</name>
<age>18</age>
<score>98</score>
</student>
<student>
<name>lishi</name>
<age>29</age>
<score>97</score>
</student>
</students>
四.如何从”本地和网络上”加载一个大图片显示到界面,而且要避免OOM?
思路:
- 归根结底就是不要把图片马上存到内存,而是放置符合屏幕或者自定义大小的图片.
- 1.目的都是获取图片的信息,然后获取然后再根据我们的自定义比例,重新再设置图片并加载到内存
- 2.要区别本地加载大图片和网络加载大图片
- 1.本地加载大图片:可以同同一个option,同一个解析
- 2.网络加载大图片:要进行两次访问:
- 第一次获取图片的不存入内存,而是只要获取长宽
- 第二次获取图片,设定比例,然后存入内存,最终显示图片
- 设置图片比例,选择长的一边比例占据;
读取本地图片:
详细代码如下:
/**
* 读取本地发图片的方法:
*
* 用标准的做法即可:
*
* 1.图片不存入内存,只想获取宽高 just = true;
* 2.解析图片,并且带入"选项",就可以下一步获取比例了
* 3.获取图片和屏幕的比例,并设置"选项"的比例;
* 4.存入内存 just = false;
* 5.再解析图片->显示即可;
*/
private void reateLocalPic() {
new Thread(new Runnable() {
@Override
public void run() {
/*--------------不存内存,获取比例--------------*/
BitmapFactory.Options opt = new BitmapFactory.Options();
//1.
opt.inJustDecodeBounds = true;
String path = "data/data/" + getPackageName() + "/files/" + "big.png";
//2.
BitmapFactory.decodeFile(path, opt);
//3.
int outHeight = opt.outHeight;
int outWidth = opt.outWidth;
Display display = getWindowManager().getDefaultDisplay();
int height = display.getHeight();
int width = display.getWidth();
int sH = (int) (outHeight / (float) height + 0.5f);
int sW = (int) (outWidth / (float) width + 0.5f);
int sample = 1;//原来的大小
if (sH > 1 && sW > 1) {
sample = sH > sW ? sH : sW;
}
opt.inSampleSize = sample;
/*------------存入内存,显示图片----------------*/
//4.
opt.inJustDecodeBounds = false;
//5.
final Bitmap bitmap = BitmapFactory.decodeFile(path, opt);
runOnUiThread(new Runnable() {
@Override
public void run() {
mIv.setImageBitmap(bitmap);
}
});
}
}).start();
}
读取网络图片:
详细代码如下:
/**
* 读取网络图片:
* 思维和读取本地是一样的,但是注意:
* 但是当计算出缩放比再通过
* 1.设置比例,
* 2.存入内存,
* 3.解析流放入选项,一样的过程时,发现居然不显示图片:
* <p/>
* 日志发现输出一行SkImageDecoder::Factory returned null信息,返回的是空对象,
* 原因:
* 代码中两次使用了BitmapFactory.decodeStream(is, outPadding, options)方法,
* 即两次使用了同一个InputStream流对象,
* 在第二次使用时流的起始位置已经移动到末尾了,所以返回的是空
* <p/>
* 解决:
* 访问两次网络:
* 第一次获取流,不存内存获取图片比例
* 第二次获取流,设置比例,存内存,显示图片
*/
private void readNetPic() {
new Thread(new Runnable() {
@Override
public void run() {
try {
/**
* 第一次访问网络,获取图片的大小和屏幕的比例
* 获取适应屏幕的图片的大小
*/
/*--------------第一次访问:不存内存,获取比例--------------*/
URL url = new URL("http://10.0.2.2:8080/json/imgs/big.png");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// time
conn.setConnectTimeout(3000);
conn.setReadTimeout(3000);
// getOrPost
conn.setRequestMethod("GET");
InputStream is = conn.getInputStream();
//获取屏幕高宽
Display display = getWindowManager().getDefaultDisplay();
int okH = display.getHeight();//也是目标尺寸
int okW = display.getWidth();
System.out.println("屏幕 高 : " + okH + ", 屏幕 宽 : " + okW);
BitmapFactory.Options opt = new BitmapFactory.Options();
//只获取图片信息
opt.inJustDecodeBounds = true;
//解析并放入选项下面才能获取图片的高,否则空指针
BitmapFactory.decodeStream(is, null, opt);
//读取图片的高,宽
int outHeight = opt.outHeight;
int outWidth = opt.outWidth;
System.out.println("图片 高 : " + outHeight + ", 图片 宽 : " + outWidth);
//求图片的高和屏幕的高的比例,宽度也一样
int sh = (int) (outHeight / (float) okH + 0.5f);
int sw = (int) (outWidth / (float) okW + 0.5f);
//对比比例大的,最好了比喻:竖直的屏幕,横向的大图,保存的当然是大的横向才能显示完.
System.out.println("高度比 : " + sh + ", 宽度比 : " + sw);
int sample = 1;
if (sh >= 1 && sw >= 1) {
sample = sh > sw ? sh : sw;
}
/*--------------第二次访问:存内存,设置比例,显示图片--------------*/
setPicAndShow(sample);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 第二次请求,显示图片
* @param sample
* @throws Exception
*/
private void setPicAndShow(int sample) throws Exception {
URL url = new URL("http://10.0.2.2:8080/json/imgs/big.png");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// time
conn.setConnectTimeout(3000);
conn.setReadTimeout(3000);
// getOrPost
conn.setRequestMethod("GET");
InputStream is = conn.getInputStream();
BitmapFactory.Options opt = new BitmapFactory.Options();
//设置比例
opt.inSampleSize = sample;
System.out.println(sample);
//出人内存
opt.inJustDecodeBounds = false;
final Bitmap bitmap = BitmapFactory.decodeStream(is, null, opt);
runOnUiThread(new Runnable() {
@Override
public void run() {
mIv.setImageBitmap(bitmap);
}
});
}
}).start();
}
五.如何播放网络视频?
VideoView封装了类对MediaPlayer进行调用,前者是个控件,后者是播放音频/视频的具体内部部件
VideoView 调用了 MediaPlayer 来播放视频,提供了一些视频播放的辅助功能。
1.播放本地和网上音乐
(网上资源加权限)
1.获取MediaPlayer对象
2.对象准备
(或者直接采用异步准备+准备监听+把播放内容放到监听里即可)
3.对象播放
4.后续的进度保存可以自定义设置
2.播放本地和网上视频
(网上资源要加权限)
- 1.用VideoView控件
- 1.设置路径
- 2.设置控制器
- 3.控制器设置绑定View(控件),
- 4.控件设置控制器
- 5.开始即可
- 2.用MediaPlayer和SurView结合
- 1.设置和获取Serview控件
- 2.得到控件的控制器holder
- 3.控制器设置回调-创建和销毁
- 4.在回调的创建里创建mediaplayer
- 5.才销毁的时候存sp进度
- 6.下次先获取进度再播放
- *
3.万能第三方开源播放器 vitamioPlayer
兼容性好,几乎兼容所有的格式;生命周期和mediaplayer一样,非常好用
六.常见的访问网络API都有哪些?
xUtils:
老牌控件:底层是httpclient
volley:
谷歌2013发布,使得更快,简单,健壮.
okhttp:
谷歌工程师写的