Форум программистов, компьютерный форум, киберфорум
Наши страницы
Программирование Android
Войти
Регистрация
Восстановить пароль
 
Araikovich
10 / 9 / 1
Регистрация: 09.08.2017
Сообщений: 62
1

Тема утечек памяти

18.02.2018, 01:51. Просмотров 454. Ответов 3

Всем привет. Прошу проконсультировать по поводу утечек памяти, а именно, когда утекает Активити. У меня есть Активность, презентер, и модель, которая работает с БД. Как известно, для работы с DBHelper - нужен Context. Я создаю в Активити объект модели, которой и передается Context. И вот мой вопрос, при уничтожении этой самой активити не утекает ли память, ведь ее контекст у модели. Ниже я приведу код, чтоб стало понятнее

Activity:

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
public class HairstyleCategoryActivity extends MvpAppCompatActivity implements HairstyleCategoryActivityView {
 
    @InjectPresenter
    HairstyleCategoryActivityPresenter presenter;
 
    Toolbar toolbar;
    RecyclerView recyclerView;
    ProgressBar progressBar;
    HairstyleCategoryRecyclerAdapter adapter;
    CircleImageView refresh;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_hairstyle_category);
        initView();
    }
 
    private void initView(){
        toolbar = (Toolbar)findViewById(R.id.hairstyle_categories_toolbar);
        recyclerView = (RecyclerView)findViewById(R.id.hairstyles_category_recycler_view);
        progressBar = (ProgressBar)findViewById(R.id.hairstyle_categories_progressbar);
        refresh = (CircleImageView)findViewById(R.id.hairstyle_categories_refresh);
 
        //set up toolbar;
        final Intent intent = getIntent();
        presenter.changetitle(intent.getStringExtra("title"));
        toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_back));
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onBackPressed();
            }
        });
 
        refresh.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.setCards(intent.getIntExtra("genderId", 0));
            }
        });
 
        //set up recycler view
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        if(adapter == null){
            adapter = new HairstyleCategoryRecyclerAdapter(this);
        }else {
            adapter.setContext(this);
        }
        recyclerView.setAdapter(adapter);
 
        adapter.setOnClickListener(new CategoryOnClickListener() {
            @Override
            public void onClick(int cardId, String title) {
                presenter.next(cardId, title);
            }
        });
 
        //getting model
        //
       //Вот в этом месте я и переживаю за утечку...
       //
 
        ModelComponent component = DaggerModelComponent.builder().contextModule(new ContextModule(this)).build();
        HairstyleCategoryModel model = component.getHairstyleCategoryModel();
        presenter.setModel(model);
        //load data
        if (!adapter.isLoaded())
            presenter.setCards(intent.getIntExtra("genderId", 0));
    }
 
    @Override
    public void setProgressBar(int visibility) {
        progressBar.setVisibility(visibility);
    }
 
    @Override
    public void setAdapter(ArrayList<HairstyleCategoryCard> cards) {
        adapter.setCards(cards);
    }
 
    @Override
    public void setTitle(String title) {
        toolbar.setTitle(title);
    }
 
    @Override
    public void showToast(String toast) {
        Toast.makeText(this, toast, Toast.LENGTH_SHORT).show();
    }
 
    @Override
    public void showRefresh(int visibility) {
        refresh.setVisibility(visibility);
    }
 
    @Override
    public void nextActivity(int hairstyleId, String hairstyleTitle) {
        Intent intent = new Intent(HairstyleCategoryActivity.this, HairstyleDetailActivity.class);
        intent.putExtra("hairstyleId", hairstyleId);
        intent.putExtra("hairstyleTitle", hairstyleTitle);
        startActivity(intent);
    }
 
}
Presenter:

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
@InjectViewState
public class HairstyleCategoryActivityPresenter extends MvpPresenter<HairstyleCategoryActivityView> {
 
    private HairstyleCategoryModel model;
 
    public void setModel(HairstyleCategoryModel model){
        if(this.model == null)
        this.model = model;
    }
 
