(郭霖)Android图片加载框架最全解析(一),Glide的基本用法

article/2025/9/17 7:54:43

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/53759439

本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 郭霖 即可关注,每天都有文章更新。

现在Android上的图片加载框架非常成熟,从最早的老牌图片加载框架UniversalImageLoader,到后来Google推出的Volley,再到后来的新兴军Glide和Picasso,当然还有Facebook的Fresco。每一个都非常稳定,功能也都十分强大。但是它们的使用场景基本都是重合的,也就是说我们基本只需要选择其中一个来进行学习和使用就足够了,每一个框架都尝试去掌握的话则有些浪费时间。

在这几个框架当中,我对Volley和Glide研究得比较深入,对UniversalImageLoader、Picasso和Fresco都只是有一些基本的了解。从易用性上来讲,Glide和Picasso应该都是完胜其他框架的,这两个框架都实在是太简单好用了,大多数情况下加载图片都是一行代码就能解决的,而UniversalImageLoader和Fresco则在这方面略逊一些。

那么再拿Glide和Picasso对比呢,首先这两个框架的用法非常相似,但其实它们各有特色。Picasso比Glide更加简洁和轻量,Glide比Picasso功能更为丰富。之前已经有人对这两个框架进行过全方面的对比,大家如果想了解更多的话可以去参考一下 这篇文章 。

总之,没有最好的框架,只有最适合自己的框架。经过多方面对比之后,我还是决定选择了Glide来进行研究,并且这也是Google官方推荐的图片加载框架。

说实话,关于Glide的文章我已经筹备了好久,去年这个时候本来就打算要写了,但是一直都没有动笔。因为去年我的大部分时间都放在了写《第二行代码》上面,只能用碎片时间来写写博客,但是Glide的难度远超出了我用碎片时间所能掌握的难度。当然,这里我说的是对它的源码进行解析的难度,不是使用上的难度,Glide的用法是很简单的。所以,我觉得去年我写不好Glide这个题材的文章,也就一直拖到了今年。

而现在,我花费了大量的精力去研究Glide的源码和各种用法,相信现在已经可以将它非常好地掌握了,因此我准备将我掌握的这些知识整理成一个新的系列,帮忙大家更好地学习Glide。这个Glide系列大概会有8篇左右文章,预计花半年时间写完,将会包括Glide的基本用法、源码解析、高级用法、功能扩展等内容,可能会是目前互联网上最详尽的Glide教程。

那么本篇文章是这个系列的第一篇文章,我们先来了解一下Glide的基本用法吧。

开始

Glide是一款由Bump Technologies开发的图片加载框架,使得我们可以在Android平台上以极度简单的方式加载和展示图片。

目前,Glide最新的稳定版本是3.7.0,虽然3.8.0已经推出预览版了,但是暂时问题还比较多。因此,我们这个系列的博客都会使用Glide 3.7.0版本来进行讲解,这个版本的Glide相当成熟和稳定。

要想使用Glide,首先需要将这个库引入到我们的项目当中。新建一个GlideTest项目,然后在app/build.gradle文件当中添加如下依赖:

dependencies {compile 'com.github.bumptech.glide:glide:3.7.0'
}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

如果你还在使用Eclipse,可以点击 这里 下载Glide的jar包。

另外,Glide中需要用到网络功能,因此你还得在AndroidManifest.xml中声明一下网络权限才行:

<uses-permission android:name="android.permission.INTERNET" />
  • 1
  • 1

就是这么简单,然后我们就可以自由地使用Glide中的任意功能了。

加载图片

现在我们就来尝试一下如何使用Glide来加载图片吧。比如这是必应上一张首页美图的地址:

http://cn.bing.com/az/hprichbg/rb/Dongdaemun_ZH-CN10736487148_1920x1080.jpg
  • 1
  • 1

然后我们想要在程序当中去加载这张图片。

