Retrofit 2.5框架使用与源码分析

2023-11-11

Retrofit 框架使用

请求内容与返回值

使用PostMan进行请求测试
请求:https://api.github.com/search/repositories?q=android

返回值:

Header:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AJwMe2by-1575109468105)(/assets/Retrofit.png)]

Body:

{
"total_count": 943593,
"incomplete_results": false,
"items": [
{
"id": 82128465,
"node_id": "MDEwOlJlcG9zaXRvcnk4MjEyODQ2NQ==",
"name": "Android",
"full_name": "open-android/Android",
"private": false,
"owner": {
"login": "open-android",
"id": 23095877,
"node_id": "MDQ6VXNlcjIzMDk1ODc3",
"avatar_url": "https://avatars2.githubusercontent.com/u/23095877?v=4",
//……
},
"html_url": "https://github.com/open-android/Android",
"description": "GitHub上最火的Android开源项目,所有开源项目都有详细资料和配套视频",
"fork": false,
"url": "https://api.github.com/repos/open-android/Android",
//……
},
{
"id": 12544093,
"node_id": "MDEwOlJlcG9zaXRvcnkxMjU0NDA5Mw==",
"name": "Android",
"full_name": "hmkcode/Android",
"private": false,
"owner": {
"login": "hmkcode",
"id": 3790597,
//……
},
//……
}
]
}
引入Retrofit依赖
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
根据返回的请求结果定义Repository Bean类

返回的报文采用google.gson进行处理,金处理必要的值

public class RepoBean {

//用于表示Repo id
private int id;
//用于表示RepoName
private String name;

//用于表示完整名称
//Repository中json的返回值为 `full_name`,与定义的变量名不一致,使用注解`@SerializedName`进行标注
@SerializedName("full_name")
private String fullName;
//省略getter和setter
//……
}

根据返回的请求结果定义一次查询结果
public class SearchRepoBean {

//用于表示仓库数量
@SerializedName("total_count")
private int totalCount;
//用于表示是否为完整结果
private boolean incompleteResults;
//用于表示持有的所有的仓库类
private List<RepoBean>items;

//省略getter和setter
//……
}

定义网络请求API接口
public interface GithubService {
//@Get注解,表示以Get方法发送网络请求
//返回类型为Call<SearchRepoBean>,SearchRepoBean是接收数据的类,可以自定义
@GET("search/repositories")
Call<SearchRepoBean> getRepoInfo(@Query("q") String query);
}

初始化Retrofit实例,生成接口实现类

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/") //设置网络请求的URL地址
.addConverterFactory(GsonConverterFactory.create()) //设置数据解析器
.build();

githubService = retrofit.create(GithubService.class);

进行网络请求

Call<SearchRepoBean> call = githubService.getRepoInfo("Android");
//同步请求方式
//call.request();
//异步请求方式
call.enqueue(new Callback<SearchRepoBean>() {
@Override
public void onResponse(Call<SearchRepoBean> call, Response<SearchRepoBean> response) {
//输出请求结果
// LogUtils.printInfo("搜索到的仓库的数量:" + response.body().getItems().size());
// List<RepoBean>repoBeans=new ArrayList<>();
// repoBeans.addAll(response.body().getItems());
// for (int i=repoBeans.size()-1;i>=0;i--){
// LogUtils.printInfo(repoBeans.get(i).getFullName());
// }
}

@Override
public void onFailure(Call<SearchRepoBean> call, Throwable t) {
}
});
将请求值的返回设为LiveData

将请求的返回值设为LiveData可以通过为Retrofit添加CallAdapterFactory来实现

public interface GithubService {
@GET("search/repositories")
LiveData<SearchRepoBean> getRepoInfo(@Query("q") String query);
}

自定义LiveDataCallAdapterFactory

public class LiveDataCallAdapterFactory extends CallAdapter.Factory {

@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {

//用于获取泛型的参数
Type observerType = getParameterUpperBound(0, (ParameterizedType) returnType);

Class<?> rawObserverType = getRawType(observerType);


LiveDataCallAdapter<Object> liveDataCallAdapter = new LiveDataCallAdapter<>(rawObserverType);

return liveDataCallAdapter;
}
}


