java从AsyncTask向MainActivity返回数据的最佳方式
我在应用程序中使用ASyncTask
,通过REST API从web服务(Bitly)获取一些数据(一个短URL)
当ASyncTask
完成时,我想将结果传递回我的MainActivity
通过使用AsyncTask
的onPostExecute
方法,可以将数据返回到MainActivity
我读了很多关于如何做到这一点的书,似乎有两种方法
最初,我使用的是一种“WeakReference”方法,在AsyncTask
类开始时,您可以创建一个对MainActivity
的弱引用,如下所示:
private class getShortURL extends AsyncTask<String, Void, String> {
private WeakReference<MainActivity> mainActivityWeakReference;
myASyncTask(MainActivity activity) {
mainActivityWeakReference = new WeakReference<>(activity);
}
{etc etc}
使用这种方法,你的AsyncTask
类位于MainActivity
类之外,因此很多东西需要通过弱引用来引用
这很好(除了我怀疑——可能是错误的——这种弱引用可能是偶尔出现NPE的原因),但后来我找到了另一种方法
第二种方法涉及将ASyncTask
类移动到MainActivity
类内部
通过这种方式,我可以直接访问MainActivity
类中可访问的所有内容,包括MainActivity
中定义的UI元素和方法。这还意味着我可以访问字符串等资源,并可以生成toasts
来通知用户正在发生什么
在这种情况下,可以删除上面的整个WeakReference
代码,并将AsyncTask
类设为私有
然后我也可以直接在onPostExecute
中执行类似的操作,或者将其保存在MainActivity
中的一个方法中,我可以直接从onPostExecute
调用该方法:
缩短进度条。setUndeterminate(假);
缩短进度条。设置可见性(视图不可见)
if (!shortURL.equals("")) {
// Set the link URL to the new short URL
short_link_url.setText(shortURL);
} else {
CommonFuncs.showMessage(getApplicationContext(), getString(R.string.unable_to_shorten_link));
short_link_url.setHint(R.string.unable_to_shorten_link);
}
(请注意,CommonFuncs.showMessage()
是我自己对toast函数的包装,使其更易于调用)
但是,Android Studio随后发出警告,“类应该是静态的,否则可能会发生泄漏”
如果我将该方法设置为静态,则会收到一条警告,即我想从MainActivity
调用的onPostExecute
方法不能被调用,因为它是非静态的
如果我把MainActivity
中的那个方法变成一个静态方法,那么它就不能访问字符串资源和任何其他非静态的方法了——我要去兔子洞
如果我将代码从MainActivity
中的方法移到onPostExecute
方法中,正如您所预料的那样,情况也是如此。
所以
- 将AsyncTask作为非静态方法真的是件坏事吗?(我的 应用程序似乎可以在AS中使用此警告,但我显然不行 想在我的应用程序中创建内存泄漏李>
- 实际上,{
}方法是更正确、更安全的方法吗李> - 如果我使用
WeakReference
方法,如何创建需要在UI线程和访问字符串上运行的toasts
之类的东西 来自MainActivity
的资源等李> - 如果我使用
我在某个地方读到了关于创建interface
的内容,但有点迷路了,再也找不到了。这难道不会像WeakReference
那样依赖MainActivity
吗?这是一件坏事吗
我真的在寻找关于如何从一个安全且不存在内存泄漏风险的AsyncTask
将一些数据返回到MainActivity
和UI线程的最佳实践指导
# 1 楼答案
是的,你的观点和背景会泄露出去
旋转足够多,你的应用程序就会崩溃
这是一只死猪上的唇膏,这种情况下的弱引用比一个解决方案更像是一个破解,绝对不是 EME>正确的解决方案。
你要寻找的是某个事件总线的一种形式,它比活动时间更长
您可以使用保留片段*或Android架构组件ViewModel
您可能需要引入观察者模式(但不一定是LiveData)
不要在^{中运行那种东西
最简单的方法是使用this library(或者自己写一些做同样事情的东西,由你决定),把
EventEmitter
放到ViewModel
中,然后在你的活动中订阅/取消订阅这个EventEmitter在你的活动/片段中