那么首先打开项目的布局文件,在布局当中加入一个Button和一个ImageView,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><Button
        android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Load Image"android:onClick="loadImage"/><ImageView
        android:id="@+id/image_view"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

为了让用户点击Button的时候能够将刚才的图片显示在ImageView上,我们需要修改MainActivity中的代码,如下所示:

public class MainActivity extends AppCompatActivity {ImageView imageView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);imageView = (ImageView) findViewById(R.id.image_view);}public void loadImage(View view) {String url = "http://cn.bing.com/az/hprichbg/rb/Dongdaemun_ZH-CN10736487148_1920x1080.jpg";Glide.with(this).load(url).into(imageView);}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

没错,就是这么简单。现在我们来运行一下程序,效果如下图所示:

可以看到,一张网络上的图片已经被成功下载,并且展示到ImageView上了。

而我们到底做了什么?实际上核心的代码就只有这一行而已:

Glide.with(this).load(url).into(imageView);
  • 1
  • 1

千万不要小看这一行代码,实际上仅仅就这一行代码,你已经可以做非常非常多的事情了,包括加载网络上的图片、加载手机本地的图片、加载应用资源中的图片等等。

下面我们就来详细解析一下这行代码。

首先,调用Glide.with()方法用于创建一个加载图片的实例。with()方法可以接收Context、Activity或者Fragment类型的参数。也就是说我们选择的范围非常广,不管是在Activity还是Fragment中调用with()方法,都可以直接传this。那如果调用的地方既不在Activity中也不在Fragment中呢?也没关系,我们可以获取当前应用程序的ApplicationContext,传入到with()方法当中。注意with()方法中传入的实例会决定Glide加载图片的生命周期,如果传入的是Activity或者Fragment的实例,那么当这个Activity或Fragment被销毁的时候,图片加载也会停止。如果传入的是ApplicationContext,那么只有当应用程序被杀掉的时候,图片加载才会停止。

接下来看一下load()方法,这个方法用于指定待加载的图片资源。Glide支持加载各种各样的图片资源,包括网络图片、本地图片、应用资源、二进制流、Uri对象等等。因此load()方法也有很多个方法重载,除了我们刚才使用的加载一个字符串网址之外,你还可以这样使用load()方法:

// 加载本地图片
File file = new File(getExternalCacheDir() + "/image.jpg");
Glide.with(this).load(file).into(imageView);// 加载应用资源
int resource = R.drawable.image;
Glide.with(this).load(resource).into(imageView);// 加载二进制流
byte[] image = getImageBytes();
Glide.with(this).load(image).into(imageView);// 加载Uri对象
Uri imageUri = getImageUri();
Glide.with(this).load(imageUri).into(imageView);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

最后看一下into()方法,这个方法就很简单了,我们希望让图片显示在哪个ImageView上,把这个ImageView的实例传进去就可以了。当然,into()方法不仅仅是只能接收ImageView类型的参数,还支持很多更丰富的用法,不过那个属于高级技巧,我们会在后面的文章当中学习。

那么回顾一下Glide最基本的使用方式,其实就是关键的三步走:先with(),再load(),最后into()。熟记这三步,你就已经入门Glide了。

占位图

现在我们来学一些Glide的扩展内容。其实刚才所学的三步走就是Glide最核心的东西,而我们后面所要学习的所有东西都是在这个三步走的基础上不断进行扩展而已。

观察刚才加载网络图片的效果,你会发现,点击了Load Image按钮之后,要稍微等一会图片才会显示出来。这其实很容易理解,因为从网络上下载图片本来就是需要时间的。那么我们有没有办法再优化一下用户体验呢?当然可以,Glide提供了各种各样非常丰富的API支持,其中就包括了占位图功能。

顾名思义,占位图就是指在图片的加载过程中,我们先显示一张临时的图片,等图片加载出来了再替换成要加载的图片。