自定义 LiveDataCallAdapter


public class LiveDataCallAdapter<R> implements CallAdapter<R, LiveData<SearchRepoBean>> {

private Type responseType;

public LiveDataCallAdapter(Type responseType){
this.responseType=responseType;
}

@Override
public Type responseType() {
return responseType;
}

@Override
public LiveData<SearchRepoBean> adapt(final Call<R> call) {

LiveData<SearchRepoBean>searchRepoBeanLiveData=new LiveData<SearchRepoBean>() {

@Override
protected void onActive() {
super.onActive();
call.enqueue(new Callback<R>() {
@Override
public void onResponse(Call<R> call, Response<R> response) {
postValue((SearchRepoBean) response.body());
}

@Override
public void onFailure(Call<R> call, Throwable t) {
LogUtils.printInfo("error");
}
});
}
};
//这里的return 即为下文中githubService.getRepoInfo("Android")调用的返回值
return searchRepoBeanLiveData;
}
}

为Retrofit实例添加CallAdapterFactory

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(new LiveDataCallAdapterFactory())
.build();

调用方法


repoBeanLiveData = githubService.getRepoInfo("Android");
repoBeanLiveData.observe(GithubApiActivity.this, new Observer<SearchRepoBean>() {
@Override
public void onChanged(SearchRepoBean searchRepoBean) {
//输出结果
}
});

添加通用的响应实体

通过LiveDataCallAdapterLiveDataCallAdapterFactory 可以将返回的数据表示为LiveData数据形式,且只能对返回结果为SearchRepoBean类型的JSON字符串进行处理。如果是返回其他的实体则需要重新构造适配器。

定义一个通用的响应实体

public class ApiResponse<T> {

public ApiResponseSuccess<T> create(Response<T> response) {
if (response.isSuccessful()) {
return new ApiResponseSuccess<T>(response.body());
} else {
return null;
}
}

//用于表示返回成功的值
public static class ApiResponseSuccess<T> extends ApiResponse<T> {
/用于表示请求返回成功的内容,在本代码中是SearchRepoBean
private T body;

public ApiResponseSuccess(T body) {
this.body = body;
}

public T getBody() {
return body;
}
}
}

修改LiveDataCallAdapterFactory

public class LiveDataCallAdapterFactory extends CallAdapter.Factory {

@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
//用于获取泛型的参数
//return type为LiveData<ApiResponse<SearchRepoBean>>
//observerType为ApiResponse<SearchRepoBean>
Type observerType = getParameterUpperBound(0, (ParameterizedType) returnType);
//bodyType为SearchRepoBean
Type bodyType = getParameterUpperBound(0, (ParameterizedType) observerType);
LiveDataCallAdapter<Object> liveDataCallAdapter = new LiveDataCallAdapter<>(bodyType);

return liveDataCallAdapter;
}
}

修改LiveDataCallAdapter

public class LiveDataCallAdapter<R> implements CallAdapter<R,LiveData<ApiResponse<R>>> {

private Type responseType;

public LiveDataCallAdapter(Type responseType){
this.responseType=responseType;
}

@Override
public Type responseType() {
return responseType;
}

@Override
public LiveData<ApiResponse<R>> adapt(final Call<R> call) {
LiveData<ApiResponse<R>> result=new LiveData<ApiResponse<R>>() {
@Override
protected void onActive() {
super.onActive();
call.enqueue(new Callback<R>() {
@Override
public void onResponse(Call<R> call, Response<R> response) {
postValue(new ApiResponse<R>().create(response));
}

@Override
public void onFailure(Call<R> call, Throwable t) {
// LogUtils.printInfo("+++++!2312qwqweww31");
}
});
}
};
return result;
}
}

修改调用方法