    public void setCards(final int genderId){
        if(model.isIsdLoading())
            return;
        getViewState().showRefresh(View.GONE);
        model.loadCategoriesFromServer(genderId, new Callback<ArrayList<HairstyleCategoryCard>>() {
            @Override
            public void onResponse(Call<ArrayList<HairstyleCategoryCard>> call, Response<ArrayList<HairstyleCategoryCard>> response) {
                getViewState().setAdapter(response.body());
                getViewState().setProgressBar(View.GONE);
                model.saveCardToDb(response.body());
            }
 
            @Override
            public void onFailure(Call<ArrayList<HairstyleCategoryCard>> call, Throwable t) {
                model.getCardsFromDb(genderId, new LoadCallBack<ArrayList<HairstyleCategoryCard>>() {
                    @Override
                    public void onLoadSuccess(ArrayList<HairstyleCategoryCard> result) {
                        getViewState().setAdapter(result);
                        getViewState().setProgressBar(View.GONE);
                    }
 
                    @Override
                    public void onFail(String message) {
                        getViewState().setProgressBar(View.GONE);
                        getViewState().showRefresh(View.VISIBLE);
                        getViewState().showToast("Пробдемы с сетью, попробуйте еще раз");
                    }
                });
            }
        });
    }
 
    public void changetitle(String title){
        getViewState().setTitle(title);
    }
 
    public void next(int hairstyleId, String hairstyleTitle){
        getViewState().nextActivity(hairstyleId, hairstyleTitle);
    }
 
}
И Model, которая как раз зависима от Context:

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
public class HairstyleCategoryModel {
 
    private ServerApi api;
    private DBHelper db;
    private boolean isdLoading = false;
 
    public HairstyleCategoryModel(ServerApi api, DBHelper db){
        this.api = api;
        this.db = db;
    }
 
    public void loadCategoriesFromServer(int genderId, Callback callback){
        Call<ArrayList<HairstyleCategoryCard>> call = api.getHairstyleCategories(genderId);
        call.enqueue(callback);
    }
 
    public void saveCardToDb(ArrayList<HairstyleCategoryCard> cards){
        SaveCategoryCardsTask task = new SaveCategoryCardsTask();
        task.execute(cards);
    }
 
    public void getCardsFromDb(int genderId, LoadCallBack callBack){
        LoadCategoryCardsTask task = new LoadCategoryCardsTask(genderId, callBack);
        task.execute();
    }
 
    public boolean isIsdLoading(){
        return isdLoading;
    }
 
    class SaveCategoryCardsTask extends AsyncTask<ArrayList<HairstyleCategoryCard>, Void, Void> {
 
        @Override
        protected Void doInBackground(ArrayList<HairstyleCategoryCard>... params) {
            ContentValues contentValues = new ContentValues();
            SQLiteDatabase database = db.getWritableDatabase();
            database.delete("category", null, null);
            for(int i = 0; i<params[0].size(); i++){
                contentValues.put("id", params[0].get(i).getId());
                contentValues.put("genderId", params[0].get(i).getSexId());
                contentValues.put("title", params[0].get(i).getTitle());
                contentValues.put("imageUrl", params[0].get(i).getImageUrl());
                database.insert("category", null, contentValues);
                contentValues.clear();
            }
            return null;
        }
 
    }
 
    class LoadCategoryCardsTask extends AsyncTask<Void, Void, ArrayList<HairstyleCategoryCard>>{
 
        LoadCallBack callBack;
        int genderId;
 
        public LoadCategoryCardsTask(int genderId, LoadCallBack callBack){
            this.callBack = callBack;
            this.genderId = genderId;
        }
 
        @Override
        protected ArrayList<HairstyleCategoryCard> doInBackground(Void... params) {
            isdLoading = true;
            ArrayList<HairstyleCategoryCard> cards = new ArrayList<>();
            Cursor cursor = db.getReadableDatabase().query("category", null, null, null, null, null, null);
            while (cursor.moveToNext()){
                if(cursor.getInt(cursor.getColumnIndex("genderId")) != genderId){
                    return null;
                }
                HairstyleCategoryCard card = new HairstyleCategoryCard();
                card.setSexId(cursor.getInt(cursor.getColumnIndex("genderId")));
                card.setSexId(cursor.getInt(cursor.getColumnIndex("id")));
                card.setTitle(cursor.getString(cursor.getColumnIndex("title")));
                card.setImageUrl(cursor.getString(cursor.getColumnIndex("imageUrl")));
                cards.add(card);
            }
            cursor.close();
            return cards;
        }
 
