Students Save 30%! Learn & create with unlimited courses & creative assets Students Save 30%! Save Now
Advertisement
  1. Code
  2. Android SDK
Code

使用Picasso编写图像库Android应用程序

by
Difficulty:IntermediateLength:LongLanguages:

Chinese (Simplified) (中文(简体)) translation by Zhang Xiang Liang (you can also view the original English article)

Final product image
What You'll Be Creating

Picasso是一个流行的开源Android库,用于加载本地和远程图像。了解如何轻松使用它来处理图片加载需求。

什么是Picasso?

Picasso  (名字灵感来自法国着名艺术家Pablo Picasso)是一款非常受欢迎的开源Android库,用于在Android应用中加载图像。根据官方文件,它指出:

..毕加索允许在应用程序中轻松加载图像 - 通常只需一行代码!

请注意,Picasso使用  OkHttp  (来自同一开发人员的网络库)来通过互联网加载图像。

2.为什么要使用Picasso?

现在你已经知道了毕加索的全部内容,你可能会问的下一个问题是为什么要使用它?

在Java或Kotlin中开发自己的媒体加载和显示功能可能是一件非常痛苦的事情:您必须关心缓存,解码,管理网络连接,线程,异常处理等等。毕加索是一个易于使用,计划周密,记录完备,经过充分测试的图书馆,可以为您节省大量宝贵的时间,并为您节省一些麻烦。

根据官方文档,以下是加载由毕加索为您处理的Android图像的许多常见陷阱:

  • 在一个适配器中处理  ImageView
  • 回收和下载取消复杂的图像转换与最小的内存使用
  • 自动内存和磁盘缓存

将图像添加到您的应用程序可以使您的Android应用程序活着。因此,在本教程中,我们将通过构建一个简单的图库应用来了解毕加索2。 它会通过互联网加载图像,并以缩略图形式显示在  RecyclerView中,当用户点击图像时,它将打开包含较大图像的细节活动。

本教程的示例项目(在Kotlin中)可以在我们的GitHub仓库中找到,以便您轻松进行跟踪。

好艺术家复制,伟大的艺术家窃取。- 巴勃罗毕加索

3.先决条件

为了能够学习本教程,您需要:

启动Android Studio并创建一个新的项目(您可以命名它  PicassoDemo)并使用一个名为空的  MainActivity。确保也检查  包括Kotlin支持  复选框。

Android Studios Add an Activity to Mobile dialog

4.  声明依赖关系

创建新项目后,在build.gradle中指定以下依赖  项。在撰写本文时,最新版本的毕加索是  2.71828。 

或者与Maven:

确保在添加毕加索和RecyclerViewv7工件后同步您的项目。

5.  添加Internet权限

由于毕加索将执行网络请求以通过互联网加载图像,因此我们需要INTERNET在我们的AndroidManifest.xml中包含权限。 

所以现在就去做吧!

请注意,只有在您要从互联网上载入图像时才需要。如果您仅在设备上本地加载图像,则不需要这样做。

6.  创建布局

我们将首先在activity_main.xml布局文件中创建RecyclerView。

创建自定义项目布局

接下来,让我们创建将用于RecyclerView每个项目(ImageView)  的XML布局(item_image.xml)。 

现在我们已经创建了我们简单的图库应用程序所需的布局,下一步是创建RecyclerView 用于填充数据的  适配器。然而,在我们这样做之前,让我们创建我们简单的数据模型。

7.  创建一个数据模型

我们将为我们定义一个简单的数据模型  RecyclerView。该模型实现了  Parcelable,  用于在Android中将数据从一个组件高效传输到另一个组件。在我们的案例中,数据将被传输  SunsetGalleryActivity到  SunsetPhotoActivity。  在我们的案例中,数据将被传输到SunsetPhotoActivity。 

请注意,这个模型SunsetPhoto只有一个被称为url (为了演示目的)的字段,但是如果你愿意,你可以有更多的字段。这个类实现Parcelable,这意味着我们必须重写一些方法。