下面我们就来学习一下Glide占位图功能的使用方法,首先我事先准备好了一张loading.jpg图片,用来作为占位图显示。然后修改Glide加载部分的代码,如下所示:

Glide.with(this).load(url).placeholder(R.drawable.loading).into(imageView);
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

没错,就是这么简单。我们只是在刚才的三步走之间插入了一个placeholder()方法,然后将占位图片的资源id传入到这个方法中即可。另外,这个占位图的用法其实也演示了Glide当中绝大多数API的用法,其实就是在load()和into()方法之间串接任意想添加的功能就可以了。

不过如果你现在重新运行一下代码并点击Load Image,很可能是根本看不到占位图效果的。因为Glide有非常强大的缓存机制,我们刚才加载那张必应美图的时候Glide自动就已经将它缓存下来了,下次加载的时候将会直接从缓存中读取,不会再去网络下载了,因而加载的速度非常快,所以占位图可能根本来不及显示。

因此这里我们还需要稍微做一点修改,来让占位图能有机会显示出来,修改代码如下所示:

Glide.with(this).load(url).placeholder(R.drawable.loading).diskCacheStrategy(DiskCacheStrategy.NONE).into(imageView);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

可以看到,这里串接了一个diskCacheStrategy()方法,并传入DiskCacheStrategy.NONE参数,这样就可以禁用掉Glide的缓存功能。

关于Glide缓存方面的内容我们将会在后面的文章进行详细的讲解,这里只是为了测试占位图功能而加的一个额外配置,暂时你只需要知道禁用缓存必须这么写就可以了。

现在重新运行一下代码,效果如下图所示:

可以看到,当点击Load Image按钮之后会立即显示一张占位图,然后等真正的图片加载完成之后会将占位图替换掉。

当然,这只是占位图的一种,除了这种加载占位图之外,还有一种异常占位图。异常占位图就是指,如果因为某些异常情况导致图片加载失败,比如说手机网络信号不好,这个时候就显示这张异常占位图。

异常占位图的用法相信你已经可以猜到了,首先准备一张error.jpg图片,然后修改Glide加载部分的代码,如下所示:

Glide.with(this).load(url).placeholder(R.drawable.loading).error(R.drawable.error).diskCacheStrategy(DiskCacheStrategy.NONE).into(imageView);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

很简单,这里又串接了一个error()方法就可以指定异常占位图了。

现在你可以将图片的url地址修改成一个不存在的图片地址,或者干脆直接将手机的网络给关了,然后重新运行程序,效果如下图所示:

这样我们就把Glide提供的占位图功能都掌握了。

指定图片格式

我们还需要再了解一下Glide另外一个强大的功能,那就是Glide是支持加载GIF图片的。这一点确实非常牛逼,因为相比之下Jake Warton曾经明确表示过,Picasso是不会支持加载GIF图片的。

而使用Glide加载GIF图并不需要编写什么额外的代码,Glide内部会自动判断图片格式。比如这是一张GIF图片的URL地址:

http://p1.pstatp.com/large/166200019850062839d3
  • 1
  • 1

我们只需要将刚才那段加载图片代码中的URL地址替换成上面的地址就可以了,现在重新运行一下代码,效果如下图所示:

也就是说,不管我们传入的是一张普通图片,还是一张GIF图片,Glide都会自动进行判断,并且可以正确地把它解析并展示出来。

但是如果我想指定图片的格式该怎么办呢?就比如说,我希望加载的这张图必须是一张静态图片,我不需要Glide自动帮我判断它到底是静图还是GIF图。

想实现这个功能仍然非常简单,我们只需要再串接一个新的方法就可以了,如下所示:

Glide.with(this).load(url).asBitmap().placeholder(R.drawable.loading).error(R.drawable.error).diskCacheStrategy(DiskCacheStrategy.NONE).into(imageView);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