repoBeanLiveData = githubService.getRepoInfo("Android");
repoBeanLiveData.observe(GithubApiActivity.this, new Observer<ApiResponse<SearchRepoBean>>() {
@Override
public void onChanged(ApiResponse<SearchRepoBean> searchRepoBeanApiResponse) {
SearchRepoBean searchRepoBean = (SearchRepoBean) ((ApiResponse.ApiResponseSuccess) searchRepoBeanApiResponse).getBody();
//输出结果
}
});

源码详解

Retrofit构建中的.baseUrl("https://api.github.com/")介绍

Retrofit源碼,Retrofit在源码中使用建造者模式进行实例化,将String类型的地址转换为OKhttp3中的HttpUrl类型


public final class Retrofit {

public static final class Builder {
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
return baseUrl(HttpUrl.get(baseUrl));
}
public Builder baseUrl(HttpUrl baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
}
}

Retrofit构建中的.addConverterFactory(GsonConverterFactory.create())

通过.addConverterFactory()传入我们需要的ConverFactory,目的是将responseBody转换成我们的Bean类,在这里我们使用的是GsonConverterFactory

public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}

Converter接口源码,核心是T convert(F value),将F类型的数据转换为T类型


public interface Converter<F, T> {
//将F类型的数据转换为T类型
@Nullable T convert(F value) throws IOException;

//根据数据类型创建Converter创建 Converter
abstract class Factory {
//将HTTP响应的body体转换成type,type是由CallAdapter 接口里面的responseType()函数返回的。
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations, Retrofit retrofit) {
return null;
}

//将API方法的输入参数使用注解@Body, @Part 和 @PartMap标记的类型,从type转换为RequestBody
public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
//将API方法的输入参数使用注解@Header, @HeaderMap, @Path, @Query 和 @QueryMap 标记的类型从type转换为String
public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}

protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}

protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}

Retrofit构建中的.addCallAdapterFactory(new LiveDataCallAdapterFactory())

用于添加数据适配器,在HttpServiceMethod实例生成的时候会调用

public final class Retrofit {
final List<CallAdapter.Factory> callAdapterFactories;
//…………
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
callAdapterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
//…………
}

最终用来创建Service的代码retrofit.create(GithubService.class)

create()采用代理的方式进行创建,

public final class Retrofit {
//……
public <T> T create(final Class<T> service) {
//判断定义的接口服务是否可用
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];

@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// 如果是Object本身的方法,正常调用后返回
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//如果是platform默认的方法,正常调用后返回
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//解析我们定义的网络请求的方法
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
//……
}

loadServiceMethod(Method method)源码解析,其实际上是HttpServiceMethod对象


ServiceMethod<?> loadServiceMethod(Method method) {
//从解析的缓存中获取
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;

synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method)源码

abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//RequestFactory负责解析接口并且生成Request
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

//…………
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}

abstract T invoke(Object[] args);
}


HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)源码


//将一个接口方法转变为一个Http请求
final class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
//创建HTTP请求的CallAdapter,在下面有createCallAdapter()源码
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
//……
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);

okhttp3.Call.Factory callFactory = retrofit.callFactory;
return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
}

private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
Retrofit retrofit, Method method) {
Type returnType = method.getGenericReturnType();
Annotation[] annotations = method.getAnnotations();
try {
//retrofit.callAdapter()返回 Retrofit实例化中.addCallAdapterFactory(new LiveDataCallAdapterFactory())添加的CallAdapter
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create call adapter for %s", returnType);
}
}

//…………

private final RequestFactory requestFactory;
private final okhttp3.Call.Factory callFactory;
private final CallAdapter<ResponseT, ReturnT> callAdapter;
private final Converter<ResponseBody, ResponseT> responseConverter;

private HttpServiceMethod(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
CallAdapter<ResponseT, ReturnT> callAdapter,
Converter<ResponseBody, ResponseT> responseConverter) {
this.requestFactory = requestFactory;
this.callFactory = callFactory;
this.callAdapter = callAdapter;
this.responseConverter = responseConverter;
}

//代理调用的invoke最终会调用下面invoke方法
@Override ReturnT invoke(Object[] args) {
return callAdapter.adapt(
new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}
}