        @Override
        protected void onPostExecute(ArrayList<HairstyleCategoryCard> cards) {
            super.onPostExecute(cards);
            isdLoading = false;
            if(cards!= null && cards.size() > 0)
                callBack.onLoadSuccess(cards);
            else
                callBack.onFail("Null table");
        }
    }
}
Проще говоря, прошу проверить опытных программистов на тему утечки памяти. Спасибо)
0
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
18.02.2018, 01:51
Ответы с готовыми решениями:

Определение утечек памяти (Android Studio)
Как можно в AS 1.5 определить строчку кода которая приводит к утечке памяти(не используя MAT)? Или...

Устал от утечек памяти
С этими утечками памяти в C++ просто беда. Посоветуйте, что можно сделать? Может быть есть какие-то...

Обнаружение утечек памяти
Существуют ли какие-нибудь средства позволяющие отлаживать ошибки, вызванные утечками памяти? ...

Обнаружение утечек памяти
в общем есть большой проект, изначально не мой. решил проверить весь код на утечки, подключил...

Чтобы не было утечек памяти
Товарищи, такой вопрос: class node { int *a; double *b; vector&lt;node *&gt; vec; public: //тут...

3
demixdn
312 / 256 / 80
Регистрация: 31.10.2016
Сообщений: 619
19.02.2018, 13:37 2
Araikovich, есть 2 вида необходимости контекста: контекст от приложения, и контекст от активити.
Контекст от приложения нужен для баз данных, контент провайдера, извлечения ресурсов приложения таких как строки, цвета, все то что лежит в res/ и других системных вещей.
Контекст от активити нужен для отображения UI компонентов, например для алерт диалога, view inflate и других UI вещей.
Причем контекст от активити можно использовать как системный, он отработает как нужно. Но если использовать контекст приложения для алерта, то могут быть проблемы с темой приложения, если она другая от активти. Короче есть нюансы и их нужно знать.
К чему я веду. Да, ваш код ведет к утечке актвити. Вы передаете контекст актвити внутрь своих инекций, и скорей всего он будет использоваться для формирования БД и когда асинк такси будут работать, они утянут этот контекст.
Java
1
2
ModelComponent component = DaggerModelComponent.builder().contextModule(new ContextModule(this)).build();
        HairstyleCategoryModel model = component.getHairstyleCategoryModel();
вот этой херни не должно быть в Activity. ContextModule должен формироваться в Application.
Java
1
DaggerModelComponent.builder().contextModule(new ContextModule(this)).build();
не должно вызываться нигде кроме как в Application. Вы же делаете dependency injection и сразу же в актвити раcкрываете детали реализации. WTF?
Java
1
HairstyleCategoryModel model = component.getHairstyleCategoryModel();
не должно быть в принципе. HairstyleCategoryModel должна попасть в конструктор вашего презентера с использованием di инъекции, не через сеттер.
ну а класс HairstyleCategoryModel это нечто особенное, но может это ваш стиль, не буду придираться.
2
Araikovich
10 / 9 / 1
Регистрация: 09.08.2017
Сообщений: 62
19.02.2018, 22:45  [ТС] 3
demixdn, Спасибо огромное! Я через monitors в итоге обнаружил утечки. Насчет HairstyleCategoryModel -
это говно. Но я не знаю, как правильно. Может поделитесь ссылками на хорошие статьи о том, как проектировать model, и о di
0
demixdn
312 / 256 / 80
Регистрация: 31.10.2016
Сообщений: 619
20.02.2018, 17:16 4
Araikovich, вот весьма приличный курс по архитектуре от e-legion. тут еще точка входа в сообщество "чистой" архитектуры. есть еще куча разрозненных статей об архитектуре, но вам того что дал достаточно для того чтоб войти в тему.
2
20.02.2018, 17:16
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
20.02.2018, 17:16

Тулза для поиска утечек памяти
Прога, написанная мною, сильно тормозит. Скорее всего имеются утечки памяти. Подскажите...

Подключении механизма обнаружение утечек памяти
// output N number of M devide L.cpp : Defines the entry point for the console application. // ...

Windows. Обнаружение утечек памяти. Memdbg.lib
memdbg.lib Предисловие Очень часто начинающие (да и опытные иногда) программисты допускают...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru