🍀【Android】8.0网络请求数据与JSON解析
注意:不是教程只是笔记,如有错误欢迎批评指正
🍁网络请求权限
既然需要访问网络自然需要网络请求权限
<uses-permission android:name="android.permission.INTERNET"/>
除此之外还需要加上这一行,否则http的网页请求不成功
android:usesCleartextTraffic="true"
🌳网络请求
网络在主线程异常
这段代码是网络请求数据,http://121.4.44.56/user 这是老师提前发在网上的数据文件,可通过这个网址访问,其中的数据是:
try {
URL url = new URL("http://121.4.44.56/user");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
InputStream inputStream = urlConnection.getInputStream();
Reader reader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(reader);
String result = "";
String temp;
while ((temp = bufferedReader.readLine()) != null) {
result += temp;
}
Log.i("MainActivity", result);
inputStream.close();
reader.close();
bufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
将这段代码放在主线程下执行会出现警告warn
W/System.err: android.os.NetworkOnMainThreadException
网络在主线程异常-》网络请求不能在主线程
生命周期中执行的方法默认是主线程(UI线程)不能执行耗时的操作
耗时操作-》such as:
读取文件(读数据库)、网络请求
子线程网络请求
因此我们需要创建一个子线程来访问网络数据,并且在子线程中将获取到的数据显示在TextView 控件上
Thread thread=new Thread(){
@Override
public void run() {
super.run();
try {
URL url = new URL("http://121.4.44.56/user");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
InputStream inputStream = urlConnection.getInputStream();
Reader reader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(reader);
String result = "";
String temp;
while ((temp = bufferedReader.readLine()) != null) {
result += temp;
}
Log.i("MainActivity", result);
textView.setText(result);
inputStream.close();
reader.close();
bufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
};
thread.start();
运行发现虚拟机上只显示一部分数据,查看日志窗口发现:
线程切换
出现警告:在错误的线程中执行
W/System.err: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
原因: 对于UI控件的操作不能放在子线程中->需要放到主线程中执行->线程切换
不能直接在主线程中设置,因为主线程和子线程是一起运行的,它们在运行时是无法人为预知的
在子线程中通过runOnUiThread(new Runnable() 实现线程切换
String finalResult=result;
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText(finalResult);
}
});
🌺JSON数据解析
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
问题:网络请求是耗时的,那么如何一次请求到所有的数据呢?
如图一次请求到年龄,姓名和是否是学生三个数据,但是我们只需要姓名,我们就只需要通过JSON解析字符串,再通过 键名 获取到姓名
基本类型
json 数据结构的特点:"key":value
try {
JSONObject jsonObject=new JSONObject(finalResult);
String name=jsonObject.getString("name");
textView.setText(name);
} catch (JSONException e) {
e.printStackTrace();
}
json字符串的数据结构可以是浮点型,整型,长整型,字符串型,布尔型 ,数组类型,josn类型,class类型等等
json类型
json数据结构还可以是json类型的,这种情况需要嵌套解析,http://121.4.44.56/object1 文件里的内容如下:
{ "age":20,"name":"张三", "isstudent":true,"class":{"grade":"18级","classname":"计算机科学与技术"} }
JSONObject jsonObject=new JSONObject(finalResult);
JSONObject classObj=jsonObject.getJSONObject("class");
String className=classObj.getString("classname");
数组类型
json数据结构还可以数数组类型,http://121.4.44.56/object2 文件里的内容如下:
{ "grade":"18级","classname":"计算机科学与技术","students":["张三","李四","王五"] }
JSONObject jsonObject=new JSONObject(finalResult);
JSONArray jsonArray= jsonObject.getJSONArray("students");
for(int i=0;i<jsonArray.length();++i){
String student=jsonArray.getString(i);
Log.i("Students","student = "+student);
}
json数组类型
再复杂一丢丢,json数组类型,http://121.4.44.56/object3 文件里的内容如下:
{ "grade":"20级","classname":"计算机科学与技术",
"students":[
{ "id":"001","age":30,"name":"张三", "isstudent":false },
{ "id":"002","age":25,"name":"李四111", "isstudent":true },
{ "id":"003","age":26,"name":"王1111五", "isstudent":true }
]}
JSONArray jsonArray= jsonObject.getJSONArray("students");
for(int i=0;i<jsonArray.length();++i){
JSONObject studentobj=jsonArray.getJSONObject(i);
String name=studentobj.getString("name");
Integer age=studentobj.getInt("age");
Log.i("MainActivity","name = "+name+" age = "+age);
}
学习要求:会解析json数据结构,会构json造数据结构
例如京东列表:
{"list":[{"name":iphone12,"price":6799},{"name":iphone12 plus,"price":7988},{},{}]}
🌷第三方框架 gson
google/gson:一个Java序列化/反序列化库,用于将Java Objects转换为JSON并返回 (github.com)
优点
- 直接将字符串解析成对象
- 解析成为一个实体类
添加依赖
implementation 'com.google.code.gson:gson:2.9.0'
创建一个实体类
实体类要求字段的名称和类型严格一致
{ "age":30,"name":"张三", "isstudent":true }
使用GSON框架解析
普通json数据类型类
Gson gson=new Gson();
Student student=gson.fromJson(finalResult,Student.class);
Log.i("MainActivity", "run: "+student.name);
嵌套json类型实体类
如果是json类型嵌套实体类,那么实体类应该做如下修改:
{ "age":20,"name":"张三", "isstudent":true,"class":{"grade":"18级","classname":"计算机科学与技术"} }
json数据类型对应java的类,所以嵌套的json结构,改写成实体类时也是嵌套的类(内部类),除此之外还要声明这个内部类,因为这里键名是class与java的关键字冲突,所以要注解"class",然后换个变量名
在MainActivity 的子线程中解析数据并打印
json数组实体类
通常使用java集合类中的List可变数组定义json数据结构中的数组
实体类插件GsonFormatPlus
GSON框架虽然简化了我们解析数据的过程,但是需要书写一个实体类又给我们添加了麻烦,可以通过如下插件一键生成json数据结构的实体类
安装
打开
设置
使用
在左侧粘贴json数据结构的字符串,然后ok即可
MainActivity完整代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView=findViewById(R.id.textView);
Log.i("MainActivity", "test1 ");
Thread thread=new Thread(){
@Override
public void run() {
super.run();
try {
URL url = new URL("http://121.4.44.56/user");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
InputStream inputStream = urlConnection.getInputStream();
Reader reader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(reader);
String result = "";
String temp;
while ((temp = bufferedReader.readLine()) != null) {
result += temp;
}
Log.i("MainActivity", result);
Log.i("MainActivity", "test3 ");
String finalResult=result;
runOnUiThread(new Runnable() {
@Override
public void run() {
Gson gson=new Gson();
Student student=gson.fromJson(finalResult,Student.class);
Log.i("MainActivity", "run: "+student.students.get(0).name+" "+
student.students.get(0).id);
try {
JSONObject jsonObject=new JSONObject(finalResult);
String name=jsonObject.getString("name");
textView.setText(name);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
inputStream.close();
reader.close();
bufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
};
thread.start();
Log.i("MainActivity", "test2 ");
}
}
Student类完整代码
public class Student{
public String grade;
public String classname;
public List<MyStudent> students;
public class MyStudent{
public String id;
public int age;
public String name;
public boolean isstudent;
}
}
|