Android 调用改装2时避免内存泄漏

Android 调用改装2时避免内存泄漏,android,memory-leaks,retrofit,retrofit2,Android,Memory Leaks,Retrofit,Retrofit2,通过下面的文章,我发现在onCreate()方法上调用Reformation enqueue()可能会导致内存泄漏 这篇文章是这样说的: 在主线程中调用改装 public class MoviesActivity extends Activity { private TextView mNoOfMoviesThisWeek; @Override protected void onCreate(Bundle savedInstanceState) { s

通过下面的文章,我发现在onCreate()方法上调用Reformation enqueue()可能会导致内存泄漏

这篇文章是这样说的:

在主线程中调用改装

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.
                    }
                });
    }
}
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);
            }
        }
    }
公共类电影活动扩展活动{
私人文本视图mnoofmoviesthisbeek;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.layout\u活动);
mNoOfMoviesThisWeek=(TextView)findViewById(R.id.no_of_movies_text_view);
MoviesRepository repository=((MoviesApp)getApplication()).getRepository();
repository.getMoviesThisWeek()
.enqueue(新的回调函数(){
@凌驾
公共void onResponse(调用,
回应(回应){
int numberOfMovies=response.body().size();
mNoOfMoviesThisWeek.setText(“本周电影数量:”+String.valueOf(numberOfMovies));
}
@凌驾
失败时公共无效(调用调用,可丢弃的t){
//哎呀。
}
});
}
}
现在,如果此网络调用在非常慢的连接上运行,并且在调用结束之前,活动以某种方式被旋转或破坏,那么整个活动实例将泄漏

我试着在我的应用程序上做同样的事情。我在onCreate()方法中使用ign enqueue()调用了一个大内容(240个对象)。然后,在加载内容时,我将设备旋转了多次,并向我展示了文章中所说的活动中的内存泄漏

然后我尝试了两种方法来避免内存泄漏:

第一选项

使用静态内部类在后台线程上调用reformation execute()方法

在后台线程中调用改装

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.
                    }
                });
    }
}
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);
            }
        }
    }
私有静态类调用扩展了异步任务{
私人WeakReference numberOfShows;
公用电话(TextView numberOfShows){
this.numberOfShows=新的WeakReference(numberOfShows);
}
@凌驾
受保护列表背景(无效…无效){
List showList=new ArrayList();
如果(!isCancelled()){
改装改装=新改装.Builder()
.baseUrl(TvMazeService.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
TvMazeService服务=改装.create(TvMazeService.class);
试一试{
响应=service.getShows().execute();
if(response.issusccessful()){
showList=response.body();
}
退货清单;
}捕获(IOE异常){
e、 printStackTrace();
}
}
返回null;
}
@凌驾
受保护的void onPostExecute(列表显示){
super.onPostExecute(显示);
TextView TextView=numberOfShows.get();
if(textView!=null){
String number=String.valueOf(shows.size());
textView.setText(数字);
}
}
}
然后,我再次尝试使用LeakCanary获取内存泄漏,碰巧内存泄漏消失了

第二选项

使用

正如您在文档中所看到的,在ViewModel类中使用ViewModel时,我称之为“异步改造”,当屏幕旋转(活动被破坏)时,不需要再次加载数据,因为数据仍然保存

这种方法也不会导致内存泄漏,在讨论内存时是最好的方法

问题

1) 那么,使用ViewModel调用翻新是最好的选择,它真的可以避免内存泄漏吗

2) 像MoviesActivity那样,在onCreate()中使用enqueue()调用Reformation有什么问题吗

3) 在这种方法中,哪种方法最适合调用以验证用户身份?

1)以正确的方式使用ViewModel不会导致内存泄漏,是一个不错的选择。你可以看到,还有这堂课,讲的是。第二节课对这个话题做了很好的解释

2) 在onCreate()中调用Reformation enqueue()是一个问题,它会导致内存泄漏。问题在于,当您第一次启动称为改装的活动时,当您旋转设备时,所有活动都会被销毁并重新创建。如果在数据加载完成之前旋转设备,则在再次调用onCreate()时将第二次调用Reformation,如果继续执行10次,将调用Reformation 10次,然后停止旋转设备。调用的结果将开始出现,bzzz:(结果将显示10次,因为您调用了10次。这意味着存在巨大的内存泄漏。如果您实施此方法并使用,您将看到泄漏

3) 最好的方法是什么

  • 在onCreate()中使用enqueue()方法肯定不好
  • 静态内部类(使用AsyncTask)是好的,但它不能在配置更改后继续存在,因为您需要在onDestroy()中取消它。这就是为什么它不会导致内存泄漏,因为任务已在onDestroy()中取消
  • MVP是一种非常好的进行改装呼叫的方法。您可以从中了解更多信息,源代码如下
  • 阅读本文中MVP和MVVM之间的区别
  • 最后,谷歌建议开发者在这些场景中使用
你可以在另一个会议上关注我的讨论。在这里,我们讨论的是同一主题,但同时将用户登录到服务器。

<