九、连接外部世界——网络
我们生活在数字通信时代。手持设备在交流中发挥着巨大的作用,并影响着人们的互动方式。在前一章中,我们讨论了安卓的一个强大功能——识别用户的位置并根据位置定制服务。在这一章中,我们将重点介绍安卓设备最有用和最强大的功能之一——联网和与外部世界的连接。
虽然我们将简要介绍网络连接的重要概念和对网络的安卓框架支持,但我们将特别关注各种内置第三方库的配置和使用。我们还将学习如何从网址加载图像,并在我们创建的示例应用中显示它。
我们将涵盖以下内容:
- 网络连接
- Android 框架对网络的支持
- 内置库的使用
- 第三方图书馆的使用
网络连接
了解和识别用户所连接的网络的状态和类型对于为用户提供丰富的体验至关重要。安卓框架为我们提供了几个类,我们可以用它们来查找网络的细节:
ConnectivityManager
NetworkInfo
ConnectivityManager
提供网络连接状态及其变化的信息,而NetworkInfo
提供网络类型的信息——移动或无线网络。
以下代码片段有助于确定网络是否确实可用,以及设备是否连接到网络:
fun isOnline(): Boolean {
val connMgr = getSystemService(Context.CONNECTIVITY_SERVICE) as
ConnectivityManager
val networkInfo = connMgr.activeNetworkInfo
return networkInfo != null && networkInfo.isConnected
}
isOnline()
方法根据ConnectivityManager
返回的结果返回Boolean
—真或假。connMgr
实例与NetworkInfo
一起用于查找网络信息。
清单权限
访问网络和发送/接收数据需要访问互联网和网络状态的许可。必须在清单文件中定义以下权限,应用才能利用设备的网络:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
internet 权限允许应用通过启用网络套接字进行通信,而访问网络状态权限则允许它查找有关可用网络的信息。
安卓框架为应用提供了管理网络数据的默认意图MANAGE_NETWORK_USAGE
。处理意图的活动可以针对应用来实施:
<intent-filter>
<action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
截击库
通过 HTTP 协议与网络服务器通信并以字符串、JSON 和图像的形式交换信息的能力使应用更具交互性,并为用户提供丰富的体验。安卓有一个名为Volley
的内置 HTTP 库,可以开箱即用地进行这种信息交换。
除了使信息交换更容易之外,Volley
还为用户提供了更容易的方法来处理请求的整个生命周期,即计划、取消、优先化等等。
Volley
is quite good for lightweight network operations and makes information exchange easier. For huge downloads and streaming operations, developers should use Download Manager.
同步适配器
保持应用中的数据与 web 服务器同步,使开发人员能够为用户提供丰富的体验。安卓框架提供同步适配器,使数据同步能够以定义的周期间隔发生。
与Volley
类似,同步适配器具备处理数据传输生命周期的所有设施,并提供无缝的数据交换手段。
Sync adapter implementation typically contains a stub authenticator, a stub content provider, and a sync adapter.
第三方图书馆
除了安卓框架的内置支持,我们还有相当多的第三方库可以用来处理网络操作。其中,Square 的Picasso
和 bumptech 的Glide
是广泛使用的图像下载和缓存库。
在本节中,我们将重点关注这两个库的实现——Picasso
和Glide
——以从特定的 URL 加载图像并在我们的示例应用中显示它。
Networking calls should never be done on the main thread. Doing so will result in the app becoming less responsive and create Application Not Responding conditions. Instead, we should create separate worker threads which handle such network calls and provide information as and when the request is attended to.
毕加索
在这个示例项目中,让我们了解如何使用 Square 中的Picasso
库,并从指定的 URL 加载图像。
让我们创建一个新的安卓项目,并将其称为 ImageLoader。我们需要确保 Kotlin 的支持被检查。
对于图像加载器示例,我们可以通过选择空活动来继续:
让我们将活动命名为MainActivity
,默认情况下会出现该活动,并且将 XML 命名为activity_main
:
用户界面——可扩展标记语言
生成的默认 XML 代码将包含一个TextView
。我们需要稍微调整一下 XML 代码,用一个“T2”代替TextView
。该ImageView
将提供占位符,用于显示使用Picasso
从网址获取的图像。
下面的 XML 代码显示默认的 XML 包含TextView
;我们将用ImageView
取代TextView
:
*<?*xml version="1.0" encoding="utf-8"*?>
* <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.natarajan.imageloader.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
带有ImageView
的修改后的 XML 看起来像下面代码块中显示的那个。我们可以通过从小部件中拖动ImageView
或者通过在 XML 布局中键入代码来轻松添加它。在ImageView
中,我们将其标记为显示启动器图标作为占位符:
*<?*xml version="1.0" encoding="utf-8"*?>
* <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.natarajan.imageloader.MainActivity">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@mipmap/ic_launcher"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:layout_editor_absoluteX="139dp"
tools:layout_editor_absoluteY="219dp" />
</android.support.constraint.ConstraintLayout>
ImageViewer
在占位符中显示启动器图标,标记为从网址加载时显示图像。只要我们在 XML 中进行更改,就会显示启动器图标:
build.gradle
我们需要在build.gradle
依赖项中添加实现com.square.picasso.picasso:2.71828
。2.71828 版本是撰写本文时的最新版本。为了确保我们使用最新版本,谨慎的做法是检查http://square.github.io/picasso/并在 Gradle 依赖项中使用最新版本。
我们需要在build.gradle
文件的依赖项部分添加以下行,以使Picasso
可用于我们的应用:
实施com.squareup.picasso:picasso:2.71828
修改后的build.gradle
文件应该如下图所示:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
implementation 'com.squareup.picasso:picasso:2.71828'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' }
Kotlin 码
生成的默认 Kotlin 代码将有名为MainActivity
的类文件。该类文件扩展了AppCompatActivity
,提供了支持库动作栏功能。
代码在onCreate
方法中加载activity_main
中定义的 XML,并在加载时显示它。setContentView
读取activity_main
中定义的 XML 内容,并在加载时显示ImageView
:
package com.natarajan.imageloader
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
我们已经通过将默认的TextView
替换为ImageView
对 XML 进行了更改。我们需要在我们的 Kotlin 代码中反映这些变化,并通过使用Picasso
实现图像的加载。
我们需要为我们的程序添加ImageView
和Picasso
导入来使用这些组件:
import android.widget.ImageView
import com.squareup.picasso.Picasso
由于我们已经导入了Picasso
并确保添加了依赖项,我们应该能够通过一行代码Picasso.get().load("URL").into(ImageView)
加载日期:
Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(imageView);
毕加索图像加载的最终修改 Kotlin 类应如下所示:
package com.natarajan.imageloader
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.widget.ImageView
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.*activity_main*)
Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(imageView);
}
}
清单权限
我们需要确保我们的应用已经添加了访问互联网的权限。这是必需的,因为我们将从指定的网址下载图像,并将其显示在我们的ImageViewer
中。
我们已经详细介绍了所需的清单权限。让我们继续添加此权限:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
修改后的 XML 应该如下所示:
*<?*xml version="1.0" encoding="utf-8"*?>
* <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.natarajan.imageloader">
<uses-permission android:name="android.permission.INTERNET">
</uses-permission>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
现在我们都已经完成了对 XML、Kotlin 代码、build.gradle
和AndroidManifest
文件的更改,是时候启动我们的应用并通过Picasso
了解图像的无缝加载过程了。
运行应用后,我们应该能够看到我们的设备加载页面,显示应用名称 ImageLoader,并显示以下网址中显示的图像:
滑音
Glide
来自 bumptech 的是另一个非常受欢迎的图像加载库。我们将考虑使用Glide
并从特定的网址加载图像。
让我们继续在我们的build.gradle
和其他相关文件中进行Glide
所需的更改。
build.gradle
我们需要添加插件kotlin-kapt
并在我们应用的build.gradle
文件中添加依赖项。一旦我们同步所做的更改,我们应该能够在代码中使用Glide
并加载图像。
Glide
库使用标注处理。注释处理有助于生成样板代码,并使代码更容易理解。为了观察运行时工作的实际代码,开发人员可以检查生成的代码并理解库生成的样板代码:
apply plugin: 'kotlin-kapt' implementation 'com.github.bumptech.glide:glide:4.7.1' kapt "com.github.bumptech.glide:compiler:4.7.1"
The Glide
library talks about adding the annotation processor along with Glide
in the dependencies. This is applicable for Java. For Kotlin, we need to add the kapt
Glide
compiler as shown in the code block.
修改后的build.gradle
依赖关系应该如下所示:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-
jre7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-
layout:1.1.0'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'com.github.bumptech.glide:glide:4.7.1'
kapt "com.github.bumptech.glide:compiler:4.7.1"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation
'com.android.support.test.espresso:espresso-core:3.0.1' }
在项目级build.gradle
文件中,我们需要在repositories
部分添加mavenCentral()
,如图所示:
allprojects {
repositories {
google()
mavenCentral()
jcenter()
}
我们已经完成了对build.gradle
文件的更改;我们应该对proguard-rules.pro
文件做如下补充。proguard-rules.pro
文件使开发人员能够通过移除对应用中未使用和不想要的代码的引用来缩小 APK 大小。
为了保证Glide
模块是而不是不受 proguard 萎缩的影响,我们需要明确提到 app 要求我们保留对Glide
的引用。*-*keep
命令确保在构建中保留对Glide
和相应模块的引用:
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
# for DexGuard only -keepresourcexmlelements manifest/application/meta-data@value=GlideModule
Kotlin 码
我们定义了一个单独的类ImageLoaderGlideModule
,它扩展了AppGlideModule()
。类上的注释@GlideModule
使应用能够访问GlideApp
实例。GlideApp
实例可用于我们应用中的各种活动:
package com.natarajan.imageloader
*/**
** Created by admin on 4/14/2018. **/* import com.bumptech.glide.annotation.GlideModule
import com.bumptech.glide.module.AppGlideModule
@GlideModule
class ImageLoaderGlideModule : AppGlideModule()
我们需要在MainActivity
Kotlin 类中进行以下更改,以使图像由Glide
加载,并在应用启动时显示。
与Picasso
类似,Glide
也有一个简单的语法用于从指定的网址加载图像:
GlideApp.with(this).load("URL").into(imageView);
修改后的MainActivity
Kotlin 类应该如下图所示:
package com.natarajan.imageloader
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if(imageView != null){
GlideApp.with(this).load("http://goo.gl/gEgYUd").into(imageView);
}
}
}
我们已经完成了Glide
— build.gradle
、Proguard.rules
和 Kotlin 类文件所需的所有更改。我们应该看到应用从指定的网址加载图像并显示在ImageView
中,如图所示:
摘要
联网和连接外部世界是安卓设备非常强大的功能。我们介绍了网络基础知识,检查网络状态,可用网络类型,以及安卓框架提供的执行网络操作的内置功能。
我们还详细讨论了第三方库Picasso
和Glide
,图像加载库,并在我们的应用中介绍了这些库的实现。
在下一章中,我们将致力于开发一个简单的待办事项应用,并讨论各种概念,如 listview、dialog 等,并学习如何在应用中使用它们。
版权属于:月萌API www.moonapi.com,转载请注明出处