`call.enqueue(new Callback<SearchRepoBean>() {})`最终调用的方法是OkhttpCall中的`call.enqueue(new okhttp3.Callback() {})`

```java

final class OkHttpCall<T> implements Call<T> {

//……
@Override public void enqueue(final Callback<T> callback) {

//……
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
//……
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
//……
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Retrofit 2.5框架使用与源码分析 的相关文章

  • 如何对这个字符串进行子串化

    我想得到这个字符串的 4 个部分 String string 10 trillion 896 billion 45 million 56873 我需要的4个部分是 10万亿 8960亿 4500万 和 56873 我所做的是删除所有空格 然
  • 使用workmanager时Firestore脱机持久性错误

    我正在使用一个WorkManger定期从我的中检索信息Firestore当应用程序处于后台和前台时的数据库 此信息用于根据状态更新 UI 因此不同的状态会添加或删除 UI 的不同部分 第一次运行时效果很好 但是 一旦应用程序处于后台并且Wo
  • React Native 从 JavaScript 代码内部访问 strings.xml

    有没有办法访问当前值android app src main res values strings xml从 JavaScript 代码内部 我想为每个构建放置不同的端点 URL 但我什至无法检测到反应本机代码内的构建类型 而不必求助于 D
  • android中向sqlite中插入大量数据

    目前 我必须一次向我的 Android 中插入超过 100 亿条数据 然而 内存不足的问题会使程序崩溃 sqlite 插入测试非常简单 只需使用 for 循环生成 sql 插入命令并通过 开始 和 提交 进行包装 private Array
  • 卸载后 Web 应用程序不显示“添加到主屏幕”

    这是我第一次创建网络应用程序 我设法解决了这个问题 所以我得到了实际的 chrome 提示 将其添加到主屏幕 然后我从手机上卸载了该网络应用程序 因为我想将其展示给我的同事 但是 屏幕上不再出现提示 问题 这是有意为之的行为还是我的应用程序
  • Android 后退按钮无法与 Flutter 选项卡内的导航器配合使用

    我需要在每个选项卡内有一个导航器 因此当我推送新的小部件时 选项卡栏会保留在屏幕上 代码运行得很好 但是 android 后退按钮正在关闭应用程序而不是运行 Navigator pop import package flutter mate
  • CardView 圆角获得意想不到的白色

    When using rounded corner in CardView shows a white border in rounded area which is mostly visible in dark environment F
  • Android Activity 生命周期函数基础知识

    我正在测试这段代码 它显示活动所处的状态 public class Activity101Activity extends Activity String tag Lifecycle Called when the activity is
  • Adobe 是否为其 PDF 阅读器提供 Android SDK 或 API? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我希望能够在我们的应用程序内的视图中显示本地 PDF 文件 在 Android 4 03 下的平板电脑上运行 目前 我们将 Adob eR
  • 使用 Android 发送 HTTP Post 请求

    我一直在尝试从 SO 和其他网站上的大量示例中学习 但我无法弄清楚为什么我编写的示例不起作用 我正在构建一个小型概念验证应用程序 它可以识别语音并将其 文本 作为 POST 请求发送到 node js 服务器 我已确认语音识别有效 并且服务
  • 你的CPU不支持NX

    我刚刚下载了 android studio 但是我遇到了一个问题 当我运行它时 它说你的 cpu 不支持 NX 我应该怎么办 NX 或实际上是 NX 处理器位 是处理器的一项功能 有助于保护您的 PC 免受恶意软件的攻击 当此功能未启用并且
  • 在 SQLite 中搜索时排除 HTML 标签和一些 UNICODE 字符

    更新 4 我已经成功运行了firstchar例如 但现在的问题是使用regex 即使包含头文件 它也无法识别regex操作员 有什么线索可以解决这个问题吗 更新 2 我已经编译了sqlite3我的项目中的库 我现在正在寻找任何人帮助我为我的
  • 我想实现下面的布局,按钮应该在屏幕底部,当惰性列被填充时,按钮不应该出去

    顶部有惰性列 惰性列下方有输入电话号码布局并从电话簿布局添加联系人 我希望当未添加联系人时此布局位于顶部 当我添加大量联系人时输入电话号码并添加电话簿布局中的联系人会随着惰性列滚动并移出屏幕 我不让他们走出屏幕 当接触较多时 它们必须粘在底
  • 如何发布Android .aar源以使Android Studio自动找到它们?

    我正在将库发布到内部 Sonatype Nexus 存储库 Android Studio 有一个功能 可以自动查找通过 gradle 引用的库的正确源 我将 aar 的源代码作为单独的 jar 发布到 Nexus 但 Android Stu
  • 在 android DatePickerDialog 中将语言设置为法语

    有什么办法可以让日期显示在DatePickerDialog用法语 我已经搜索过这个但没有找到结果 这是我的代码 Calendar c Calendar getInstance picker new DatePickerDialog Paym
  • 错误:在根项目“projectName”中找不到项目“app”

    我有一个在 Eclipse 中开发的旧应用程序 现在尝试将其迁移到 Android Studio 我更新了库并遵循了基本步骤 现在 我收到此错误 Error Project app not found in root project pro
  • Android访问远程SQL数据库

    我可以直接从 Android 程序访问远程 SQL 数据库 在网络服务器上 吗 即简单地打开包含所有必需参数的连接 然后执行 SQL 查询 这是一个私人程序 不对公众开放 仅在指定的手机上可用 因此我不担心第三方获得数据库访问权限 如果是这
  • 实现滚动选择 ListView 中的项目

    我想使用 ListView 您可以在其中滚动列表来选择一个项目 它应该像一个 Seekbar 但拇指应该是固定的 并且您必须使用该栏来调整它 我面临的一个问题是 我不知道这种小部件是如何调用的 这使得我很难搜索 所以我制作了下面这张图片 以
  • 将两个文本视图并排放置在布局中

    我有两个文本视图 需要在布局中并排放置 并且必须遵守两条规则 Textview2 始终需要完整显示 如果布局中没有足够的空间 则必须裁剪 Textview1 例子 文本视图1 文本视图2 Teeeeeeeeeeeeeeeeeextview1
  • android sdk 的位置尚未在 Windows 操作系统的首选项中设置

    在 Eclipse 上 我转到 windows gt Android SDK 和 AVD Manager 然后弹出此消息 Android sdk 的位置尚未在首选项中设置 进入首选项 在侧边栏找到 Android 然后会出现一个 SDK 位

随机推荐

  • linux内核历史版本及网址介绍

    官网 https www kernel org 最新版本4 12 rc4 Protocol Location HTTP https www kernel org pub GIT https git kernel org RSYNC rsyn
  • esBuild + SWC 构建 TS 项目

    1 esBuild 介绍 在 esbuild 的官方介绍中打包 threejs 只需要 0 37 秒 Esbuild 是一个非常新的模块打包工具 它提供了与 Webpack Rollup Parcel 等工具 相似 的资源打包能力 却有着高
  • 两个3*3的卷积核替代5*5(三个3*3卷积核替代7*7)分析

    文章目录 为什么一个5x5的卷积核可以用两个3x3的卷积核来替代 一个5 5卷积 两个3 3卷积核 为什么一个7x7的卷积核可以用三个个3x3的卷积核来替代 一个7 7卷积 三个3 3卷积核 优点总结 为什么一个5x5的卷积核可以用两个3x
  • 输入一个字符串,把一个字符串的字符逆序输出

    package com qf day4 import java util Scanner public class Test29 public static void main String args 把一个字符串的字符逆序输出 Scann
  • 可能是最详细的React组件库搭建总结

    可能是最详细的React组件库搭建总结 概览 本文包含以下内容 prepare 组件库前期开发准备工作 eslint commit lint typescript等等 dev 使用docz进行开发调试以及文档编写 build umd cjs
  • TeamViewer账号未激活问题

    出现如下问题 解决步骤 1 点击重新发送电子邮件 2 网页上登录 3 QQ邮箱里面添加设备信任 4 返回登录页面再重新 刷新重新输入登录信息登录 然后重新发送电子邮件到qq邮箱 5 点击激活 6 登录 gt gt gt 不要现在登录 gt
  • JAVA各种加密与解密方式

    之前有兴趣研究了一下java的加密与解密的方法 发现市面上有好多种加密解密方式 在这里整理了一下 目录 1 BASE64加密 解密 2 MD5 Message Digest Algorithm 加密 3 DES Data Encryptio
  • 将 pip 的默认源修改为阿里源(Windows 版)

    背景 由于 python 自带的源下载速度非常慢 特别是安装一些库的时候 甚至有时会失败 临时替换 临时替换直接使用以下命令即可 pip install 包名 i 源地址 例如 pip install numpy i http mirror
  • Visual Studio无法打开源文件错误

    在写用Visual Studio跨平台Linux项目的时候 遇到了无法打开源文件错误 主要原因是include目录里面没有这些文件 解决方法是 把Linux的 usr include目录压缩下载在本地 zip r usr include z
  • js 导出excel详解

    一 需要安装 npm install xlsx style Blob js 和Export2Excel js 在网上搜都可以找到的 而Export2Excel我做了修改 代码如下 带 的都是我改动的地方 Export2Excel js es
  • SQL中CASE的用法

    在SQL中 CASE语句是一种条件表达式 用于根据条件执行不同的操作 它有两种形式 简单CASE表达式和搜索CASE表达式 简单CASE表达式的语法如下 CASE expression WHEN value1 THEN result1 WH
  • GEO数据下载及处理详细过程

    GEO2R 如果出现提示 请指定GEO系列加入和平台 单击 定义组 并输入您计划比较的样品组的名称 例如测试和控制 将样本分配给每个组 突出显示Sample行 然后单击组名称以将这些Samples分配给该组 使用样本元数据 标题 源和特征
  • C++ 强制类型转换(const_cast/reinterpret_cast)使用详解

    一 const cast用法 const cast lt new type gt expression 用于转换指针或引用 可以去掉类型的const属性 在c 参考文档网站上 const cast conversion cppreferen
  • 用力抱一下APP国际化

    APP国际化 说的直白应该也叫本土化或者本地化 如果你的应用上线到谷歌应用市场 那么应该做好本地化的支持 用来支持不同语言及地区的风俗习惯 当然也要结合公司拓展的海外市场需要 那么对于一款应用 至少应该做到多语言和多布局的支持 最近忙于阿拉
  • rocketmq顺序发送消息

    1 概念 严格顺序消息模式下 消费者收到的所有消息均是有顺序的 消息有序指的是可以按照消息的发送顺序来消费 FIFO RocketMQ可以严格的保证消息有序 可以分为分区有序或者全局有序 顺序消费的原理解析 在默认的情况下消息发送会采取Ro
  • (二)MySQL的安装、启动/停止/连接、卸载

    本篇魔镜为大家介绍MySQL的安装 启动 停止 客户端连接 卸载 安 装 在学习SQL语言时 我们总是避免不了使用关系型数据库管理系统 RDBMS 云端的RDBMS使用时比单机的RDBMS更麻烦 而在常用DBMS的安装等问题上 总是有小伙伴
  • h5 原生 ajax,原生ajax和axios取消请求实现

    原生ajax中取消请求的方法 const xhr new XMLHttpReques xhr open GET api xhr onreadstatechange gt if xhr readState 4 2 d 2 test xhr s
  • 怎么使用 js 动态生成海报?

    方案一 DOM gt canvas gt image 将目标 DOM 节点绘制到 canvas 画布 然后利用 canvas 相关的 API 以图片形式导出 可简单标记为绘制阶段和导出阶段两个步骤 绘制阶段 选择希望绘制的 DOM 节点 根
  • svn 恢复删除的文件

    本文转载至 http stackoverflow com questions 497670 whats a simple way to undelete a file in subversion If you just did svn rm
  • Retrofit 2.5框架使用与源码分析

    Retrofit 框架使用 请求内容与返回值 使用PostMan进行请求测试 请求 https api github com search repositories q android 返回值 Header 外链图片转存失败 源站可能有防盗