可以看到,这里在load()方法的后面加入了一个asBitmap()方法,这个方法的意思就是说这里只允许加载静态图片,不需要Glide去帮我们自动进行图片格式的判断了。

现在重新运行一下程序,效果如下图所示:

由于调用了asBitmap()方法,现在GIF图就无法正常播放了,而是会在界面上显示第一帧的图片。

那么类似地,既然我们能强制指定加载静态图片,就也能强制指定加载动态图片。比如说我们想要实现必须加载动态图片的功能,就可以这样写:

Glide.with(this).load(url).asGif().placeholder(R.drawable.loading).error(R.drawable.error).diskCacheStrategy(DiskCacheStrategy.NONE).into(imageView);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这里调用了asGif()方法替代了asBitmap()方法,很好理解,相信不用我多做什么解释了。

那么既然指定了只允许加载动态图片,如果我们传入了一张静态图片的URL地址又会怎么样呢?试一下就知道了,将图片的URL地址改成刚才的必应美图,然后重新运行代码,效果如下图所示。

没错,如果指定了只能加载动态图片,而传入的图片却是一张静图的话,那么结果自然就只有加载失败喽。

指定图片大小

实际上,使用Glide在绝大多数情况下我们都是不需要指定图片大小的。

在学习本节内容之前,你可能还需要先了解一个概念,就是我们平时在加载图片的时候很容易会造成内存浪费。什么叫内存浪费呢?比如说一张图片的尺寸是1000*1000像素,但是我们界面上的ImageView可能只有200*200像素,这个时候如果你不对图片进行任何压缩就直接读取到内存中,这就属于内存浪费了,因为程序中根本就用不到这么高像素的图片。

关于图片压缩这方面,我之前也翻译过Android官方的一篇文章,感兴趣的朋友可以去阅读一下 Android高效加载大图、多图解决方案,有效避免程序OOM 。

而使用Glide,我们就完全不用担心图片内存浪费,甚至是内存溢出的问题。因为Glide从来都不会直接将图片的完整尺寸全部加载到内存中,而是用多少加载多少。Glide会自动判断ImageView的大小,然后只将这么大的图片像素加载到内存当中,帮助我们节省内存开支。

当然,Glide也并没有使用什么神奇的魔法,它内部的实现原理其实就是上面那篇文章当中介绍的技术,因此掌握了最基本的实现原理,你也可以自己实现一套这样的图片压缩机制。

也正是因为Glide是如此的智能,所以刚才在开始的时候我就说了,在绝大多数情况下我们都是不需要指定图片大小的,因为Glide会自动根据ImageView的大小来决定图片的大小。

不过,如果你真的有这样的需求,必须给图片指定一个固定的大小,Glide仍然是支持这个功能的。修改Glide加载部分的代码,如下所示:

Glide.with(this).load(url).placeholder(R.drawable.loading).error(R.drawable.error).diskCacheStrategy(DiskCacheStrategy.NONE).override(100, 100).into(imageView);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

仍然非常简单,这里使用override()方法指定了一个图片的尺寸,也就是说,Glide现在只会将图片加载成100*100像素的尺寸,而不会管你的ImageView的大小是多少了。

好了,今天是我们这个Glide系列的第一篇文章,写了这么多内容已经算是挺不错的了。现在你已经了解了Glide的基本用法,当然也是一些最常用的用法。下一篇文章当中,我们会尝试去分析Glide的源码,研究一下在这些基本用法的背后,Glide到底执行了什么神奇的操作,能够使得我们加载图片变得这么简单?敬请期待。

关注我的技术公众号,每天都有优质技术文章推送。关注我的娱乐公众号,工作、学习累了的时候放松一下自己。

微信扫一扫下方二维码即可关注:

        


http://chatgpt.dhexx.cn/article/fAtWBIyY.shtml

相关文章

图灵专访:郭霖的成长之路

