Android
安卓开发者指南:https://developer.android.google.cn/guide
1 网络操作
1.1 Android中的网络操作
Android程序最重要的模块就是网络部分,如何从网络上下载数据,如何将处理过的数据上传至网络,往往是android程序的关键环节。
Android网络多半数是基于移动端的开发,那么这时候我们所开发的app就要不断的向服务器端发送请求,然后服务器端会根据相应的请求字段将相应的内容返回给app端,这时候返回给app端的是json格式的字符串,然后app端通过一定的json解析手段将一定的数据显示在对应的控件上,达到数据显示的效果。
-
客户端与服务端
-
Http协议(超文本传输协议Hypertext Transfer Protocol,应用层),是web联网的基础,也是手机联网常用的协议之一, HTTP协议是建立在TCP协议之上的一种应用。HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。HTTP提供了封装或者显示数据的具体形式,Socket 提供了网络通信的能力。
HTTPS (全称: Hypertext Transfer Protocol over Secure Socket Layer ),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。它是一 个URI scheme (抽象标识符体系),句法类同http:体系,用于安全的HTTP数据传输。https:URL 表明它使用了HTTP但HTTssPS存在不同于HTTP的默认端口及一个加密/身份验证层(在HTTP与TCP之间)。被广泛用于万维网上安全敏感的通讯,例如交易支付方面。 -
URL解析
协议、域名、端口、虛拟目录、参数…
从服务器获取数据
1.实例化一个URL对象
5. 获取HttpURLConnection对象
3.设置请求连接属性
4.获取响应码,判断连接结果码
5.读取输入流并解析
get VS post
get请求
会出现闪退,解决方案:
利用多线程,操作网络在主线程就会闪退,在子线程不会,但是更新主线程UI也会闪退,使用runOnUiThread。(主线程跳子线程,再跳回主线程,很麻烦,但是会有一些耗时操作,在子线程做一些耗时操作,最后在主线程更新)
new Thread(new Runable() {
public void run() {
try{
URL url = new URL
......
if(responseCode == HttpURLConnection.HTTP_ OK){
InputStream inputStream = connect ion getInputStream() ;
mResult = streamToString(inputStream);// String mResult全局变量
runOnUiThread(new Runnable(){
@Override
public void run(){
mResult = decode(mResult);
mTextView.setText(mResult );
}
});
} else {
Log.e(TAG, "run:error code:" + responseCode+",message:"+responseMessage);
}
}
}
}
在AndroidManifest.xml中申请Internet网络权限
<uses-permission android:name="android.permission.INTERNET"/>
API 28(Android 9.0)新特性
9.0对http请求的限制。在Android9.0版本中,对网络安全有较高的要求,如果访问的是https协议则不受影响;而如果访问了http协议的网址,还需要添加安全配置文件,步骤如下:
1.创建安全配置文件:
在res文件夹下创建文件夹xml,network-security-config文件
增加cleartextTrafficPermitted属性(允许http请求)
<network-security-config>
<base-config cleartextTrafficPermitted = "true"/>
</network-security-config>
2.添加安全配置文件
在AndroidManifest.xml中的application声明添加:
android:networkSecurityConfig="@xml/network-security-config"
post请求
登录注册大多是用的post请求(get简单,但是不安全)
1.2 JSON数据解析
-
JSON数据解析
JSON数据格式是什么:
一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性。业内主流技术为其提供了完整的解决方案(有点类似于正则表达式, 获得了当今大部分语言的支持),从而可以在不同平台间进行数据交换。JSON采用兼容性很高的文本格式,同时也具备类似于C语言体系的行为。
-
使用JSONObject解析JSON数据
-
使用GSON解析JSON数据
demo代码:
public class NetworkActivity extends AppCompatActivity implements View.OnClickListener{
private TextView mTextView;
private Button mButton;
private static final String TAG = "NetworkActivity";
private String mResult;
private Button mParseDataButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_network);
findViews();
setListeners();
}
private void findViews() {
mTextView = findViewById(R.id.textView);
mButton = findViewById(R.id.getButton);
mParseDataButton = findViewById(R.id.parseDataButton);
}
private void setListeners() {
mButton.setOnClickListener(this);
mParseDataButton.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.getButton:
new Thread(new Runnable() {
@Override
public void run() {
String urlString = "http://www.imooc.com/api/teacher?type=2&page=1";
mResult = requestDataByGet(urlString);
runOnUiThread(new Runnable() {
@Override
public void run() {
mResult = decode(mResult);
mTextView.setText(mResult);
}
});
}
}).start();
break;
case R.id.parseDataButton:
if (!TextUtils.isEmpty(mResult)) {
handleJSONData(mResult);
}
break;
}
}
private void handleJSONData(String json) {
try {
JSONObject jsonObject = new JSONObject(json);
LessonResult lessonResult = new LessonResult();
List<LessonResult.Lesson> lessonList = new ArrayList<>();
int status = jsonObject.getInt("status");
JSONArray lessons = jsonObject.getJSONArray("data");
if (lessons != null && lessons.length() > 0) {
for (int index = 0; index < lessons.length(); index++) {
JSONObject item = (JSONObject) lessons.get(0);
int id = item.getInt("id");
String name = item.getString("name");
String smallPic = item.getString("picSmall");
String bigPic = item.getString("picBig");
String description = item.getString("description");
int learner = item.getInt("learner");
LessonResult.Lesson lesson = new LessonResult.Lesson();
lesson.setID(id);
lesson.setName(name);
lesson.setSmallPictureUrl(smallPic);
lesson.setBigPictureUrl(bigPic);
lesson.setDescription(description);
lesson.setLearnerNumber(learner);
lessonList.add(lesson);
}
lessonResult.setStatus(status);
lessonResult.setLessons(lessonList);
mTextView.setText("data is : " + lessonResult.toString());
}
} catch (JSONException e) {
e.printStackTrace();
}
}
private String requestDataByGet(String urlString) {
String result = null;
try {
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(30000);
connection.setRequestMethod("GET"); // GET POST
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Charset", "UTF-8");
connection.setRequestProperty("Accept-Charset", "UTF-8");
connection.connect();
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream inputStream = connection.getInputStream();
result = streamToString(inputStream);
} else {
String responseMessage = connection.getResponseMessage();
Log.e(TAG, "requestDataByPost: " + responseMessage);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
/**
* 将输入流转换成字符串
* @param is 从网络获取的输入流
* @return 字符串
*/
public String streamToString(InputStream is) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
baos.close();
is.close();
byte[] byteArray = baos.toByteArray();
return new String(byteArray);
} catch (Exception e) {
Log.e(TAG, e.toString());
return null;
}
}
/**
* 将Unicode字符转换为UTF-8类型字符串
*/
public static String decode(String unicodeStr) {
if (unicodeStr == null) {
return null;
}
StringBuilder retBuf = new StringBuilder();
int maxLoop = unicodeStr.length();
for (int i = 0; i < maxLoop; i++) {
if (unicodeStr.charAt(i) == '\\') {
if ((i < maxLoop - 5)
&& ((unicodeStr.charAt(i + 1) == 'u') || (unicodeStr
.charAt(i + 1) == 'U')))
try {
retBuf.append((char) Integer.parseInt(unicodeStr.substring(i + 2, i + 6), 16));
i += 5;
} catch (NumberFormatException localNumberFormatException) {
retBuf.append(unicodeStr.charAt(i));
}
else {
retBuf.append(unicodeStr.charAt(i));
}
} else {
retBuf.append(unicodeStr.charAt(i));
}
}
return retBuf.toString();
}
private String requestDataByPost(String urlString) {
String result = null;
try {
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(30000);
connection.setRequestMethod("POST");
// 设置运行输入,输出:
connection.setDoOutput(true);
connection.setDoInput(true);
// Post方式不能缓存,需手动设置为false
connection.setUseCaches(false);
connection.connect();
// 我们请求的数据:
String data = "username=" + URLEncoder.encode("imooc", "UTF-8")
+ "&number=" + URLEncoder.encode("15088886666", "UTF-8");
// 获取输出流
OutputStream out = connection.getOutputStream();
out.write(data.getBytes());
out.flush();
out.close();
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream inputStream = connection.getInputStream();
Reader reader = new InputStreamReader(inputStream, "UTF-8");
char[] buffer = new char[1024];
reader.read(buffer);
result = new String(buffer);
reader.close();
} else {
String responseMessage = connection.getResponseMessage();
Log.e(TAG, "requestDataByPost: " + responseMessage);
}
final String finalResult = result;
runOnUiThread(new Runnable() {
@Override
public void run() {
mTextView.setText(finalResult);
}
});
connection.disconnect();
return result;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}