android:服务器与客户端的双向开发
在前面的两讲中,我们讲解了JSON数据格式的一些基本知识,以及做一些小Demo,这一讲我们在前面的基础上来做一个综合的可扩展的Demo,主要是针对Android客户端解析服务端传递过来的JSON数据。整个Demo所作的操作如下图所示
1. 服务端
服务端我们需要用到的解析JSON的库是用org.json --> Java --> JSON-lib项目中的库json-lib-2.4-jdk15.jar,这个库还需要附带几个依赖包:commons-beanutils.jar, commons-httpclient.jar, commons- lang.jar, ezmorph.jar,morph-1.0.1.jar。具体的包我会放在源码的lib目录下,读者可以自己去下载。
查看这个项目的api文档:http://json-lib.sourceforge.net/apidocs/jdk15/index.html,我们主要使用的是JSON JSONArray JSONObject JSONSerializer 这几个类,JSONObject这个类可以发现它与org.json这个项目的用法很类似。
1) 先做一个服务端的小实验,就是在服务端实现对Java对象转换成JSON数据格式并且在控制台输出。
Person.java 普通的Person类
[java] view plaincopy![]()
- package com.json.domain;
- public class Person {
- private int id;
- private String name;
- private String address;
- public Person(int id, String name, String address) {
- super();
- this.id = id;
- this.name = name;
- this.address = address;
- }
- public Person() {
- // TODO Auto-generated constructor stub
- }
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getAddress() {
- return address;
- }
- public void setAddress(String address) {
- this.address = address;
- }
- }
JsonService.java 服务于Person,给Person对象赋予各种属性
[java] view plaincopy![]()
- package com.json.service;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import com.json.domain.Person;
- public class JsonService {
- public JsonService() {
- // TODO Auto-generated constructor stub
- }
- public Person getPerson(){
- Person person = new Person(23, "AHuier", "XIAMEN");
- return person;
- }
- public List<Person> getListPerson(){
- List<Person> list = new ArrayList<Person>();
- Person person1 = new Person(1001, "AHuier1", "Beijing");
- Person person2 = new Person(1002, "AHuier2", "shenzheng");
- list.add(person1);
- list.add(person2);
- return list;
- }
- public List<String> getListString(){
- List<String> list = new ArrayList<String>();
- list.add("Hello");
- list.add("World");
- list.add("AHuier");
- return list;
- }
- public List<Map<String, Object>> getListMaps(){
- List<Map<String, Object>> listMap = new ArrayList<Map<String,Object>>();
- Map<String, Object> map1 = new HashMap<String, Object>();
- map1.put("color", "red");
- map1.put("id", 01);
- map1.put("name", "Polu");
- listMap.add(map1);
- Map<String, Object> map2 = new HashMap<String, Object>();
- map2.put("id", 07);
- map2.put("color", "green");
- map2.put("name", "Zark");
- listMap.add(map2);
- return listMap;
- }
- }
JsonTools.java 工具类
[java] view plaincopy![]()
- package com.json.tools;
- import net.sf.json.JSONObject;
- /**
- * @author xukunhui
- * 工具类,这里专门处理Java对象转Json字符串的功能
- */
- public class JsonTools {
- public JsonTools() {
- // TODO Auto-generated constructor stub
- }
- /**
- * @param key : JSON 名值对中的的名字
- * @param value :JSON 名值对中的值,值可以有多种类型
- * @return
- */
- // 接受对象转换为JSON数据格式并且作为字符串输出.
- public static String createJsonString(String key, Object value){
- JSONObject jsonObject = new JSONObject();
- jsonObject.put(key, value);
- return jsonObject.toString(); //就可以转换成Json数据格式
- }
- }
JsonTest.java 测试类
[java] view plaincopy![]()
- package com.json.test;
- import com.json.domain.Person;
- import com.json.service.JsonService;
- import com.json.tools.JsonTools;
- /**
- * @author xukunhui
- * 测试类,利用JSON讲Java对象转换成JSON数据格式,并且在控制台中输出
- */
- public class JsonTest {
- public JsonTest() {
- // TODO Auto-generated constructor stub
- }
- /**
- * @param args
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- String msg = "";
- JsonService service = new JsonService();
- // 带有三个属性的person对象
- Person person = service.getPerson();
- msg = JsonTools.createJsonString("person", person);
- System.out.println(msg);
- System.out.println("------------------------------");
- // List中存放两个person对象,这两个对象有各自的三个属性
- msg = JsonTools.createJsonString("persons", service.getListPerson());
- System.out.println(msg);
- System.out.println("------------------------------");
- // List中存放三个字符串
- msg = JsonTools.createJsonString("listString", service.getListString());
- System.out.println(msg);
- System.out.println("------------------------------");
- // List中存放两个Map,两个Map中分别存放三个不同的属性
- msg = JsonTools.createJsonString("listMap", service.getListMaps());
- System.out.println(msg);
- }
- }
编译执行结果:
{"person":{"address":"XIAMEN","id":23,"name":"AHuier"}}
------------------------------
{"persons":[{"address":"Beijing","id":1001,"name":"AHuier1"},{"address":"shenzheng","id":1002,"name":"AHuier2"}]}
------------------------------
{"listString":["Hello","World","AHuier"]}
------------------------------
{"listMap":[{"id":1,"color":"red","name":"Polu"},{"id":7,"color":"green","name":"Zark"}]}【说明】:从这里可以发现在服务端利用JSON很方便的将Java对象转换成JSON数据格式。
【注意】:我们这边需要给加一个person的标示符,作为最外面的一个对象的名,我们在客户端解析数据的时候,其实不加person的标示符也是可以的,但是这样写的目的是把原有的对象转换成JSON数据格式之后,我们在外层再给予封装一层对象,便于后续利用外层的这个对象进行解析。如下图所示:
2) 现在我们将服务端的项目部署到Tomcat服务器(如何部署可以参考前面几篇博文),然后通过在浏览器的地址栏中传递不同的action值来获取相应的JSON数据格式,这样的话浏览器也会显示出请求服务解析好的JSON数据格式。实现好这一步骤之后,我们在服务端的工作也完成了。服务端的项目结构图如下所示:
JsonAction.java Servlet类,处理根浏览器客户端通过不同的参数请求返回JSON数据。
[java] view plaincopy![]()
- package com.json.action;
- import java.io.IOException;
- import java.io.PrintWriter;
- import java.nio.charset.Charset;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import com.json.service.JsonService;
- import com.json.tools.JsonTools;
- /**
- * @author xukunhui
- * Servlet类,处理根浏览器客户端通过不同的参数请求返回JSON数据。
- */
- public class JsonAction extends HttpServlet {
- private JsonService service;
- /**
- * Constructor of the object.
- */
- public JsonAction() {
- super();
- }
- /**
- * Destruction of the servlet. <br>
- */
- public void destroy() {
- super.destroy(); // Just puts "destroy" string in log
- // Put your code here
- }
- /**
- * The doGet method of the servlet. <br>
- *
- * This method is called when a form has its tag value method equals to get.
- *
- * @param request the request send by the client to the server
- * @param response the response send by the server to the client
- * @throws ServletException if an error occurred
- * @throws IOException if an error occurred
- */
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- doPost(request, response);
- }
- /**
- * The doPost method of the servlet. <br>
- *
- * This method is called when a form has its tag value method equals to post.
- *
- * @param request the request send by the client to the server
- * @param response the response send by the server to the client
- * @throws ServletException if an error occurred
- * @throws IOException if an error occurred
- */
- public void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- response.setContentType("text/html; Charset=utf-8");
- request.setCharacterEncoding("utf-8");
- response.setCharacterEncoding("utf-8");
- PrintWriter out = response.getWriter();
- /*
- * 如果是以下这种方式直接在浏览器地址栏中用 http://192.168.0.112:8080/JsonProject/servlet/JsonAction 请求即可
- * String jsonString = JsonTools.createJsonString("person", service.getListPerson());
- * out.print(jsonString); // 从服务端提取数据,并且输出的浏览器客户端。
- */
- // 根据不同的参数输出不同的JSON数据
- String jsonString = "";
- String action_flag = request.getParameter("action_flag");
- if(action_flag.equals("person")) {
- jsonString = JsonTools.createJsonString("person", service.getPerson());
- } else if(action_flag.equals("persons")){
- jsonString = JsonTools.createJsonString("persons", service.getListPerson());
- } else if(action_flag.equals("listString")) {
- jsonString = JsonTools.createJsonString("listString", service.getListString());
- } else if(action_flag.equals("listMap")){
- jsonString = JsonTools.createJsonString("listMap", service.getListMaps());
- }
- out.print(jsonString);
- out.flush();
- out.close();
- }
- /**
- * Initialization of the servlet. <br>
- *
- * @throws ServletException if an error occurs
- */
- public void init() throws ServletException {
- // Put your code here
- service = new JsonService();
- }
- }
程序执行,在浏览器地址栏中输入与浏览器显示如下:
输入: http://192.168.0.112:8080/JsonProject/servlet/JsonAction?action_flag=person
输出: {"person":{"address":"XIAMEN","id":23,"name":"AHuier"}}输入:http://192.168.0.112:8080/JsonProject/servlet/JsonAction?action_flag=persons
输出: {"persons":[{"address":"Beijing","id":1001,"name":"AHuier1"},{"address":"shenzheng","id":1002,"name":"AHuier2"}]}输入:http://192.168.0.112:8080/JsonProject/servlet/JsonAction?action_flag=listString
输出: {"listString":["Hello","World","AHuier"]}输入:http://192.168.0.112:8080/JsonProject/servlet/JsonAction?action_flag=listMap
输出: {"listMap":[{"id":1,"color":"red","name":"Polu"},{"id":7,"color":"green","name":"Zark"}]}【备注】:自此,我们服务端模块的内容已经实现的差不多了,在服务端我们通常还结合JDBC进行操作。可以把JDBC的数据提取出来,提取出来的肯定是单条记录,或者是某一个集合。也就是服务端从JDBC数据库中提取到数据只要转换成JSON的数据格式后提供客户端进行显示。如下图所示:
2. 客户端
上面我们已经写好了服务端的代码,现在我们开始进行Android客户端的操作。JSON的解析有一个规则就是服务端把对象转换成一个JSON的数据格式,而客户端需要把JSON格式换成对象,客户端主要是通过Http协议向服务端发出请求获得服务端的JSON数据。
客户端项目结构如下图所示:
1. 客户端需要通过网络去向服务端请求数据,所以需要在 manifest.xml 清单文件中定义好访问网络的属性
[html] view plaincopy![]()
- <!-- add permission of access Internet -->
- <uses-permission android:name="android.permission.INTERNET"/>
2. HttpUtils.java 负责从服务器请求获取到JSON数据格式的字符串
[java] view plaincopy![]()
- package com.android.jsonproject.http;
- import java.io.ByteArrayOutputStream;
- import java.io.InputStream;
- import java.net.HttpURLConnection;
- import java.net.URL;
- /**
- * @author xukunhui 从服务器请求获取到JSON数据格式的字符串
- */
- public class HttpUtils {
- public HttpUtils() {
- // TODO Auto-generated constructor stub
- }
- public static String getJsonContent(String url_path) {
- try {
- URL url = new URL(url_path);
- HttpURLConnection connection = (HttpURLConnection) url.openConnection();
- connection.setConnectTimeout(3000); // 请求超时时间3s
- connection.setRequestMethod("GET");
- connection.setDoInput(true);
- int code = connection.getResponseCode(); // 返回状态码
- if (code == 200) {
- // 或得到输入流,此时流里面已经包含了服务端返回回来的JSON数据了,此时需要将这个流转换成字符串
- return changeInputStream(connection.getInputStream());
- }
- } catch (Exception e) {
- // TODO: handle exception
- }
- return "";
- }
- private static String changeInputStream(InputStream inputStream) {
- // TODO Auto-generated method stub
- String jsonString = "";
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- int length = 0;
- byte[] data = new byte[1024];
- try {
- while (-1 != (length = inputStream.read(data))) {
- outputStream.write(data, 0, length);
- }
- // inputStream流里面拿到数据写到ByteArrayOutputStream里面,
- // 然后通过outputStream.toByteArray转换字节数组,再通过new String()构建一个新的字符串。
- jsonString = new String(outputStream.toByteArray());
- } catch (Exception e) {
- // TODO: handle exception
- }
- return jsonString;
- }
- }
3. JSONTools.java 完成对从服务端请求获得的JSON数据的解析成指定的对象.
[java] view plaincopy![]()
- package com.android.jsonproject.json;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import org.json.JSONArray;
- import org.json.JSONObject;
- import com.android.jsonproject.domain.Person;
- /**
- * @author xukunhui
- * 完成对从服务端请求获得的JSON数据的解析成指定的对象.
- */
- public class JSONTools {
- public JSONTools() {
- // TODO Auto-generated constructor stub
- }
- // 此时从服务端取下来的数据是:{"person":{"address":"XIAMEN","id":23,"name":"AHuier"}}
- public static Person getPerson(String key, String jsonString){
- Person person = new Person();
- try {
- // 在Android官方文档中,org.json 这是Android提供给我们的解析json数据格式的包,
- // 我们比较常用的是JSONArray 和 JSONObject这个两个类
- JSONObject jsonObject = new JSONObject(jsonString);
- JSONObject personObject = jsonObject.getJSONObject(key);
- person.setId(personObject.getInt("id"));
- person.setAddress(personObject.getString("address"));
- person.setName(personObject.getString("name"));
- } catch (Exception e) {
- // TODO: handle exception
- }
- return person;
- }
- //{"persons":[{"address":"Beijing","id":1001,"name":"AHuier1"},{"address":"shenzheng","id":1002,"name":"AHuier2"}]}
- public static List<Person> getPersons(String key, String jsonString){
- List<Person> list = new ArrayList<Person>();
- try {
- JSONObject jsonObject = new JSONObject(jsonString);
- //返回json的数组
- JSONArray jsonArray = jsonObject.getJSONArray(key);
- for(int i = 0; i < jsonArray.length(); i++){
- JSONObject jsonObject2 = jsonArray.getJSONObject(i);
- Person person = new Person();
- person.setId(jsonObject2.getInt("id"));
- person.setName(jsonObject2.getString("name"));
- person.setAddress(jsonObject2.getString("address"));
- list.add(person);
- }
- } catch (Exception e) {
- // TODO: handle exception
- }
- return list;
- }
- //{"listString":["Hello","World","AHuier"]}
- public static List<String> getListString(String key, String jsonString){
- List<String> listString = new ArrayList<String>();
- try {
- JSONObject jsonObject = new JSONObject(jsonString);
- //返回JSON的数组
- JSONArray jsonArray = jsonObject.getJSONArray(key);
- for(int i = 0; i < jsonArray.length(); i++){
- String msg = jsonArray.getString(i);
- listString.add(msg);
- }
- } catch (Exception e) {
- // TODO: handle exception
- }
- return listString;
- }
- // 此时从服务端取下来的数据是:{"listMap":[{"id":1,"color":"red","name":"Polu"},{"id":7,"color":"green","name":"Zark"}]}
- public static List<Map<String, Object>> getListMaps(String key, String jsonString){
- List<Map<String, Object>> listMap = new ArrayList<Map<String, Object>>();
- try {
- JSONObject jsonObject = new JSONObject(jsonString);
- JSONArray jsonArray = jsonObject.getJSONArray(key);
- for(int i = 0; i < jsonArray.length(); i++){
- JSONObject jsonObject2 = jsonArray.getJSONObject(i);
- Map<String, Object> map = new HashMap<String, Object>();
- // 通过org.json中的迭代器来取Map中的值。
- Iterator<String> iterator = jsonObject2.keys();
- while(iterator.hasNext()) {
- String jsonKey = iterator.next();
- Object jsonValue = jsonObject2.get(jsonKey);
- //JSON的值是可以为空的,所以我们也需要对JSON的空值可能性进行判断。
- if(jsonValue == null){
- jsonValue = "";
- }
- map.put(jsonKey, jsonValue);
- }
- listMap.add(map);
- }
- } catch (Exception e) {
- // TODO: handle exception
- }
- return listMap;
- }
- }
4. Person.java 配合客户端将JSON数据转换成Java对象,服务端有Person对象,所以客户端需要相应的Person对象
[java] view plaincopy![]()
- package com.android.jsonproject.domain;
- public class Person {
- private int id;
- private String name;
- private String address;
- public Person(int id, String name, String address) {
- super();
- this.id = id;
- this.name = name;
- this.address = address;
- }
- public Person() {
- // TODO Auto-generated constructor stub
- }
- @Override
- public String toString() {
- return "Person [id=" + id + ", name=" + name + ", address=" + address + "]";
- }
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getAddress() {
- return address;
- }
- public void setAddress(String address) {
- this.address = address;
- }
- }
5. Android 客户端主界面代码,这里主要是定义四个按钮分别处理解析不同类型的JSON数据格式,布局文件这里不再贴出.
[java] view plaincopy![]()
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- switch (v.getId()) {
- case R.id.person:
- String path = "http://192.168.0.112:8080/JsonProject/servlet/JsonAction?action_flag=person";
- String jsonString = HttpUtils.getJsonContent(path);
- Log.i(TAG, "The jsonString:" + jsonString);
- Person person = JSONTools.getPerson("person", jsonString);
- Log.i(TAG, "The person:" + person.toString());
- break;
- case R.id.persons:
- String path2 = "http://192.168.0.112:8080/JsonProject/servlet/JsonAction?action_flag=persons";
- String jsonString2 = HttpUtils.getJsonContent(path2);
- Log.i(TAG, "The jsonString:" + jsonString2);
- List<Person> list2 = JSONTools.getPersons("persons", jsonString2);
- Log.i(TAG, "The persons:" + list2.toString());
- break;
- case R.id.liststring:
- String path3 = "http://192.168.0.112:8080/JsonProject/servlet/JsonAction?action_flag=listString";
- String jsonString3 = HttpUtils.getJsonContent(path3);
- Log.i(TAG, "The jsonString:" + jsonString3);
- List<String> list3 = JSONTools.getListString("listString", jsonString3);
- Log.i(TAG, "The listString:" + list3.toString());
- break;
- case R.id.listmap:
- String path4 = "http://192.168.0.112:8080/JsonProject/servlet/JsonAction?action_flag=listMap";
- String jsonString4 = HttpUtils.getJsonContent(path4);
- Log.i(TAG, "The jsonString:" + jsonString4);
- List<Map<String, Object>> list4 = JSONTools.getListMaps("listMap", jsonString4);
- Log.i(TAG, "The listMap:" + list4.toString());
- break;
- }
- }
客户端编译执行结果:
1. 点击解析person数据按钮
2. 点击解析List嵌套person数据
3. 点击List嵌套String数据
4. 点击List嵌套Map数据
自此,Android客户端与服务之间的JSON数据交互的Demo就完成了,下面附上源代码,读者可以自行编译执行
服务端: MyEclipse + Tomcat + Servlet
客户端: Eclipse + Android(模拟器和真机都可以,但是必须保证通过IP地址可以访问)
源码下载:http://download.csdn.net/detail/xukunhui2/6546095
服务端(符JSON开源项目包路径:JsonProject\WebRoot\WEB-INF\lib):
客户端:http://download.csdn.net/detail/xukunhui2/6546117
接下去,我们会学习一下google-gson的数据格式的解析,敬请关注。
android:服务器与客户端的双向开发相关推荐
- 即时通讯项目 java版本qq (含服务器和客户端)源码_即时通讯安卓-QQ互联网和即时通讯云,如何实现即时通讯,这是Android还是Java...
Android是系统平台. 应用程序所做的是应用程序的开发和完成 也就是说,通信是网络通信,但在手机环境中,网络的情况更复杂,所以我们必须做好结构 安卓即时通讯. 怎么做?安卓版TT即时通讯排行. A ...
- Android:Socket客户端开发,Android 的Socket客户端优化,Android非UI线程修改控件程序崩溃的问题
一.Android:Socket客户端开发 创建一个工程 我们要做的是按下按键之后,去往服务器 (服务器) 或者我们自己写的服务器 ,给他发送一些预定好的东西 然后打开操作界面 然后修改一下 你要发送 ...
- Android本地服务器NanoHttpd配置Https双向认证
一. 了解数字证书 在HTTPS的传输过程中,有一个非常关键的角色--数字证书,那什么是数字证书?又有什么作用呢? 所谓数字证书,是一种用于电脑的身份识别机制.由数字证书颁发机构(CA)对使用私钥创建 ...
- 基于STM32C8T6、ESP8266-01S、JavaWeb、JSP、Html、JavaScript、Android、服务器和客户端设计、上位机和下位机设计等技术融合的物联网智能监控系统设计与实现
系列文章目录 第一章ESP8266的java软件仿真测试 第二章ESP8266硬件与软件测试 第三章ESP8266客户端与Java后台服务器联调 第四章ESP8266客户端与JavaWeb服务器联调 ...
- Android长连接神器框架Mina之服务器和客户端例子
一.概述 Apache Mina Server 是一个网络通信应用框架,也就是说,它主要是对基于TCP/IP.UDP/IP协议栈的通信框架(当然,也可以提供JAVA 对象的序列化服务.虚拟机管道通信服 ...
- Android简单实现Socket通信,客户端连接服务器后,服务器向客户端发送文字数据
案例实现的是简单的Socket通信,当客户端(Android客户端)连接到指定服务器以后,服务器向客户端发送一句话文字信息(你可以拓展其它的了) 先看一下服务端程序的实现吧 Server.java i ...
- android获取服务器时间格式,Android 获取服务器与客户端时差的实例代码
一般我们在做商品倒计时的时候会遇到要从后台获取商品的开始时间和结束时间,还要计算商品距离开始时间的倒计时和结束时间的倒计时,但是这样只是从后台获取到开始时间,还要再和手机系统的时间相减,才能获取到开始 ...
- android+客户端+教程,Android新浪客户端开发教程完整版.pdf
Android新浪客户端开发教程完整版 Android 新浪客户端开发教程新浪客户端开发教程 (完整版(完整版)) 新浪客户端开发教程新浪客户端开发教程 ((完整版完整版)) android开发我的新 ...
- 400-集群聊天服务器的客户端开发
我们之前把聊天服务器的代码基本上功能开发完了,在后面转成集群版本的时候要引入中间件-基于发布订阅的Redis. 现在我们先开始客户端的开发 我们聊天服务器项目工程的客户端和服务器会共用很多代码,所以把 ...
最新文章
- 使用Oracle调度程序自动完成任务
- 2020五大技术趋势一览!超自动化、人类增强技术、无人驾驶发展、机器视觉崛起、区块链实用化...
- 如何在10亿数中找出前1000大的数
- ubuntu16.04无法连接WiFi搜索不到网络网卡驱动
- 【朝夕Net社区技术专刊】Core3.1 WebApi集群实战专题---WebApi环境搭建运行发布部署篇...
- 前端学习(1651):前端系列实战课程之json和字符串互转
- JavaWeb:XML总结
- 无法安装64位版本的office,因为在您的PC上找到了以下32位程序:microsoft visio professional 2013
- flutter listview 滚动到指定位置_Flutter 布局原理及实战
- libevent编程疑难解答
- 大约HR升级版的设计为组汇总
- 为并发而生的 ConcurrentHashMap,基于 Java8 分析
- 内置函数filter()
- 关于跨域以及跨域的实现方式
- Ignition Vision基本操作
- 求和函数java_java函数求和要怎么写?java求和代码实现
- 图像处理之双线性插值法
- 一天一个西红柿,健康多多
- MSI驱动指南HOWTO
- CF533A——题解
热门文章
- Revit二次开发-修改标注线尺寸界线的方向
- html单标记和双标记个两个,在HTML页面中,带有“”符号的元素被称为单标记与双标记。...
- 百度移动应用安卓_百度官宣,价值19亿美元,曾经的最强安卓分发渠道正式下线...
- Python简单网页爬虫——极客学院视频自动下载
- 小创意之-C#设置电脑壁纸
- Vty password is not set问题解决
- Kotlin报错:Out-projected type ... prohibits the use of ... defined in ...的解决方案
- Linux安装Ubuntu18.04/显卡驱动/CUDA11.4/cuDNN8.2
- idea 关于 filed to create JVM:error code -1
- 去除《简-书》页面右边《热门故事》,直达《全部评论》《推荐阅读》