各位小伙伴们大家早上好&#xff0c;最近这段时间我真的是快要忙疯了&#xff0c;好多件事情同时在做&#xff0c;实在抽不出时间写原创文章。 正巧想到前段时间和图灵做了一次专访&#xff0c;记录了一些我的成长经历。这篇专访姑且也可以算是一篇原创吧&#xff0c;因为里面的…

第一行代码-第二版(郭霖著)笔记十一(Material Design)

目录 一、什么是Material Design 二、Toolbar 三、滑动菜单 1.DrawerLayout 2.NavigationView 四、悬浮按钮和可交互提示 1.FloatingActionButton&#xff1a;悬浮按钮 2.Snackbar&#xff1a;提示工具 3.CoordinatorLayout&#xff1a;加强版FrameLayout 五、卡片式…

第一行代码-第二版(郭霖著)笔记二(Activity)

目录 一、Activity的用法 1.Activity 2.Toast 3.菜单 4.销毁一个活动 二、Intent 1.使用显示Intent 2.使用隐式Intent 3.更多隐式Intent的用法 4.向下一个活动传递数据 5.返回数据给上一个活动 三、活动的生命周期 1.返回栈 2.活动的四种状态 3.活动的生存期 4…

android动态权限依赖库,动态申请app权限:郭霖大神的PermissionX库带你告别原生

引言 为什么那么多人想要自定义Android的权限申请PermissonX?因为PermissionX默认的权限提醒弹出实在是太丑了!而且,需要在你需要提醒用户弹出Dialog时,显得捉襟见肘,你可能就在想有没有一款能封装进去Dialog提醒用户,具有超棒的用户体验,还能看起来美观大气的Permissio…

跟随郭霖学Volley

volley 下载导入volleyjar 学习地址: https://blog.csdn.net/guolin_blog/article/details/17482095 2013在Google I/O大会提出 github地址: https://github.com/google/volley 下载volley导入到as 具体的操作是: project模式下 具体看图: 之后的操作是打开lib 选择jar 右…

android 6.0权限 郭霖,Permission——郭霖认为最优的运行时权限方案

Android6.0发布这么久&#xff0c;对运行时权限也看了很多资料&#xff0c;对比过几个流行的库。但是个人还是喜欢在项目里用自己动手封装的东西&#xff0c;哪怕照抄也好。。。不知道是什么原因。 前天无意听郭神的直播。讲解的是运行时权限的封装&#xff0c;收益颇多。依样画…

郭霖LitePal

由于项目需要开始学习sqlite 一开始先学习使用的是 android ormlite 操作 从最基本的建表增删改查一路走来 磕磕碰碰很多 都是在内存中操作sqlite 只能通过sqlitestudio工具进行查看 不能导出 并且应用卸载数据表就丢失 最终考虑在sd卡中操作sqlite 但是ormlite 并没有这方面…

android郭霖博客,Runtime Permissions(郭霖CSDN公开课)

运行时权限 Api23开始&#xff0c;Android权限机制更改&#xff0c;有一部分权限不再是简单的在AndroidManifest.xml中声明即可。而是需要在运行时让用户去选择是否允许该项权限的操作。 那么哪些权限需要在运行时申请呢&#xff1f;危险权限需要这么做&#xff0c;而普通权限仍…

看一看Facebook工程师是怎么评价《第一行代码》的

本文同步发表于我的微信公众号&#xff0c;扫一扫文章底部的二维码或在微信搜索 郭霖 即可关注&#xff0c;每个工作日都有文章更新。 大家好&#xff0c;我是一名Facebook的工程师&#xff0c;同时也是《第一行代码——Android》的忠实读者。 虽然我最近几年是在国外读书和工…

郭霖:手把手教你实现 App 360 度旋转看车效果

这是郭神号前阵子的推送&#xff0c;应该有不少人还没有看过&#xff0c;现在分享给大家&#xff0c;希望对大家的Android工作和学习有所帮助。 / 作者简介 / 本篇文章来自Youth Lee的投稿&#xff0c;分享了他自己结合Glide写的一个控件&#xff0c;希望对大家有所帮助&#…