我们可以利用Android Studio IDEA为我们生成这些方法,但是这样做的缺点是维护。怎么样?任何时候,如果我们不更新方法,我们可能会忘记显式更新constructor和writeToParcel方法,这会导致一些错误。

现在,为了避免更新或编写这些样板方法,Kotlin 1.1.14引入了@Parcelize注释。此注释将帮助我们生成writeToParcelwriteFromParceldescribeContents引擎盖下自动为我们的方法。

现在,我们的代码SunsetPhoto类只有两行!真棒!

请记住将以下代码添加到您的应用程序模块中  build.gradle:

此外,我包括(在Java或静态方法)同伴对象getSunsetPhotos()在SunsetPhoto模型类,将只会返回一个ArrayList中的SunsetPhoto调用时。

8.  创建适配器

我们将创建一个适配器来填充我们  RecyclerView的数据。我们还将实现一个点击侦听器来打开详细信息活动 - SunsetPhotoActivity将它SunsetPhoto作为一个意图额外的实例。细节活动将显示图像的特写。我们将在后面的章节中创建它 请注意,我们使用apply 扩展函数将对象作为额外的意图。作为提示,该apply函数将传递给它的对象作为参数(即接收方对象)返回。

请注意,我们使用apply 扩展函数将对象作为额外的意图。作为提示,该apply函数将传递给它的对象作为参数(即接收方对象)返回。

9.  从URL加载图像

我们需要Picasso在本节中完成它的工作 - 不是为了给我们绘制一件艺术品,而是从互联网上获取图像并显示它们。 当用户滚动应用程序时,我们会在我们的RecyclerView onBindViewHolder()方法中分别在各自的ImageViews中  显示这些图像。

一步一步,这就是要做的Picasso事情:

get()方法

这将返回Picasso使用以下默认配置初始化的全局实例(单例实例): 

  • LRU内存缓存为可用应用程序RAM的15%。
  • 2%存储空间的磁盘缓存高达50MB但不低于5MB。注意:这仅适用于API 14+。
  • 三个用于磁盘和网络访问的下载线程。

请注意,如果这些设置不符合您的应用程序的要求,您可以自由构建自己的Picasso实例,并通过使用完全控制这些配置Picasso.Builder。 

最后,您调用该build()方法以Picasso使用您自己的配置返回实例。 

建议你在你的系统中执行此操作,Application.onCreate然后Picasso.setSingletonInstance在该方法中将其设置为单例实例- 以确保该Picasso实例是全局实例。

load()方法

load(String path) 使用指定的路径启动图像请求。该路径可以是远程URL,文件资源,内容资源或Android资源。

  • placeholder(int placeholderResId):当图像加载并显示时使用的本地占位符资源ID或绘图。它在用户下载图像时显示占位符图像是一种很好的用户体验。 

请注意,Picasso首先会检查所请求的图像是否位于内存缓存中,如果是,则显示来自此处的图像(我们将在后面的章节中更多地讨论Picasso中的缓存)。

其他方法

  • error(int errorResId):如果请求的图片无法加载,可能会因为网站关闭而使用drawable。 
  • noFade():Picasso总是褪色的形象被展示进去ImageView。如果您不想要淡入淡出动画,只需调用该noFade()方法即可。 
  • into(ImageView imageView):将放置图像的目标图像视图。

图像大小调整和转换

如果您要求图像的服务器不能以所需的大小为您提供所需的图像,则可以使用该图像轻松调整图像大小resize(int targetWidth, int targetHeight)。 调用此方法会调整图像大小,然后将其显示在屏幕上ImageView。请注意,尺寸以像素(px)为单位,而不是dp。 

您可以使用该方法传递Android维度资源的宽度和高度  resizeDimen(int targetWidthResId, int targetHeightResId)。此方法将尺寸大小转换为原始像素,然后resize()在引擎盖下调用- 通过转换大小(以像素为单位)作为参数。

请注意,这些调整大小的方法不会考虑宽高比。换句话说,您的图像宽高比可能会失真。

