安卓基础(持续更新的笔记)
为什么要这样:
// 创建请求体RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),jsonObject.toString());
jsonObject 就包含了一个 JSON 数据,它其实就是:
{"name": "张三","age": 10
}
所以,jsonObject.toString() 会把我们的 JSON 数据转换成:
{"name":"张三","age":10}
什么是 client.newCall(request).enqueue()?
client 是什么?
- 你可以把
client想象成一个邮递员。 - 它负责接收信件(就是请求)并把信件送到目的地(比如服务器)。
request 是什么?
request就是你要寄出的信,它包含了你想要发送的信息(比如:你想要从网站获取的数据)。- 你可以把 request 看作是装在信封里的信,信里写着你要做什么(比如:查天气,获取新闻等)。
newCall(request) 是什么意思?
- 当你说
client.newCall(request)时,你是在告诉邮递员:“嘿!这是我的信(请求),帮我寄出去!”
enqueue(new Callback() {...}) 是什么意思?
-
这部分就是你告诉邮递员,“当信送到之后,告诉我一声!”就像你期待收信一样,你也期待邮递员处理完请求之后给你一个答复。
-
enqueue是一个 "异步" 操作,意味着邮递员把信送出去后,他不会立刻等待回信,而是继续去做其他事情。等他收到回复时,他会 通知你,就像“嘿!你的信已经回来了,我有了答案!” -
Callback就是你给邮递员的一个回信地址,你告诉邮递员,“当有回复的时候,联系我”。当你收到答复时,邮递员就会通过Callback告诉你 答复内容。
public void onResponse(Call call, Response response) throws IOException
为什么要加一个 Call call 参数?
-
表示当前的请求:
onResponse是一个回调方法,它在网络请求成功后被调用。Call call这个参数是告诉你当前的请求是什么,它是你发起的某个网络请求对象。这样,在回调中你可以通过call来获取有关请求的信息。 -
支持多次请求: 有时候,程序可能会发起多个请求。通过在
onResponse中传递call,你就能知道是哪个请求返回的结果。如果没有call,你就不知道是哪个请求触发了回调。
String responseBody = response.body().string();
response.body().string(); 这行代码的意思是什么?
response: 这是你从网络请求得到的回应,它包含了很多信息,比如服务器返回的数据、状态码、头信息等。body(): 这个方法可以用来获取服务器返回的数据内容。可以理解为,"body" 就是回应的内容。string(): 这个方法把回应的内容转换成字符串。因为服务器返回的数据通常是以二进制的方式存储的,我们需要把它转换成可读的文本(字符串)才能理解里面的内容。
举个简单的例子:
想象你给朋友发了一个包裹,这个包裹里有一些写着字的纸条,代表服务器给你的回应。
response.body()就像是你打开包裹,拿到里面的纸条。string()就是你把纸条上的内容读出来,变成可以理解的文字。
轮询获取消息是什么?
轮询获取消息,简单来说,就是定时检查是否有新消息。就像你每天都会去查看邮箱,看看是否有新的邮件。你定期检查一次,如果有新邮件,你就打开看,没有就过一会儿再看一次。
代码怎么实现?
- Looper 是顾客排队的地方(等候队列),
- Handler 就是把任务分配给助手的工具(执行任务)。
new Handler(Looper.getMainLooper())就是告诉你:“嘿,我们要让这个任务在应用的大脑(主线程)里执行!”-
handler.post(new Runnable()):
handler.post(new Runnable())就是把一个新的任务(Runnable)交给管家(Handler)来执行。- 它的作用是告诉管家:“嘿,我有个任务交给你,你去做吧!”
-
Looper.loop()会启动一个无限的循环,持续检查并执行交给它的任务。
在安卓中,轮询可以通过定时任务来实现。最常见的方法是使用Handler和Runnable,每隔一段时间就去请求服务器看看有没有新消息。这里是一个简单的例子:
// 导入 Android 中的 Handler 类和 Looper 类
import android.os.Handler;
import android.os.Looper;public class PollingExample {// 创建一个 Handler 对象,Handler 会在主线程中处理任务private Handler handler = new Handler(Looper.getMainLooper());// 定义一个变量 interval,每隔5秒检查一次private int interval = 5000; // 每5秒钟检查一次private boolean isPolling = false; // 用来标记是否在进行轮询// 开始轮询,设置 isPolling 为 true,表示开始检查新消息public void startPolling() {isPolling = true; // 开启轮询pollMessages(); // 调用 pollMessages 方法开始检查}// 停止轮询,设置 isPolling 为 false,表示不再检查新消息public void stopPolling() {isPolling = false; // 停止轮询}// 检查是否有新消息的方法private void pollMessages() {if (isPolling) { // 如果正在进行轮询// 模拟发起网络请求,检查是否有新消息System.out.println("正在检查是否有新消息..."); // 输出提示信息,表示正在检查消息// 模拟检查到新消息boolean newMessageReceived = checkForNewMessages();// 如果检查到新消息,就输出提示信息if (newMessageReceived) {System.out.println("有新消息!"); // 输出“有新消息!”}// 每隔 interval(5秒)再去检查一次handler.postDelayed(new Runnable() {@Overridepublic void run() {pollMessages(); // 再次调用 pollMessages 方法,继续检查}}, interval); // 设置延迟时间为 interval(5秒)}}// 模拟一个方法,用来检查是否有新消息private boolean checkForNewMessages() {// 假设这里是通过网络请求来检查新消息,我们简单返回 true,表示有新消息return true;}
}
Retrofit 是一个用来简化网络请求的 Android 库。它帮助我们在 Android 应用程序中发送 HTTP 请求(比如获取网络上的数据),并把这些请求的响应数据转换成我们能理解和使用的格式。换句话说,它是一个让你与网络进行“对话”的工具。
如何使用 Retrofit?
- 创建一个接口:定义你想要请求的 API,告诉 Retrofit 你需要什么数据。
- 配置 Retrofit 实例:设置 Retrofit,告诉它请求的 URL 和如何处理数据。
- 发起请求:通过 Retrofit 请求网络数据,并处理返回的结果。
步骤 1: 安装 Retrofit
首先,我们需要在我们的项目中添加 Retrofit 这个工具。就像是我们需要下载一个游戏的安装包一样。
- 打开 Android Studio。
- 找到你项目中的
build.gradle文件(就是一个列出我们需要用到的工具和库的清单)。 - 在这个文件里添加 Retrofit 的依赖(就像是给我们的游戏添加功能):
dependencies {implementation 'com.squareup.retrofit2:retrofit:2.9.0' // 这是 Retrofit 这个工具implementation 'com.squareup.retrofit2:converter-gson:2.9.0' // 用来转换数据的工具
}
然后点击 Sync Now,就像是安装游戏一样,安装完成后你就可以使用 Retrofit 了。
步骤 2: 创建 Retrofit 接口
接下来我们要告诉 Retrofit,我要去哪里获取数据(就像告诉游戏你要去哪里玩)。
接口 是一个用来定义我们需要请求哪些数据的地方。我们可以把它想象成是告诉 Retrofit 我们要去哪里拿数据。
比如我们想去一个网站,看看 GitHub 上某个人的仓库(就像是我们想要知道某个游戏的排名)。我们可以定义一个接口来告诉 Retrofit 我们需要这些信息。
public interface ApiService {@GET("users/{user}/repos") // 这里是 GitHub 的地址Call<List<Repo>> listRepos(@Path("user") String user); // 这个方法去获取某个用户的所有仓库
}
这里我们用了一个 GET 请求,意思是去获取数据。
步骤 3: 创建 Retrofit 实例
接下来,我们需要让 Retrofit 开始工作,就像启动游戏一样。
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.github.com/") // 告诉 Retrofit 去哪里获取数据.addConverterFactory(GsonConverterFactory.create()) // 使用 Gson 来帮助我们理解数据.build();
步骤 4: 发起请求
现在我们需要告诉 Retrofit 去获取数据。我们只需要告诉它一个用户的名字,它就会帮我们去获取这个用户的所有仓库。
ApiService apiService = retrofit.create(ApiService.class); // 创建接口
Call<List<Repo>> call = apiService.listRepos("octocat"); // 发起请求,获取 octocat 的仓库
步骤 5: 处理结果
当我们请求数据时,Retrofit 会帮我们处理所有的事情。我们只需要准备好两件事情:
- 如果请求成功了,我们怎么处理结果(就像完成任务后获得奖励)。
- 如果请求失败了,我们怎么处理失败的情况(就像遇到障碍要重新尝试)。
call.enqueue(new Callback<List<Repo>>() {@Overridepublic void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {if (response.isSuccessful()) { // 请求成功List<Repo> repos = response.body(); // 获取到仓库数据for (Repo repo : repos) {System.out.println(repo.getName()); // 打印出每个仓库的名字}}}@Overridepublic void onFailure(Call<List<Repo>> call, Throwable t) {t.printStackTrace(); // 如果请求失败了,打印错误信息}
});
addConverterFactory(GsonConverterFactory.create()) 这个代码行是 Retrofit 的一部分,它告诉 Retrofit 如何将从网络上获取到的数据(通常是 JSON 格式)转换成 Java 对象。简单来说,它就像是一个“翻译员”,帮你把网络上收到的“外文”数据(比如 JSON)翻译成你能理解的“中文”数据(比如 Java 对象)。
具体解释:
-
Gson:它是一个工具库,可以将 JSON 数据转换成 Java 对象,也可以将 Java 对象转换成 JSON 数据。Retrofit 使用 Gson 来帮你完成这种转换。
-
ConverterFactory:这就是一个工具箱,里面有很多种转换数据的“翻译员”。
GsonConverterFactory.create()就是告诉 Retrofit 用 Gson 这个“翻译员”来做这个工作。 -
addConverterFactory():这个方法是用来告诉 Retrofit 你希望使用哪种“翻译员”,并且让它使用这个“翻译员”来处理数据。
举个例子:
假设你从网络上请求到一个用户的信息,服务器返回的结果是这样的一段 JSON:
{"name": "Tom","age": 12
}
你可能想把这段 JSON 转换成一个 Java 对象,可能是这样的:
class User {String name;int age;
}
然后,使用 addConverterFactory(GsonConverterFactory.create()),Retrofit 就会帮你把这段 JSON 数据自动转换成 User 类的对象,这样你就能在程序里像使用普通 Java 对象一样使用这段数据。
总结:
addConverterFactory(GsonConverterFactory.create()) 就是告诉 Retrofit 用 Gson 来帮你自动翻译 JSON 数据,让你可以直接使用 Java 对象,免去了你自己手动解析 JSON 的麻烦。
Gson 是怎么工作的?
Gson 可以帮助你把这段 JSON 数据“翻译”成一个 Java 对象,像这样:
class Person {String name;int age;
}
使用 Gson,你可以通过以下代码把 JSON 转换成 Java 对象:
Gson gson = new Gson();
String json = "{\"name\":\"Tom\", \"age\":12}";
Person person = gson.fromJson(json, Person.class);
这里,fromJson() 方法会把 JSON 数据转换成 Person 类型的对象。现在你就可以像使用普通 Java 对象一样,访问 person.name 或 person.age 了。
Gson 能做什么?
-
将 Java 对象转换成 JSON(序列化):
Person person = new Person(); person.name = "Tom"; person.age = 12; Gson gson = new Gson(); String json = gson.toJson(person); // 将 Java 对象转换为 JSON -
这会得到一个 JSON 字符串:
{"name":"Tom", "age":12}。 -
将 JSON 转换成 Java 对象(反序列化):
String json = "{\"name\":\"Tom\", \"age\":12}";
Person person = gson.fromJson(json, Person.class); // 从 JSON 创建 Java 对象
为什么要用 Gson?
- 简单易用:你只需要很少的代码就可以处理 JSON。
- 自动转换:Gson 会自动把 JSON 数据和 Java 对象的字段进行匹配。
- 高效:它处理 JSON 数据非常高效,尤其适合网络请求和响应。
总结:
Gson 就是一个用来处理 JSON 数据的工具,它让你在 Java 程序中可以轻松地和 JSON 数据打交道,把它们相互转换成 Java 对象。
使用 OkHttp3:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("https://api.example.com/data").build();client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {// 请求失败}@Overridepublic void onResponse(Call call, Response response) throws IOException {// 请求成功,获取响应数据}
});
使用 Retrofit:
// 1. 定义接口
public interface ApiService {@GET("data")Call<Data> getData(); // 自动把响应转换成 Data 对象
}// 2. 创建 Retrofit 实例并发起请求
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.example.com/").addConverterFactory(GsonConverterFactory.create()) // Gson 解析响应.build();ApiService apiService = retrofit.create(ApiService.class);
Call<Data> call = apiService.getData(); // 通过接口方法发起请求call.enqueue(new Callback<Data>() {@Overridepublic void onResponse(Call<Data> call, Response<Data> response) {// 处理响应数据,response.body() 会自动转成 Data 对象}@Overridepublic void onFailure(Call<Data> call, Throwable t) {// 请求失败}
});
总结:
- OkHttp3 是底层的工具,用来发起 HTTP 请求并处理响应。
- Retrofit 是基于 OkHttp3 的更高级工具,它让我们通过定义接口、注解和一些简化的代码来轻松发起 HTTP 请求,并且能自动解析服务器响应的数据。
HashMap 和 Gson 是两个完全不同的东西,它们有不同的用途和功能。下面我会简单地说明它们各自是什么,以及它们之间的区别。
1. HashMap:
HashMap 是一种数据结构,用于存储键值对(key-value pairs)。它将一个 键(key) 映射到一个 值(value)。你可以通过给定的 键 来快速查找、添加或删除 值。
- 用途:用于存储和查找数据。
- 操作:可以存储、查找、删除、更新键值对。
- 例子:比如你有一个字典,你可以通过查找词语(键)来获得它的解释(值)。
示例:
HashMap<String, String> map = new HashMap<>();
map.put("apple", "fruit");
map.put("dog", "animal");String value = map.get("apple"); // 获取 "apple" 对应的值 "fruit"
2. Gson:
Gson 是一个用于将 Java 对象转换为 JSON 格式(序列化)和将 JSON 格式转换回 Java 对象(反序列化)的库。JSON 是一种轻量级的数据交换格式,广泛用于网络请求和响应中。
- 用途:用于在 Java 对象和 JSON 数据之间进行转换。
- 操作:将 Java 对象转换为 JSON 格式,或者将 JSON 格式的数据转换为 Java 对象。
- 例子:当你从服务器获取 JSON 数据时,可以使用 Gson 将 JSON 转换为 Java 对象,或者将 Java 对象转换为 JSON 发送到服务器。
示例:
// 将 Java 对象转换为 JSON 字符串
Person person = new Person("John", 30);
Gson gson = new Gson();
String json = gson.toJson(person); // 转换成 JSON 字符串// 将 JSON 字符串转换为 Java 对象
String jsonString = "{\"name\":\"John\",\"age\":30}";
Person personFromJson = gson.fromJson(jsonString, Person.class);
3. HashMap 和 Gson 的区别:
-
类型和功能:
- HashMap 是一个数据结构,用来存储键值对(key-value pairs),用于高效查找、添加和删除数据。
- Gson 是一个库,用来处理 JSON 和 Java 对象之间的转换。它不直接存储数据,只是帮助将数据转换成 JSON 格式,或者从 JSON 转换回 Java 对象。
-
用途:
- HashMap 用于存储和管理键值对数据,像是字典一样。
- Gson 用于将对象和 JSON 格式之间进行转换,通常用于网络请求和响应。
-
使用场景:
- HashMap 用于程序内部存储临时数据,并根据键快速查找对应的值。
- Gson 用于与外部系统(例如服务器)交换数据,或者存储/传输数据时使用 JSON 格式。
4. 总结:
- HashMap 是一个数据结构,用于存储键值对(key-value pairs),类似字典的功能。
- Gson 是一个用于 对象和 JSON 数据 相互转换的工具库。
Interceptor 是 OKHttp 中的一个强大工具,它允许你拦截和修改 HTTP 请求和响应。你可以使用 Interceptor 来实现一些常见功能,比如记录日志、修改请求头、重试机制、缓存控制等。
使用 Interceptor 的步骤
1. 创建一个 Interceptor
Interceptor 是一个接口,有两个主要的方法:
intercept(Chain chain):这个方法用于拦截请求,可以在这里修改请求和响应
// 导入 OkHttp 的相关类,Interceptor 用于拦截和修改请求和响应
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;// 创建一个 LoggingInterceptor 类,它实现了 OkHttp 的 Interceptor 接口
public class LoggingInterceptor implements Interceptor {// 重写 intercept 方法,这个方法会在请求发出之前和响应返回之后执行@Overridepublic Response intercept(Chain chain) throws IOException {// 获取原始的 HTTP 请求对象Request request = chain.request();// 打印请求的 URL 地址System.out.println("Request URL: " + request.url());// 打印请求的所有头部信息,例如 User-Agent,Content-Type 等System.out.println("Request Headers: " + request.headers());// 继续发送这个请求,获取响应。这里的 `chain.proceed(request)` 就是实际执行请求的地方Response response = chain.proceed(request);// 打印响应的状态码(例如 200 表示成功)System.out.println("Response Code: " + response.code());// 打印响应的头部信息System.out.println("Response Headers: " + response.headers());// 返回响应对象,这一步很重要,必须返回响应以继续正常流程return response;}
}
流程图:
- 请求 → 拦截器 1 → 拦截器 2 → 网络请求 → 网络拦截器 → 拦截器 2 → 拦截器 1 → 响应返回应用。
拦截器的执行顺序(请求):
假设我们有以下两个拦截器:
LoggingInterceptor(打印请求信息)HeaderInterceptor(添加额外的 header)
假设添加顺序如下:
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new LoggingInterceptor()) // 第一个拦截器.addInterceptor(new HeaderInterceptor()) // 第二个拦截器.build();
LoggingInterceptor会先执行,打印请求的 URL、头部等信息。- 然后,
HeaderInterceptor会执行,向请求中添加额外的 header(比如授权信息)。
public class LoggingInterceptor implements Interceptor {@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request(); // 获取原始请求System.out.println("Request URL: " + request.url());// 继续执行请求Response response = chain.proceed(request);System.out.println("Response Code: " + response.code());return response;}
}public class HeaderInterceptor implements Interceptor {@Overridepublic Response intercept(Chain chain) throws IOException {Request originalRequest = chain.request();Request modifiedRequest = originalRequest.newBuilder().addHeader("Authorization", "Bearer some_token") // 添加一个header.build();// 继续请求return chain.proceed(modifiedRequest);}
}
import okhttp3.*;import java.io.IOException;public class ComplexInterceptorExample {public static void main(String[] args) throws Exception {// 创建 OkHttpClient 并添加多个拦截器OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new LoggingInterceptor()) // 第一个拦截器 - 日志.addInterceptor(new HeaderInterceptor()) // 第二个拦截器 - 添加header.addInterceptor(new CustomInterceptor()) // 第三个拦截器 - 自定义处理.build();// 创建请求Request request = new Request.Builder().url("https://jsonplaceholder.typicode.com/posts").build();// 发送请求client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {System.out.println("请求失败: " + e.getMessage());}@Overridepublic void onResponse(Call call, Response response) throws IOException {System.out.println("最终响应: " + response.body().string());}});}// 第一个拦截器:日志拦截器static class LoggingInterceptor implements Interceptor {@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request(); // 获取原始请求System.out.println("日志拦截器: 请求 URL: " + request.url());// 打印请求的头信息System.out.println("日志拦截器: 请求头: " + request.headers());// 继续请求Response response = chain.proceed(request);// 打印响应的状态码System.out.println("日志拦截器: 响应码: " + response.code());// 返回响应return response;}}// 第二个拦截器:添加 Headerstatic class HeaderInterceptor implements Interceptor {@Overridepublic Response intercept(Chain chain) throws IOException {Request originalRequest = chain.request();// 在请求头添加自定义的 Authorization tokenRequest modifiedRequest = originalRequest.newBuilder().addHeader("Authorization", "Bearer some_token").build();// 打印修改后的请求头System.out.println("Header拦截器: 添加了 Authorization header");// 继续请求return chain.proceed(modifiedRequest);}}// 第三个拦截器:模拟延迟处理static class CustomInterceptor implements Interceptor {@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request();System.out.println("Custom拦截器: 在请求前做一些处理");// 模拟延迟处理try {Thread.sleep(1000); // 假设在此做了一些长时间处理} catch (InterruptedException e) {e.printStackTrace();}// 继续发送请求Response response = chain.proceed(request);// 模拟响应后处理System.out.println("Custom拦截器: 在响应后做一些处理");// 返回响应return response;}}
}
Retrofit 拦截器的工作原理
- 拦截器的作用:拦截器可以在请求被发送到服务器之前和响应被返回给应用之前进行拦截。这使得它能够修改请求和响应,比如添加自定义的请求头、打印日志、处理缓存等。
- 拦截器的类型:OkHttp 拦截器主要分为两种:
- 应用拦截器:它可以访问整个请求和响应,并可以修改它们。应用拦截器是一次性拦截请求或响应的。
- 网络拦截器:它与应用拦截器不同,网络拦截器允许你访问底层网络响应(例如,查看重定向和缓存的响应)。
如何在 Retrofit 中使用拦截器
-
创建拦截器: 你可以创建一个自定义的拦截器类,来控制请求和响应的行为。
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;public class LoggingInterceptor implements Interceptor {@Overridepublic Response intercept(Chain chain) throws IOException {// 获取请求Request request = chain.request();// 打印请求信息System.out.println("Request URL: " + request.url());System.out.println("Request Headers: " + request.headers());// 执行请求并获取响应Response response = chain.proceed(request);// 打印响应信息System.out.println("Response Code: " + response.code());System.out.println("Response Headers: " + response.headers());// 返回响应return response;}
}
将拦截器添加到 Retrofit: 使用 OkHttp 的拦截器机制,我们可以将这个拦截器添加到 Retrofit 实例中。拦截器会在每个请求的生命周期中起作用。
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;public class RetrofitInstance {private static Retrofit retrofit = null;public static Retrofit getRetrofitInstance() {if (retrofit == null) {// 创建 OkHttpClient 实例并添加拦截器OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new LoggingInterceptor()) // 添加自定义拦截器.build();// 创建 Retrofit 实例并返回retrofit = new Retrofit.Builder().baseUrl("https://jsonplaceholder.typicode.com/").client(client) // 将 OkHttpClient 添加到 Retrofit 中.addConverterFactory(GsonConverterFactory.create()) // 添加转换器.build();}return retrofit;}
}
使用 Retrofit 发起请求: 一旦你将拦截器添加到 Retrofit 中,它将自动应用于所有通过 Retrofit 发起的请求。
public interface ApiService {@GET("posts")Call<List<Post>> getPosts();
}// 使用 Retrofit 实例发送请求
ApiService apiService = RetrofitInstance.getRetrofitInstance().create(ApiService.class);
Call<List<Post>> call = apiService.getPosts();call.enqueue(new Callback<List<Post>>() {@Overridepublic void onResponse(Call<List<Post>> call, Response<List<Post>> response) {// 请求成功}@Overridepublic void onFailure(Call<List<Post>> call, Throwable t) {// 请求失败}
});
1. HttpURLConnection
HttpURLConnection 是 Android 中最基础的 HTTP 请求方式,用于从服务器获取数据或发送数据。它是 Java 自带的类,适用于大多数简单的 HTTP 请求。
使用示例:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;public class HttpURLConnectionExample {public static void main(String[] args) throws Exception {// 目标网址URL url = new URL("https://api.example.com/data");// 打开连接HttpURLConnection connection = (HttpURLConnection) url.openConnection();// 设置请求方式connection.setRequestMethod("GET");// 设置连接超时和读取超时connection.setConnectTimeout(5000);connection.setReadTimeout(5000);// 添加请求头(headers)connection.setRequestProperty("User-Agent", "Mozilla/5.0");connection.setRequestProperty("Accept", "application/json");connection.setRequestProperty("Authorization", "Bearer YOUR_ACCESS_TOKEN");// 获取响应码int responseCode = connection.getResponseCode();System.out.println("Response Code: " + responseCode);// 如果响应码是200(表示成功),读取响应内容if (responseCode == HttpURLConnection.HTTP_OK) {BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));String inputLine;StringBuffer response = new StringBuffer();while ((inputLine = in.readLine()) != null) {response.append(inputLine);}in.close();System.out.println("Response Content: " + response.toString());} else {System.out.println("Request failed");}// 关闭连接connection.disconnect();}
}
解释:
- URL: 请求的地址。
- HttpURLConnection: 用来创建 HTTP 连接。
- setRequestMethod("GET"): 设置请求方式(GET、POST 等)。
- getResponseCode(): 获取服务器响应的 HTTP 状态码(例如 200 表示成功,404 表示未找到页面)。
- getInputStream(): 获取服务器响应的内容。
- disconnect(): 关闭连接。
优缺点:
- 优点:比较简单、轻量,适合一般的网络请求。
- 缺点:API 较为底层,处理起来不如一些第三方库方便,且不支持很多现代化功能(例如请求体处理、文件上传等)。
2. HttpClient
HttpClient 是 Apache 提供的一个 HTTP 客户端库,可以用来发送 HTTP 请求。它比 HttpURLConnection 功能更强大,支持更丰富的功能(如请求重试、认证、文件上传等)。
在 Android 中,HttpClient 已经被废弃,但很多老版本的 Android 应用还是使用它。如果你要使用 HttpClient,需要将其作为依赖库导入。
使用示例:
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.CloseableHttpResponse;
import org.apache.http.util.EntityUtils;public class HttpClientExample {public static void main(String[] args) throws Exception {// 创建 HttpClient 实例CloseableHttpClient client = HttpClients.createDefault();// 创建 GET 请求HttpGet request = new HttpGet("https://api.example.com/data");// 设置请求头参数request.setHeader("User-Agent", "Mozilla/5.0");request.setHeader("Accept", "application/json");request.setHeader("Authorization", "Bearer YOUR_ACCESS_TOKEN");// 执行请求CloseableHttpResponse response = client.execute(request);// 获取响应内容HttpEntity entity = response.getEntity();String content = EntityUtils.toString(entity);// 打印响应内容System.out.println("Response Content: " + content);// 关闭连接response.close();client.close();}
}
解释:
- HttpClients.createDefault(): 创建一个默认的
HttpClient实例。 - HttpGet: 创建一个 GET 请求。
- execute(request): 执行 HTTP 请求并获取响应。
- EntityUtils.toString(entity): 从响应中提取字符串数据。
优缺点:
- 优点:功能强大、灵活,适合复杂的请求(如带有认证的请求、文件上传等)。
- 缺点:不再推荐使用,因为 Android 已经移除了
HttpClient,并且它的性能较HttpURLConnection更差。
1. BufferedReader 是什么?
想象一下,你在用吸管喝水。吸管就像是 BufferedReader,它帮助你顺畅地喝水,而不是每次喝一点点。BufferedReader 就是一个帮你快速从大杯子里喝水的吸管,它能一次性把很多水(文本)都吸到嘴里,不需要你每次都喝一点点。
2. getInputStream 是什么?
假设你打开了一瓶饮料,这瓶饮料代表了一个连接,比如网络连接。getInputStream() 就像是打开瓶子后,你从瓶子里倒饮料(数据)出来喝。这时,你得到的饮料是字节流,它是一些看不懂的“数字”,就像是瓶子里的水看不出来是什么口味一样。
3. InputStreamReader 是什么?
现在你有了“饮料”(字节流),但是你还是不清楚它是什么味道,因为它是“数字”。为了知道它是什么味道,你需要一个工具,这个工具叫做 InputStreamReader。它可以把这些“数字”转换成你能理解的“文字”或者“味道”,让你知道你喝的到底是什么。
4. 怎么一起使用这些东西?
假设你在喝饮料,整个过程是这样:
- 打开瓶子(通过
getInputStream()获取字节流)。 - 倒出来(通过
InputStreamReader把字节流转化为我们能理解的文字)。 - 吸管(
BufferedReader)帮你一口气喝更多的水(高效读取文字)。
例子:
假设你想从互联网上读取数据(就像喝一瓶饮料),我们如何做呢?
getInputStream()就像打开瓶子,获取网络上的数据。InputStreamReader就是一个工具,可以把原本难懂的字节“数字”转换成你能读懂的“文字”。BufferedReader就是帮你高效、快速读取每一口“文字”的吸管。
代码例子:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;public class Example {public static void main(String[] args) {try {// 就像打开瓶子,准备读取数据URL url = new URL("https://api.example.com/data");// 让连接到网络HttpURLConnection connection = (HttpURLConnection) url.openConnection();// 获取网络数据(字节流)InputStreamReader inputStreamReader = new InputStreamReader(connection.getInputStream());// 使用BufferedReader(吸管)来读取数据(每次读取一口)BufferedReader reader = new BufferedReader(inputStreamReader);String line;StringBuilder response = new StringBuilder();// 一口一口地读取数据,直到全部读取完while ((line = reader.readLine()) != null) {response.append(line);}// 打印读取到的内容System.out.println(response.toString());// 关闭连接reader.close();connection.disconnect();} catch (IOException e) {e.printStackTrace();}}
}
总结:
getInputStream: 就像是打开瓶子,获取饮料(数据)。InputStreamReader: 就像是一个工具,可以把“数字”变成“文字”。BufferedReader: 就像是吸管,帮你一次性高效地喝掉更多的饮料(读取更多的文字)。
什么是 SOAP?
SOAP(全名是 Simple Object Access Protocol)是一种用来在不同的系统之间交换信息的 协议,特别是在网络上交换数据时非常有用。它通常用于 Web 服务,Web 服务就是不同应用程序之间通过网络进行交流的一种方式。
举个例子:
想象一下,你有一个应用程序,它需要向另一个应用程序请求信息。你可能想要知道天气、股市数据,或者查询数据库里的数据。为了让两个应用程序能够互相交流,它们就需要一种 “通用的语言” 来进行数据交换,这就是 SOAP。
SOAP 的特点:
-
XML格式: SOAP 使用 XML(可扩展标记语言)作为消息的格式。XML 是一种类似于 HTML 的标记语言,可以用来表示结构化的数据。
-
通过 HTTP 传输: SOAP 消息通常是通过 HTTP 发送的,这意味着它可以在 Internet 或 Intranet 上使用。
-
协议无关: SOAP 是一个协议,意味着它独立于操作系统、编程语言和其他技术。只要你的系统支持 HTTP,你就能使用 SOAP。
SOAP 的结构:
SOAP 消息包含几个重要的部分,主要是:
-
Envelope(信封):这是 SOAP 消息的外层包装,用来包含消息的所有内容。
-
Header(头部):可选部分,包含一些消息的元信息(比如认证信息等)。
-
Body(主体):消息的主要内容,就是你要传输的数据。
SOAP 消息的例子:
下面是一个简单的 SOAP 请求消息的例子,使用 XML 格式表示:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"xmlns:web="http://www.example.com/"><soapenv:Header/><soapenv:Body><web:GetWeather><web:CityName>Shanghai</web:CityName></web:GetWeather></soapenv:Body>
</soapenv:Envelope>
<soapenv:Envelope>:是消息的信封,告诉接收方这个消息是一个 SOAP 消息。<soapenv:Body>:是消息的主体部分,包含了你要传递的数据。在这里,我们请求获取天气信息。<web:GetWeather>和<web:CityName>:是你请求的 Web 服务的方法和参数。在这个例子中,你请求的是获取上海的天气。
是的,xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 是固定的,通常不需要更改。
为什么是固定的?
http://schemas.xmlsoap.org/soap/envelope/ 这个 URL 指定了 SOAP 协议的标准格式和结构,它是 SOAP 消息的 命名空间。这个命名空间定义了 SOAP 消息的信封(Envelope),其中包括了消息的头(Header)和主体(Body)部分,任何符合 SOAP 标准的 Web 服务都会使用这个命名空间。
-
区分不同服务的元素:如果你的 Web 服务是
http://www.example.com/,那么在 XML 请求中,所有的与http://www.example.com/相关的元素都应该使用web命名空间。这样就能确保请求中不会与其他 Web 服务产生冲突。 -
中间的接口:可以认为
web命名空间就是连接客户端和服务器之间的“桥梁”,它帮助客户端明确指向某个特定的 Web 服务,并告诉服务器客户端请求的是什么内容。
为什么使用 SOAP?
SOAP 主要用在系统之间进行跨平台通信时,因为它可以使用 HTTP 来发送消息,而 HTTP 几乎可以在所有计算机系统中使用。
SOAP 的缺点:
- 相比一些现代的技术,SOAP 可能比较复杂。
- 它需要使用 XML 来进行消息的包装,比较繁琐,且数据量大。
总结:
- SOAP 是一种标准的协议,用来让不同的计算机系统通过网络交换数据。
- 它使用 XML 格式来表示消息,发送和接收数据。
- SOAP 通常用于 Web 服务,帮助不同的平台和编程语言的应用程序进行通信。
WebService 就像是不同计算机或手机之间的一种"语言"。它让你可以用电脑和其他设备进行沟通,互相交换信息。就像你跟朋友打电话问问题,朋友把答案告诉你,但你和朋友之间得有一个共同的语言或规则来沟通。
举个例子:
假设你想知道你家附近的天气,你可以通过手机向天气公司发出一个请求:“告诉我今天的天气”。然后,天气公司会用它们的计算机把天气信息返回给你。
这个过程的中介就是 WebService。它就像一个邮递员,把你发的问题(请求)带给天气公司(计算机),然后把答案带回给你。
用通俗的话来说:
- WebService 就是一个系统,让两个不一样的设备(比如手机和电脑)通过互联网相互交流和获取数据。
- 你向 WebService 提出一个问题,WebService 会把这个问题发送到一个服务端(比如一个天气系统),然后把回答返回给你。
所以,WebService 本质上就是一种帮助不同计算机之间互相“沟通”的工具,它让你可以从远程的计算机上获取数据或服务,就像从别人那里获取信息一样。
要使用 WebService 在 Android 上进行通信,通常我们会使用 SOAP 或 REST 这两种方式。下面是用 Android 调用 WebService 的一个简单例子,使用 SOAP 协议:
1. 添加依赖项
在 build.gradle 文件中,添加 SOAP 支持的库:
implementation 'com.koushikdutta.async:http:2.0.1'
2. SOAP WebService 调用代码
// 导入必要的库
import android.os.AsyncTask; // 用于异步执行任务
import android.os.Bundle; // 用于处理活动生命周期
import android.widget.TextView; // 用于显示文本信息
import androidx.appcompat.app.AppCompatActivity; // 用于支持现代 Android 活动
import org.ksoap2.SoapEnvelope; // 用于处理 SOAP 协议消息
import org.ksoap2.serialization.SoapObject; // 用于构建 SOAP 请求对象
import org.ksoap2.transport.HttpTransportSE; // 用于发送 SOAP 请求// 创建 MainActivity 类,继承自 AppCompatActivity
public class MainActivity extends AppCompatActivity {// 定义 WebService 的相关常量private static final String NAMESPACE = "http://www.example.com/"; // WebService 的命名空间private static final String URL = "http://www.example.com/webservice"; // WebService 的 URLprivate static final String SOAP_ACTION = "http://www.example.com/GetWeather"; // SOAP 动作private static final String METHOD_NAME = "GetWeather"; // WebService 的方法名称private TextView textView; // 创建一个 TextView 变量用于显示结果@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); // 调用父类的 onCreate 方法setContentView(R.layout.activity_main); // 设置布局文件textView = findViewById(R.id.textView); // 获取布局中的 TextView// 执行异步任务来调用 WebServicenew WebServiceTask().execute(); // 执行 WebServiceTask 异步任务}// 定义一个异步任务类,用于调用 WebServiceprivate class WebServiceTask extends AsyncTask<Void, Void, String> {// doInBackground 方法在后台线程执行@Overrideprotected String doInBackground(Void... params) {try {// 创建 SOAP 请求对象,指定 WebService 的命名空间和方法名SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);// 添加请求参数(城市名称)request.addProperty("CityName", "Shanghai");// 创建 SOAP 包装对象,用于封装请求SoapEnvelope envelope = new SoapEnvelope(SoapEnvelope.VER11); // 使用 SOAP 1.1 版本envelope.setOutputSoapObject(request); // 设置请求对象// 创建 HTTP 请求传输对象,用于向 WebService 发送请求HttpTransportSE transport = new HttpTransportSE(URL); // 使用指定的 URLtransport.call(SOAP_ACTION, envelope); // 发送请求,调用 SOAP 方法// 获取 WebService 返回的响应SoapObject response = (SoapObject) envelope.getResponse(); // 获取响应对象return response.getProperty(0).toString(); // 获取响应的第一个属性值(即返回的天气信息)} catch (Exception e) {e.printStackTrace(); // 如果发生错误,打印异常信息return "Error"; // 返回错误信息}}// onPostExecute 方法在主线程执行,用于更新 UI@Overrideprotected void onPostExecute(String result) {// 在 UI 上显示 WebService 返回的结果textView.setText(result); // 将结果显示在 TextView 中}}
}
代码的解释:
private static final String NAMESPACE = "http://www.example.com/"; // WebService 的命名空间
private static final String URL = "http://www.example.com/webservice"; // WebService 的 URL
private static final String SOAP_ACTION = "http://www.example.com/GetWeather"; // SOAP 动作
private static final String METHOD_NAME = "GetWeather"; // WebService 的方法名称
- NAMESPACE:是 WebService 的命名空间,用来区分不同 WebService 的方法。它类似于一个标签,帮助服务器识别你请求的是哪个服务。
- URL:是 WebService 服务器的地址,告诉你请求的服务在哪儿。
- SOAP_ACTION:是 WebService 对应的动作,类似于方法,告诉服务器你要做的具体操作。
- METHOD_NAME:表示你请求的具体方法名,告诉服务器你想做什么(例如查询天气、获取数据等)。
总结:
- URL:指向服务器的地址,就像你去某个地方的门牌号。
- METHOD_NAME:表示你想做什么(比如查询天气,叫做
GetWeather)。 - 请求参数:告诉 WebService 你需要哪些数据(例如城市名
Shanghai)。
1. WebService 端 (模拟):
为了理解 WebService 调用,我们可以先创建一个简单的 WebService 端。假设 WebService 提供一个天气查询接口,客户端通过 SOAP 请求发送城市名称,WebService 返回该城市的天气。
示例 WebService (假设已发布在服务器上)
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.example.com/"><soapenv:Header/><soapenv:Body><web:GetWeather><web:CityName>Shanghai</web:CityName></web:GetWeather></soapenv:Body>
</soapenv:Envelope>
这个示例包含一个 GetWeather 方法,它接受一个 CityName 参数,返回该城市的天气。
服务器端实现代码(示例):
为了在服务器端返回 Shanghai 的天气信息,你需要在 WebService 服务端编写代码来接收 SOAP 请求并返回响应。这里我们假设使用 Java 和 JAX-WS 来实现一个简单的 WebService。
import javax.jws.WebMethod;
import javax.jws.WebService;@WebService
public class WeatherService {// 定义一个方法,模拟获取城市天气@WebMethodpublic String GetWeather(String CityName) {// 根据城市名称返回天气信息(这里只是一个简单的示例)if ("Shanghai".equalsIgnoreCase(CityName)) {return "Temperature in Shanghai: 25°C"; // 返回天气信息} else {return "City not found"; // 返回未找到城市的信息}}
}
2. 客户端 (Android 中调用 WebService):
这个 Android 客户端代码通过 ksoap2 库发送 SOAP 请求,调用 WebService,并展示返回结果。
WebService 调用代码:
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.transport.HttpTransportSE;public class MainActivity extends AppCompatActivity {// WebService 的相关常量private static final String NAMESPACE = "http://www.example.com/"; // WebService 的命名空间private static final String URL = "http://www.example.com/webservice"; // WebService 的 URLprivate static final String SOAP_ACTION = "http://www.example.com/GetWeather"; // SOAP 动作private static final String METHOD_NAME = "GetWeather"; // WebService 的方法名称private TextView textView; // 显示结果的 TextView@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main); // 设置布局文件textView = findViewById(R.id.textView); // 获取 TextView 实例// 执行异步任务来调用 WebServicenew WebServiceTask().execute(); // 执行任务}// 定义一个异步任务,用于调用 WebServiceprivate class WebServiceTask extends AsyncTask<Void, Void, String> {// 在后台线程执行 WebService 调用@Overrideprotected String doInBackground(Void... params) {try {// 创建 SOAP 请求对象,指定命名空间和方法名SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);// 添加请求参数(城市名称)request.addProperty("CityName", "Shanghai");// 创建 SOAP 包装对象SoapEnvelope envelope = new SoapEnvelope(SoapEnvelope.VER11); // 使用 SOAP 1.1 版本envelope.setOutputSoapObject(request); // 设置请求对象// 创建 HTTP 请求传输对象HttpTransportSE transport = new HttpTransportSE(URL);transport.call(SOAP_ACTION, envelope); // 发送请求并获取响应// 获取响应结果SoapObject response = (SoapObject) envelope.getResponse();return response.getProperty(0).toString(); // 返回天气信息} catch (Exception e) {e.printStackTrace(); // 出现错误时打印异常return "Error"; // 返回错误信息}}// 在主线程更新 UI@Overrideprotected void onPostExecute(String result) {textView.setText(result); // 显示 WebService 返回的结果}}
}
相关文章:
安卓基础(持续更新的笔记)
为什么要这样: // 创建请求体RequestBody body RequestBody.create(MediaType.parse("application/json; charsetutf-8"),jsonObject.toString()); jsonObject 就包含了一个 JSON 数据,它其实就是: {"name": "张…...
10. Hbase Compaction命令
一. 什么是Compaction 在 HBase 中,频繁进行数据插入、更新和删除操作会生成许多小的 HFile,当 HFile 数量增多时,会影响HBase的读写性能。此外,垃圾数据的存在也会增加存储需求。因此,定期进行 Compact操作ÿ…...
在 UniApp 项目中设置多语言
在 UniApp 项目中设置多语言支持可以通过以下步骤实现: 1. 安装依赖 首先,你需要安装 vue-i18n 插件来处理多语言支持。 npm install vue-i18n --save2. 创建语言文件 在项目中创建一个 lang 文件夹,用于存放不同语言的翻译文件。例如&am…...
告别卡关!XSS挑战之旅全关卡通关思路详解
XSS挑战之旅 XSS测试思路Level1Level2Level3Level4Level5Level6Level7Level8Level9Level10Level11Level12Level13Level14Level15Level16Level17Level18Level19Level20免责声明: XSS测试思路 确定输入输出点: 寻找URL参数、表单输入、HTTP头(R…...
SpringCloud框架下的注册中心比较:Eureka与Consul的实战解析
摘要 在探讨SpringCloud框架中的两种注册中心之前,有必要回顾单体架构与分布式架构的特点。单体架构将所有业务功能集成在一个项目中,优点是架构简单、部署成本低,但耦合度高。分布式架构则根据业务功能对系统进行拆分,每个模块作…...
【Java】分布式锁Redis和Redisson
https://blog.csdn.net/weixin_44606481/article/details/134373900 https://www.bilibili.com/video/BV1nW421R7qJ Redis锁机制一般是由 setnx 命令实现,set if not exists,语法setnx key value,将key设置值为value,如果key不存在…...
Python的imutils库详细介绍
imutils 是一个专为简化OpenCV(计算机视觉库)常见操作而设计的Python工具库,提供了一系列便捷函数,使图像和视频处理更加高效和简洁。以下是对其功能、安装及用法的详细介绍: 1. 安装方法 通过pip安装: p…...
蓝桥杯 Java B 组之简单动态规划(爬楼梯、斐波那契数列)
Day 6:简单动态规划(爬楼梯、斐波那契数列) 动态规划(Dynamic Programming,简称 DP)是计算机科学中的一种算法设计思想,用来解决最优解问题,它的核心思想是将大问题分解为小问题&am…...
Hive增量迁移方案与实操PB级
客户一共1PB数据,每天新增10T,有些表只保留3天。 需要客户提供: a.tbl_size(大小GB) a.last_mtime(最新更新时间) a.tbl_ttl(保留时间) b.last_part_dt(分区值) b.last_part_size(最新分区大小) t_day(表更新规律,t几) 因为目前…...
【练习】【双指针】力扣热题100 283. 移动零
题目 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输入: nums [0] 输出…...
Python 依赖管理的革新——Poetry 深度解析
引言 在 Python 生态中,依赖管理一直是开发者关注的重要话题。从最初的 pip 和 virtualenv,到后来的 pipenv,Python 依赖管理工具不断进化。而近年来,Poetry 作为一款集成包管理和虚拟环境管理的新兴工具,逐渐获得了广…...
从零开始学Python爬虫:(二)使用基本库urllib(下)
一、异常处理 关于某些情况下,可能会出现异常,如果不处理它们,会发生很多错误。 而urllib库提供了error模块来处理这些异常,该模块包括以下功能: (1)URLError 该类含有一个属性reason&#x…...
电商分布式场景中如何保证数据库与缓存的一致性?实战方案与Java代码详解
文章目录 一、缓存一致性问题的本质写后读不一致:更新数据库后,缓存未及时失效并发读写竞争:多个线程同时修改同一数据缓存与数据库事务不同步:部分成功导致数据错乱 二、5大核心解决方案与代码实现方案1:延迟双删策略…...
kamailio中Core Cookbook 核心配置手册
Core Cookbook 核心配置手册 版本: Kamailio SIP 服务器 v6.0.x (稳定版) 概述 本教程收集了 Kamailio 核心导出到配置文件的功能和参数。 注意: 本页参数未按字母顺序排列。 结构 kamailio.cfg 的结构可分为三部分: 全局参数模块设置路由块 建议按此顺序排列以保持清晰…...
【嵌入式Linux应用开发基础】read函数与write函数
目录 一、read 函数 1.1. 函数原型 1.2. 参数说明 1.3. 返回值 1.4. 示例代码 二、write 函数 2.1. 函数原型 2.2. 参数说明 2.3. 返回值 2.4. 示例代码 三、关键注意事项 3.1 部分读写 3.2 错误处理 3.3 阻塞与非阻塞模式 3.4 数据持久化 3.5 线程安全 四、嵌…...
一、OpenSM 架构部署及原理详解
目录 一、OpenSM 架构与核心功能 1. InfiniBand 子网管理器(SM)的作用 2. OpenSM 的架构 二、OpenSM 部署步骤(以 Linux 为例) 1. 安装依赖与软件包 2. 配置文件 3. 启动 OpenSM 服务 4. 验证部署 5. 高可用性配置(可选) 三、OpenSM 工作原理详解 1. 拓扑发现(…...
2526考研资料分享 百度网盘
通过网盘分享的文件:01、2026【考研数学】 链接:https://pan.baidu.com/s/1PwMzp_yCYqjBqa7492mP3w?pwd98wg 提取码:98wg--来自百度网盘超级会员v3的分享 通过网盘分享的文件:01、2026【考研政治】 链接:https://pan.baidu.com/s/1PwMzp_yCYqjBqa7492…...
15.1 Process(进程)类
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 通常开发时想要获得进程是比较困难的事,必须要调用CreateToolhelpSnapshot、ProcessFirst、ProcessNext等API或者诸如 Zw…...
事件传递和监控
今天介绍一下UIApplication的函数 - (BOOL)sendAction:to:from:forEvent: - (BOOL)sendAction:to:from:forEvent: 是 UIApplication 类中的一个方法,主要用于发送事件响应链中的动作(action)。它允许应用程序从一个特定的发送者(…...
CentOS 7 企业级Redis 7部署指南
CentOS 7 企业级Redis 7部署指南 目录导航 一、环境准备 1.1 依赖管理 二、离线安装 2.1 源码编译安装2.2 目录结构规范 三、生产配置 3.1 主配置文件3.2 配置生成脚本 四、系统集成 4.1 Systemd服务文件4.2 服务管理命令 五、安全加固 5.1 网络安全配置5.2 审计配置 六、性能…...
Python创建Excel的方式——提供4中方式可供参考
目录 专栏导读库的安装代码1——pandas代码2——openpyxl代码3——xlsxwriter代码4——xlwings总结 专栏导读 🌸 欢迎来到Python办公自动化专栏—Python处理办公问题,解放您的双手 🏳️🌈 博客主页:请点击——>…...
消息中间件深度剖析:以 RabbitMQ 和 Kafka 为核心
在现代分布式系统和微服务架构的构建中,消息中间件作为一个不可或缺的组件,承担着系统间解耦、异步处理、流量削峰、数据传输等重要职能。尤其是在面临大规模并发、高可用性和可扩展性需求时,如何选择合适的消息中间件成为了开发者和架构师们…...
回文数:简单问题中的多种优化思路
回文数:简单问题中的多种优化思路 引言 回文数(Palindrome Number)是一个有趣的问题,在算法竞赛、面试、甚至一些实际应用场景中都会遇到。最直观的方式是将数字转换成字符串,然后反转比较。但仅仅满足“能解”是不够…...
大语言模型简史:从Transformer(2017)到DeepSeek-R1(2025)的进化之路
2025年初,中国推出了具有开创性且高性价比的「大型语言模型」(Large Language Model — LLM)DeepSeek-R1,引发了AI的巨大变革。本文回顾了LLM的发展历程,起点是2017年革命性的Transformer架构,该架构通过「…...
java八股文-spring
目录 1. spring基础 1.1 什么是Spring? 1.2 Spring有哪些优点? 1.3 Spring主要模块 1.4 Spring常用注解 1.5 Spring中Bean的作用域 1.6 Spring自动装配的方式 1.7 SpringBean的生命周期 1.8 多级缓存 1.9 循环依赖? 1 .8.1 原因 1.8…...
机器学习--实现多元线性回归
机器学习—实现多元线性回归 本节顺延机器学习--线性回归中的内容,进一步讨论多元函数的回归问题 y ′ h ( x ) w ⊤ ∙ x b y^{\prime}h(x)w^\top\bullet xb y′h(x)w⊤∙xb 其中, w T ⋅ x 就是 W 1 X 1 w 2 X 2 w 3 X 3 ⋯ w N X N \text{其中,}w^\math…...
vue3响应式丢失解决办法(三)
vue3的响应式的理解,与普通对象的区别(一) vue3 分析总结响应式丢失问题原因(二) 经过前面2篇文章,知道了响应式为什么丢失了,但是还是碰到了丢失情况,并且通过之前的内容还不能解…...
NLP 八股 DAY1:BERT
BERT全称:Pre-training of deep bidirectional transformers for language understanding,即深度双向Transformer。 模型训练时的两个任务是预测句⼦中被掩盖的词以及判断输⼊的两个句⼦是不是上下句。在预训练 好的BERT模型后⾯根据特定任务加上相应的⽹…...
蓝桥与力扣刷题(230 二叉搜索树中第k小的元素)
题目:给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 小的元素(从 1 开始计数)。 示例 1: 输入:root [3,1,4,null,2], k 1 输出:1示例 2ÿ…...
半遮挡检测算法 Detecting Binocular Half-Occlusions
【1. 背景】: 本文分析【Detecting Binocular Half-Occlusions:Empirical Comparisons of Five Approaches】Geoffrey Egnal和Richard P. Wildes于2002年发表在IEEE Transactions on Pattern Analysis and Machine Intelligence上,这是1篇中…...
