Следуя этой статье , я обнаружил, что вызов метода Retrofit enqueue () для метода onCreate () может вызвать утечку памяти.
Вот что говорится в статье, делая это:
Вызов 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.
}
});
}
}
Теперь, если этот сетевой вызов выполняется на очень медленном соединении и до того, как вызов завершится, действие будет каким-либо образом повернуто или разрушено, тогда весь экземпляр действия будет просочиться.
Я пытался сделать то же самое в своем приложении. Я вызвал большой контент (240 объектов) usign enqueue () в методе onCreate (). Затем, во время загрузки контента, я несколько раз поворачивал устройство, и 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) Есть ли проблемы с вызовом модификации с помощью enqueue () в onCreate (), как это делает MoviesActivity?
3) При таком подходе, какой из них является лучшим, чтобы позвонить для аутентификации пользователя?