幸运的是,Picasso给了我们一些有用的方法来解决这个问题: 

  • centerCrop():统一缩放图像(保持图像的高宽比),使图像填满指定区域,并尽可能多地显示图像。如果需要,图像将水平或垂直裁剪以适合。调用此方法在由指定的边界内裁剪图像resize()。 centerInside():缩放图像,使两个尺寸等于或小于要求的范围。这会将图像置于由指定的边界内resize()。 
  • onlyScaleDown():如果原始图像尺寸大于由指定的目标尺寸,则仅调整图像尺寸resize()。
  • fit():尝试调整图像的大小,使其完全符合目标ImageView的边界。
  • 图像旋转

图像旋转

Picasso有一个简单的API来旋转图像,然后显示该图像。 rotate(float degrees) 方法将图像旋转指定的度数。

在上面的例子中,这将使图像旋转90度。该  rotate(float degrees, float pivotX, float pivotY) 方法围绕枢轴点将图像旋转指定的角度。

在这里,我们将围绕枢轴点200旋转图像30度,100像素。 

转型

除了通过旋转图像来操作图像之外,毕加索还为我们提供了在显示图像之前对图像应用自定义转换的选项。  

您只需创建一个实现Picasso  Transformation界面的类。然后你必须重写两个方法:

  • Bitmap transform(Bitmap source):这将源位图转换为新的位图。 
  • String key():为转换返回一个唯一的键,用于缓存目的。

完成创建自定义转换后,只需transform(Transformation transformation)在Picasso实例上调用即可执行该转换。请注意,您也可以传递一个Transformationto  的列表transform()。 

在这里,我对毕加索转换开放源代码Android库中的图像应用了圆形裁剪转换。 这个库有许多可以应用于带有毕加索图像的转换 - 包括用于模糊或灰度缩放图像的转换。如果你想对你的图片应用一些很酷的转换,请检查一下。  

10.  初始化适配器

在这里,我们简单地创建了  RecyclerView 与  GridLayoutManager 作为布局管理器,初始化我们的适配器,并将其绑定到  RecyclerView。 

11.  创建细节活动

创建一个新的活动并命名它  SunsetPhotoActivity。我们可以SunsetPhoto 像onStart()以前一样获得  额外的功能并将图像加载到毕加索内  。

详细的布局

以下是显示详细活动的布局。它只显示一个  ImageView 将显示加载图像的全分辨率版本。 

12.  毕加索的缓存机制

如果仔细观察,您会注意到当您重新访问先前加载的图像时,加载速度比以前更快。是什么让它更快?这是毕加索的缓存机制,就是这样。

这是发生了什么。从互联网加载一次图像后,毕加索将它缓存在内存和磁盘上,从而节省了重复的网络请求并允许更快速地检索图像。当再次需要该图像时,毕加索将首先检查图像是否在内存中可用,如果它在那里,则会立即返回。如果该图像不在内存中,Picasso会检查下一个磁盘,如果它在那里,它会返回它。如果它不在那里,毕加索最终会对该图像进行网络请求并显示该图像。  当再次需要该图像时,毕加索将首先检查图像是否在内存中可用,如果它在那里,则会立即返回。如果该图像不在内存中,Picasso会检查下一个磁盘,如果它在那里,它会返回它。如果它不在那里,毕加索最终会对该图像进行网络请求并显示该图像。  总之,以下是图像请求(内存条):内存 - >磁盘 - >网络。 

总之,以下是图像请求(内存条):内存 - >磁盘 - >网络。 

但是,根据您的应用程序,您可能需要避免缓存 - 例如,如果显示的图像可能经常更改而不重新加载。

那么如何禁用缓存? 

您可以通过调用来避免内存缓存 memoryPolicy(MemoryPolicy.NO_CACHE)。这将在处理图像请求时简单地跳过内存缓存查找。 

请注意,还有另一个枚举:MemoryPolicy.NO_STORE。如果您非常确定您只会请求一次图像,这非常有用。应用此功能也不会将图像存储在内存缓存中,从而不会强制从内存缓存中删除其他位图。 应用此功能也不会将图像存储在内存缓存中,从而不会强制从内存缓存中删除其他位图。

