Проблемы с памятью при использовании внутреннего BroadcastReceiver в деятельности - PullRequest
0 голосов
/ 16 мая 2018

Я уже несколько месяцев пишу приложение для Android в качестве хобби. Теперь я пришел к тому, что мне пришлось осознать, что реальный мир не так прост, как могут звучать некоторые учебные пособия, и что приложение работает по-разному на нескольких устройствах. В настоящее время меня беспокоит использование памяти и процессора в моих приложениях. Я действительно никогда не трачу время на оптимизацию или даже на размышления о своих приложениях с точки зрения использования памяти, и хорошо, я пойду, осознавая, что, вероятно, я действительно запутался во многих моментах, и есть много чего исправить.

К сожалению, я с трудом ищу учебники и объяснения, которые актуальны и понятны для новичков. Многие учебники имеют дело со старыми версиями андроид-студии, и очень хорошие учебники о работе с DDMS. Я чувствую, что в новом Android Profiler (в Android Studio 3.0) отсутствуют некоторые важные идеи. Было бы замечательно, если бы вы помогли мне избавиться от некоторых недоразумений, которые я в настоящее время раздражал долгой ночной чтением многих инструкций и инструкций.

В настоящее время я задаюсь вопросом о BroadcastReceiver в деятельности, которая часто используется. Так, например, у меня есть музыкальное приложение. MainActivity запускает Service для управления воспроизведением музыки. Это Service сообщает деятельности о текущем состоянии воспроизведения и прошедшем времени воспроизведения. Отчетность решается путем отправки намерения из Service во внутренний BroadcastReceiver в пределах именованного MainActivity. Вот упрощенный пример, чтобы вы поняли, что я имею в виду:

public class MainActivity extends Activity {

    private class MusicPlayerBroadcast extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //update UI elements
            seekBar.post(() -> seekBar.setProgress(POSITION)); //using post for thread safeness? 

            //lots of other UI calls 

        }

    }
}

Поскольку я не был уверен, что следующие проблемы возникают из-за неправильной реализации, я решил опубликовать полный код получения намерения:

                            int currentPos = intent.getIntExtra(KEY_POSITION, -1);

                            //check if large player is showing, if not it should display mini Player
                            if(playerRootView.getVisibility() != View.VISIBLE) {
                                mini_Player.setVisibility(View.VISIBLE);
                            }

                            //if the loading hasn't been triggered away yet, this one will help
                            if(relativeLayoutLoading.getVisibility() == View.VISIBLE) {
                                relativeLayoutLoading.setVisibility(View.GONE);
                                playerControls.setVisibility(View.VISIBLE);
                            }

                            TrackModel mCurrentTrack=MusicDataMng.getInstance().getCurrentTrackModel();
                            if (currentPos > 0 && mCurrentTrack != null) {
                                long duration = currentPos / 1000;
                                String minute = String.valueOf((int) (duration / 60));
                                String seconds = String.valueOf((int) (duration % 60));
                                if (minute.length() < 2) {
                                    minute = "0" + minute;
                                }
                                if (seconds.length() < 2) {
                                    seconds = "0" + seconds;
                                }
                                String timePassed = minute + ":" + seconds;

                                if(!seeking) {
                                    // will update the "progress" propriety of seekbar until it reaches progress
                                    seekBar.post(() -> {
                                        ObjectAnimator animation = ObjectAnimator.ofInt(seekBar, "progress", currentPos);
                                        animation.setDuration(1000); // 0.5 second
                                        animation.setInterpolator(new LinearInterpolator());
                                        animation.start();
                                    });

                                } else {
                                    seekBar.post(() -> seekBar.setProgress(currentPos));
                                }
                                mini_ProgressBar.post(() -> mini_ProgressBar.setProgress(currentPos));
                                trackDurationStart.post(() -> trackDurationStart.setText(timePassed));

                            }

То, что я теперь вижу в Android Profiler при записи памяти после того, как начал играть песню, это: Screenshot of Android Profiler excerpt

Мои вопросы по этому поводу следующие:

  1. Мне кажется, что для каждого намерения не следует обновлять позицию экземпляра BroadcastReceiver. Почему они до сих пор хранятся и не удаляются после GC?
  2. Экземпляры содержат ссылку на MainActivity в arg$1.this$0
    • из идентификатора ссылки, я вижу, что они указывают на один и тот же MainActivity. Означает ли это, что они просто хранят указатель на эту ссылку или каждый экземпляр BroadcastReceiver хранит полную ссылку на MainActivity? Если это так, это будет означать интенсивное использование памяти, верно?
  3. Исчезнет ли это неправильное поведение, когда я сделаю BroadcastReceiver статическим, а затем добавлю конструктор, который установит WeakReferences, как описано здесь ?

Если вы чувствуете, что я что-то упустил из-за этой темы о производительности, или мне следует прочитать то или иное руководство или учебник, я был бы очень благодарен за любую рекомендацию.

Заранее спасибо

1 Ответ

0 голосов
/ 16 мая 2018

Объявляя ваш широковещательный приемник как вложенный класс, он содержит ссылку на включающий класс (MainActivity). Вы можете назвать его «указателем», как вы описали для экземпляра MainActivity (в памяти только один экземпляр).

Я не просматривал блог, на который вы ссылались, но, сделав его статичным, этот экземпляр «указатель / ссылка» будет удален.

Мой совет - пройти https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html, чтобы лучше понять вложенные классы в Java и когда / как лучше их использовать.

Что касается вашей конкретной проблемы, я бы порекомендовал использовать EventBus и отправлять обновления вашего плеера на шину, где любые заинтересованные классы могут подписаться и прослушать их.

http://square.github.io/otto

https://github.com/greenrobot/EventBus

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...