第一行代码-第二版(郭霖著)笔记(初识Android)

系列文章目录 第一章 第一行代码-第二版&#xff08;郭霖著&#xff09;笔记&#xff08;初识Android&#xff09; 目录 一、Android简介 1.android系统架构 2.Android应用开发特色 二、工具准备 Tips:新建项目的时候是否勾选use legacy android.support libraries 三、…

专访郭霖:成长无止境

留意文末赠书活动 嘉宾 | 郭霖 文 | 张霞 郭霖&#xff0c;Android开发工程师&#xff0c;Android GDE&#xff08;Google认证开发者专家&#xff09;。从事Android开发工作9年&#xff0c;有着丰富的项目实战经验&#xff0c;负责及参与开发过多款移动应用与游戏&#xff0c;开…

解决http响应状态为canceled

最近写登录的页面&#xff0c;发现通过ajax请求后台的时候&#xff0c;监控台返回该请求的状态是canceled。 原因 仅仅是由于之前为了在输入账号时让浏览器进行自动补全&#xff0c;而将原先的div更换为了form,而不巧的是之前的登录事件源使用的是button。 而至于为什么stat…

ajax请求导致status为canceled的原因

在使用layui的form表单提交以后&#xff0c;请求状态总是canceled。后来在form表单的后面添加了一行代码&#xff1a; return false; 就可以了。 文档&#xff1a;https://www.layui.com/doc/modules/form.html#onsubmit 错误&#xff1a; 解决方法&#xff1a; 总结一下&…

ajax请求文件状态为 canceled 的解决办法

ajax请求文件状态为 canceled 的解决办法 场景还原原因分析解决 场景还原 最近做一个表单提交的需求时&#xff0c;遇到了这种情况&#xff0c;输完账号密码后回车提交&#xff0c;报错&#xff0c;f12打开看到是请求的status为canceled了&#xff0c;震惊一秒钟。。。如下图&…

chrome同步或登录报错:Request Canceled

原因 因为某个接口连接失败造成&#xff0c;可以摁快捷键F12或者点击开发者工具。 然后选择network&#xff0c;这里面是该页面所有的收发请求 开始登录&#xff0c;登录的时候要注意network中pending或者报错的接口&#xff0c;然后把域名记录下来 解决方式 安装chrome插…

http发送请求,status显示canceled的原因

原因&#xff1a;onSubmit和submit属性比较陈旧&#xff0c;在提交了数据以后会自动刷新页面&#xff0c;导致信息丢失以及请求中止 解决&#xff1a;在 handler里面写入e.preventDefault();阻止onsubmit执行默认的刷新页面行为。

使用 npm create vue@3 报错 npm ERR! canceled

问题 之前运行都可以成功创建&#xff0c;但今天运行 npm create vue3 的时候报错了&#xff0c;错误信息如下&#xff1a; 解决方法 在网上找了一堆方法都无效。 npm 版本问题&#xff0c;升级到最新版本 npm i -g npm&#xff0c;然后重试 npm create vue3 【x】npm cac…

Go:read一个已经被canceled的http.Request的应答

Go&#xff1a;read一个已经被canceled的http.Request的应答 1.复现 最近发现项目在处理chunk类型的http应答时&#xff0c;出现读数据异常报错&#xff0c;代码示例如下&#xff1a; server package mainimport ("bytes""net/http" )func main() {http…

Idea通过git拉取代码的时候出现Update canceled问题

当在IDEA中通过Git更新代码时&#xff0c;拉取失败&#xff0c;报如下错误 12:31 Update failedInvocation failed Server returned invalid Response.java.lang.RuntimeException: Invocation failed Server returned invalid Response.at git4idea.GitAppUtil.sendXmlRequest…