提供反馈
提供反馈
假设你有一个需要上传图片的函数。当用户点击上传按钮时,会出现加载进度条或者 spinners
,这表明应用程序正在运行某些操作而不是停止工作。这对好的用户体验是至关重要的,没人喜欢无响应的应用程序。但是为用户提供反馈在代码中如何实现呢?
思考一下下面的任务,你要上传图片但是必须等待应用程序上传完成:
fun uploadImage(image: Image) {
showLoadingSpinner()
// Do some work
uploadService.upload(image)
// Work’s done, hide the spinner
hideLoadingSpinner()
}
从上面的代码中,可以了解到以下信息:
- 首先显示一个进度条。
- 接下来上传一张图片。
- 最后,当上传完成后,隐藏进度条。
不幸的是,上面的代码并非如此简单,因为进度条是有动画的,并且必须有代码实现这个动画。showLoadingSpinner
必须包含以下代码:
fun showLoadingSpinner() {
showSpinnerView()
while(running) {
rotateSpinnerImage()
delay()
}
}
showSpinnerView
用于显示真正的 UI 组件,下面的 while
循环用于处理动画。但是这个函数什么时候返回呢?
在 uploadImage
函数中,假设执行完 showLoadingSpinner
函数后进度条动画仍在运行,接下来就可以开始上传图片了。但是查看前面的代码,这是不可能的事情。
如果进度条动画在运行,就意味着 showLoadingSpinner
函数还没有返回。只要 showLoadingSpinner
返回,进度条动画就会停止并且将会开始上传图片。出现这种情况是因为阻塞调用 showLoadingSpinner
函数。
阻塞调用
阻塞调用是一个仅在完成时返回的函数。在上面的示例中,因为 showLoadingSpinner
函数使主线程保存忙碌,所有导致无法上传图片。但是当它返回时(把 running
置为 false),进度条动画就会停止。
那么如何解决在上传图片时进度条又有动画呢?
简而言之,你需要额外的线程来执行长时间运行的任务。
主线程也成为 UI 线程,因为它负责渲染屏幕上的所有内容,而这应该是它唯一的任务。这意味着它应该处理进度条的动画而不是上传图片,因为上传图片与 UI 无关。如果主线程不能做上传图片任务,那么谁可以执行上传图片任务呢?很简单,你需要一个新的线程来执行长时间运行的任务。
现在的计算机比 20 年、15 年甚至 10 年前要先进得多。那时,如果尝试同时执行多项操作,而计算机只能有一个执行线程,因此它们会死机。但是技术是进步的,现在的应用程序支持一种称为多线程的机制。每个线程都可以处理一个任务,共同完成所需的任务,这就是多线程的魅力。