以下代码模拟了点击按钮请求百度的网页源码:其中需要注意的是Android在API27之后不再支持明文访问HTTP,需要在manifest文件中配置属性允许使用明文访问,并且Url需要使用https
layout.xml
<LinearLayout 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=".MainActivity" android:orientation="vertical"> <Button android:id="@+id/web_btn1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="点击获取百度页面" android:textSize="20sp" android:layout_marginBottom="5dp" android:onClick="getHttpText"/> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/web_tv1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> ScrollView> LinearLayout>
字节流转换字符串工具类:
public class HttpInputStreamParse { public static String parseInput(InputStream in) throws IOException { StringBuilder sb = new StringBuilder(); BufferedReader br = new BufferedReader(new InputStreamReader(in)); String temp; while((temp = br.readLine())!= null){ sb.append(temp); } return sb.toString(); } }
主类.java:
public class MainActivity extends AppCompatActivity { private static final String HTTP_ADDRESS = "https://www.baidu.com"; private TextView tv1; private WebView wb1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv1 = findViewById(R.id.web_tv1); //wb1 = findViewById(R.id.webview1); } public void getHttpText(View view) { // wb1.loadUrl(HTTP_ADDRESS); // wb1.setWebViewClient(new WebViewClient(){ // @Override // public boolean shouldOverrideUrlLoading(WebView view, String url) { // view.loadUrl(url); // return true; // } // }); new Thread(new Runnable() { @Override public void run() { try { URL url = new URL(HTTP_ADDRESS); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(5000); connection.connect(); int code = connection.getResponseCode(); if (code != HttpURLConnection.HTTP_OK) { Log.d("NETWORK",code+""); }// 200; InputStream inputStream = connection.getInputStream(); final String rec = HttpInputStreamParse.parseInput(inputStream); runOnUiThread(new Runnable() { @Override public void run() { tv1.setText(rec); } });//这里使用handler也可以与主线程通信 } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }).start(); } }
配置manifest.xml文件:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.hait.cs.networkdemo"> <uses-permission android:name="android.permission.INTERNET">uses-permission> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.NetworkDemo" android:usesCleartextTraffic="true" > <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> intent-filter> activity> application> manifest>
将上述代码中的webview相关内容解除注释即可得到一个显示的网页,webview的内容显示会将下方源码挤出布局空间。
同时可以使用webview处理添加html和JavaScript文件,这里不再赘述。
可以在AS中的main文件夹下生成assets文件夹注意不要写错,将Json数据添加至此(在assets文件夹下新建文件后缀xxx.json即可),调用this.getResources().getAssets().open("json路径名")
获得一个InputStream
对象,转成字符串后可以调用JSONObject
对象的optXXX()
方法解析Json中的key值从而得到value的值,需要注意数据类型。
json对象:
{ "name": "张三", "age" : 24, "married":false }
json对象数组
[ {"name": "张三", "age" : 24, "married":false }, {"name": "阿珍", "age" : 25, "married":true }, {"name": "阿强", "age" : 26, "married":true } ]
其中json对象中的属性可以是一个json对象,例如添加属性”address“,其可以是一个json对象包含省,市,区等多个属性
除此之外,json对象的属性也可以是一个数组,例如属性"hobby"可以是[ 唱、跳、rap、篮球 ]
可以使用一些软件模拟在线的json请求,例如postman和apipost等。
以下代码演示了如何解析一个json对象,布局文件省略,大致是点击按钮,解析asset文件夹下的一个json对象文件,将解析结果用textview展示出来。
主类.java
public class JsonParseActivity extends AppCompatActivity { private TextView tv1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_json_parse); tv1 = findViewById(R.id.json_tv1); } public void parseJson(View view) { try { InputStream open = this.getResources().getAssets().open("weather.json"); String json = HttpInputStreamParse.parseInput(open); JSONObject jsonObject = new JSONObject(json); String name = jsonObject.optString("name"); int age = jsonObject.optInt("age"); String married = jsonObject.optString("married"); tv1.setText(name+":"+age+":"+married); } catch (IOException | JSONException e) { e.printStackTrace(); } } }
解析Json数组:使用JsonArray获取输入流,之后遍历数组即可
parseJsons方法
public void parseJsons(View view) { try { InputStream open = this.getResources().getAssets().open("persons.json"); String jsons = HttpInputStreamParse.parseInput(open); JSONArray jsonArray = new JSONArray(jsons); StringBuilder sb = new StringBuilder(); for (int i = 0; i< jsonArray.length();i++){ JSONObject jsonObject = jsonArray.getJSONObject(i); String name = jsonObject.optString("name"); int age = jsonObject.optInt("age"); String married = jsonObject.optString("married"); sb.append(name+":"+age+":"+married); sb.append("\n"); } tv2.setText(sb.toString()); } catch (IOException | JSONException e) { e.printStackTrace(); } }
使用google开发的第三方库Gson来解析json文件。
添加Gson依赖:选择module,open module settings,dependencies,添加依赖,输入关键字gson*添加对应版本的依赖库。
Gson解析时可以直接将json字符串转换为一个实体类对象,因此可以创建一个pojo包,将待解析的json文件按照对应属性来创建java bean类。
这里可以选择添加插件 gsonformat 或 gsonformat plus,在file选项卡下的settings内选择plugin选项卡搜索对应插件安装即可(mac os选择 Android Studio选项卡下的preference选项,选择plugin并搜索)。
pojo java bean: PersonBean.java
public class PersonBean { private String name; private int age; private boolean married; 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; } public boolean isMarried() { return married; } public void setMarried(boolean married) { this.married = married; } }
使用gson解析json对象:直接给按钮写响应,在布局中构建onClick响应函数parseGson,在主类中创造此方法。
public void parseGson(View view) { try { Gson gson = new Gson(); InputStream open = this.getResources().getAssets().open("weather.json"); String json = HttpInputStreamParse.parseInput(open); PersonBean personBean = gson.fromJson(json, PersonBean.class); String name = personBean.getName(); String age = String.valueOf(personBean.getAge()); String married = String.valueOf(personBean.isMarried()); tv1.setText(name+":"+age+":"+married); } catch (IOException e) { e.printStackTrace(); } }
上述做法直接转换为类对象
使用gson解析json数组:直接给按钮写响应,在布局中构建onClick响应函数parseGsons,在主类中创造此方法。
public void parseGsons(View view) { try { InputStream open = this.getResources().getAssets().open("persons.json"); String json = HttpInputStreamParse.parseInput(open); Gson gson = new Gson(); Type type = new TypeToken<List<PersonBean>>(){}.getType(); List<PersonBean> personList = gson.fromJson(json, type); StringBuilder sb = new StringBuilder(); for (PersonBean pb:personList){ String name = pb.getName(); String age = String.valueOf(pb.getAge()); String married = String.valueOf(pb.isMarried()); sb.append(name+":"+age+":"+married); sb.append("\n"); } tv2.setText(sb.toString()); } catch (IOException e) { e.printStackTrace(); } }
上述代码关键语句在构建type对象,new出TypeToken的实例获取type对象,将json数组转成javabean泛型的集合。最后遍历集合进行操作即可。
附加问题:更加复杂的json文件进行解析,例如json文件:
[ { "name": "zhangsan", "age": 18, "married": false, "zhifubao": { "account": "zhangsan", "balance": 10000 }, "hobby": ["sing","dance","basketball"] }, { "name": "lisi", "age": 19, "married": false, "zhifubao": { "account": "lisi", "balance": 20000 }, "hobby": ["idol","rap","walking-dead"] } ]
上述文件是一个json数组,数组内两个json对象,其中json对象中属性“zhifubao”又是一个json对象,且属性“hobby”是一个json数组。
解析上述文件时,可参考插件自动构建javabean,外围的json数组一定是一个集合,集合内对象类型为javabean,每一个javabean类中有各种属性,对于复杂属性“zhifubao”,可将其再次构建javabean,内有属性“account”,“balance”。相当于构建支付宝实体类。对于复杂属性“hobby”,其数据类型为一个字符串集合。