【发布时间】:2018-08-30 01:15:13
【问题描述】:
通过关注this 的文章,我发现在 onCreate() 方法上调用 Retrofit enqueue() 可能会导致内存泄漏。
这是文章所说的,这样做:
在主线程中调用 Retrofit
public class MoviesActivity extends Activity {
private TextView mNoOfMoviesThisWeek;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_movies_activity);
mNoOfMoviesThisWeek = (TextView) findViewById(R.id.no_of_movies_text_view);
MoviesRepository repository = ((MoviesApp) getApplication()).getRepository();
repository.getMoviesThisWeek()
.enqueue(new Callback<List<Movie>>() {
@Override
public void onResponse(Call<List<Movie>> call,
Response<List<Movie>> response) {
int numberOfMovies = response.body().size();
mNoOfMoviesThisWeek.setText("No of movies this week: " + String.valueOf(numberOfMovies));
}
@Override
public void onFailure(Call<List<Movie>> call, Throwable t) {
// Oops.
}
});
}
}
现在,如果这个网络调用在一个非常慢的连接上运行,并且在调用结束之前,Activity 以某种方式旋转或销毁,那么整个 Activity 实例将被泄露。
我尝试在我的应用上做同样的事情。我在 onCreate() 方法中调用了一个大内容(240 个对象)ussign enqueue()。然后,在加载内容时,我多次旋转设备,LeakCanary 向我显示了 Activity 中的内存泄漏,如文章所述。
然后我尝试了两种方法来避免内存泄漏:
第一选择
使用静态内部类在后台线程上调用改造 execute() 方法。
在后台线程中调用 Retrofit
private static class RetrofitCall extends AsyncTask<Void, Void, List<Show>> {
private WeakReference<TextView> numberOfShows;
public RetrofitCall(TextView numberOfShows) {
this.numberOfShows = new WeakReference<>(numberOfShows);
}
@Override
protected List<Show> doInBackground(Void... voids) {
List<Show> showList = new ArrayList<>();
if (!isCancelled()) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(TvMazeService.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
TvMazeService service = retrofit.create(TvMazeService.class);
try {
Response<List<Show>> response = service.getShows().execute();
if (response.isSuccessful()) {
showList = response.body();
}
return showList;
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void onPostExecute(List<Show> shows) {
super.onPostExecute(shows);
TextView textView = numberOfShows.get();
if (textView != null) {
String number = String.valueOf(shows.size());
textView.setText(number);
}
}
}
然后我再次尝试使用 LeakCanary 获取内存泄漏,并且内存泄漏发生了。
第二个选项
使用ViewModel。
正如您在文档中看到的那样,在使用 ViewModel 时,我在 ViewModel 类中调用了异步改造,当屏幕旋转(活动被破坏)时,它不需要再次加载数据,因为它保持保存状态。
这种方法也没有造成内存泄漏,并且在谈论内存时是最好的。
问题
1) 那么,使用 ViewModel 调用 Retrofit 是最好的选择,真的可以避免内存泄漏吗?
2) 像 MoviesActivity 那样在 onCreate() 中使用 enqueue() 调用改造有什么问题吗?
3) 在这种方法中,哪一种方法最适合进行调用以验证用户身份?
【问题讨论】:
-
这是个好问题。你找到解决办法了吗?
-
我仍在寻找这个主题,但是我得到了很多新信息。我会回答的
标签: android memory-leaks retrofit retrofit2