但要非常清楚该映像仍然会缓存在磁盘上 - 以防止使用该映像,该映像将 networkPolicy(@NonNull NetworkPolicy policy, @NonNull NetworkPolicy... additional)采用一个或多个以下枚举值:

  • NetworkPolicy.NO_CACHE:跳过检查磁盘缓存并强制通过网络加载。
  • NetworkPolicy.NO_STORE:跳过将结果存储到磁盘缓存中。
  • NetworkPolicy.OFFLINE:仅通过磁盘缓存强制请求,跳过网络。

要完全避免内存和磁盘缓存,只需依次调用这两种方法:

13.  请求监听

在毕加索中,您可以实现侦听器或回调来监视您在加载图像时所做请求的状态。如果您Target在请求中实现接口,则只会调用其中一种方法。 

  • void onBitmapFailed(e: Exception?, errorDrawable: Drawable?):无法成功加载图像时触发。在这里,我们可以访问抛出的异常。 
  • void onBitmapLoaded(Bitmap bitmap, LoadedFrom from):在图像成功加载时触发。在这里,我们获取位图来显示用户。 
  • void onPrepareLoad(Drawable placeHolderDrawable):在提交请求之前调用。

在这里,如果您有一个进度对话框,您也可以显示并隐藏进度对话框。 

还有另一个可以实现的回调监听器,如果你想调用Callback。这个接口只有两种方法:  onSuccess()和  onError(Exception e)。前者在图像请求加载成功时调用,而后者在处理请求时出错时调用。  前者在图像请求加载成功时调用,而后者在处理请求时出错时调用。 

回到我们的图片库应用程序(里面SunsetPhotoActivity),让我们通过使用Callback将设置位图的对象修改显示,  ImageView 并通过使用Android提取图像的深色和鲜艳颜色来更改布局的背景颜色  调色板API。 

因此,在您的应用程序模块的build.gradle中包含调色板工件:

现在让我们Callback在毕加索请求中实现接口。

14.  测试应用程序

最后,你可以运行应用程序!点击缩略图即可获取图像的全尺寸版本。

Final app result

15.  优先请求

当你想在同一个屏幕上同时加载不同的图像时,你可以选择哪一个比另一个更重要。换句话说,您可以先加载重要的图像。 

您只需调用您毕加索的请求实例的priority(),并通过在任何枚举:Priority.LOW,Priority.NORMAL或  Priority.HIGH。 

16.  标记请求

通过标记您的毕加索请求,您可以恢复,暂停或取消与特定标签关联的请求。根据您的使用情况,您可以使用字符串或对象来标记请求,这些字符串或对象应将请求的范围定义为a Context,an Activity或a Fragment。您可以通过调用tag(@NonNull Object tag)一个来轻松标记毕加索请求。传递它Object作为标签的实例  。 以下是您可以对标记的毕加索请求执行的以下操作: 您可以通过调用tag(@NonNull Object tag)一个来轻松标记毕加索请求。传递它Object作为标签的实例  。 

以下是您可以对标记的毕加索请求执行的以下操作:

  • pauseTag(Object tag):暂停与给定标签关联的所有请求。 
  • resumeTag(Object tag):用给定的标签继续暂停的请求。
  • cancelTag(Object tag):用给定的标签取消任何现有的请求。

虽然标记您的请求可以让您对请求进行一些控制,但在使用标签时应该非常小心,因为存在内存泄漏的可能性。以下是官方文档所说的内容:

只要此标签暂停和/或有活动请求,Picasso将保留对标签的引用。注意潜在的泄漏。

从文件系统加载

在您的应用中本地加载图片很简单。

结论

不错的工作!在本教程中,您已经使用毕加索构建了一个完整的图像库应用程序,并且沿着这个方向学习了图书馆的工作方式以及如何将它集成到自己的项目中。

您还学习了如何显示本地和远程图像,标记请求,优先化请求以及如何应用图像转换(如调整大小)。不仅如此,您还看到了启用和禁用缓存,错误处理和自定义请求侦听器是多么容易。 

要了解更多关于毕加索的信息,你可以参考它的  官方文档。要了解有关Android编码的更多信息,请查看Envato Tuts +上的其他一些课程和教程。

Envato qr branded
关注我们的公众号
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.