Служба была убита при удержании Wake Lock и после вызова startForeground - PullRequest
4 голосов
/ 11 июня 2011

У меня возникла проблема, когда мой сервис был убит, даже если я держу блокировку от пробуждения и позвонил startForeground .Когда это происходит на планшете (ASUS Transformer TF101), останавливает службу без вызова onDestroy .Других приложений не видно, и журнал cat не показывает ничего необычного (нет сообщения «недостаточно памяти» и т. Д.).Сразу после уничтожения служба перезапускается.

Приложение, которое я разрабатываю, является клиентом чата и требует постоянного подключения, оно также основано на плагинах, поэтому мое приложение разработано так: Клиент - HostService - Несколько дочерних'Сервисы'.

Хост-служба закреплена, удерживает блокировку пробуждения и вызывает startForeground (и отображает уведомление как таковое), дочерние службы не привязываются, не удерживают блокировку пробуждения и являются фоновыми службами.

Если сам клиент открыт, проблема не возникает, но модель, которую я использую, заключается в том, что пользователь может использовать устройство и оставаться на связи (получать сообщения и т. Д.), Не открывая при этом самого клиента.

Может ли кто-нибудь дать какое-либо объяснение тому, почему служба убивается таким образом, и если да, то предотвратить ее?Как показывают клиенты чата, когда пользователь входит в систему и выходит из нее, а служба умирает, убивая все открытые соединения, это заставляет клиента чата «подпрыгивать».В настоящее время это, кажется, происходит где-то между каждыми 15 и 45 минутами.

Кроме того, если кто-то знает о способе держать соединение сокета открытым непрерывно, не удерживая блокировку пробуждения в течение всей продолжительности соединения, я был бы радчтобы услышать это!

Ниже приведена версия расширенного тестового примера источника службы хоста.

public class HostService extends Service
{
    PowerManager m_powerManager = null;
    PowerManager.WakeLock m_wakeLock = null;

    @Override
    public IBinder onBind( Intent intent )
    {
        return m_serviceImplementation;
    }

    @Override
    public void onCreate()
    {
        super.onCreate();       
    }

    @Override
    public void onDestroy()
    {
        if( m_wakeLock != null )
        {
            m_wakeLock.release();
            m_wakeLock = null;
        }

        stopForeground( true );

        super.onDestroy();
    }

    @Override
    public int onStartCommand( Intent intent, int flags, int startId )
    {
        // Display a notification about us starting. We put an icon in the
        // status bar.
        Notification notification = createNotification();

        startForeground( R.string.service_running, notification );

        if( m_powerManager == null )
        {
            m_powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
        }

        if( m_wakeLock == null )
        {
            m_wakeLock = m_powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Keep background services running");
            m_wakeLock.acquire();
        }

        // We want this service to continue running until it is explicitly
        // stopped, so return sticky.
        return START_STICKY;
    }

    /**
     * Create a notification to show the service is running
     */
    private Notification createNotification()
    {
        CharSequence text = getText( R.string.service_running );
        CharSequence title = getText( R.string.app_name );

        // The PendingIntent to launch our activity if the user selects this
        // notification
        PendingIntent contentIntent = PendingIntent.getActivity( this, 0, new Intent(this, MainChat.class) , 0 );

        Notification notification = new Notification( android.R.drawable.sym_action_chat, title, System.currentTimeMillis() );  
        notification.setLatestEventInfo( this, title, text, contentIntent );

        return notification;
    }

    private final IMessageInterface.Stub m_serviceImplementation = new IMessageInterface.Stub()
    {
        ...
    };
}

Манифест Android (соответствующие биты):

<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="11" />

<service android:name="com.mydomain.chatClient.server.HostService" android:exported="true" android:enabled="true" android:process=":remote"/>

<uses-permission android:name="android.permission.WAKE_LOCK" />

1 Ответ

10 голосов
/ 11 июня 2011

У меня возникла проблема, когда мой сервис был убит, даже если я держу блокировку от пробуждения и вызвал startForeground.

startForeground() уменьшает вероятность того, что служба будет убита, но не предотвращает ее.

Приложение, которое я разрабатываю, является клиентом чата и нуждается в постоянном соединении, оно также основано на плагинах, поэтому мое приложение разработано так: Клиент - HostService - Несколько дочерних «Служб».

Я рекомендую избавиться от одного из этих слоев. Даже если ОС не закрывает вас, многие пользователи (например, убийца задач, Запуск служб в настройках) считают, что вы используете слишком много служб.

Если сам клиент открыт, проблема не возникает, но модель, которую я использую, заключается в том, что пользователь может использовать устройство и оставаться на связи (получать сообщения и т. Д.), Не открывая при этом самого клиента.

Я рекомендую сделать это необязательным. Вы можете подумать, что это сексуально. Некоторые из ваших пользователей будут атаковать вас за то, что вы тратите свою батарею.

Кто-нибудь может дать какое-либо объяснение тому, почему служба убивается таким образом, и если да, то предотвратить это?

Я бы начал с избавления от android:process=":remote". Тебе это не нужно. Ты не хочешь этого. Вы можете причинить себе вред, имея его, так как это может ускорить интерес Android к избавлению от вашего сервиса. Вы абсолютно причиняете вред пользователям, потому что вы тратите ОЗУ без всякой причины.

Тогда я бы избавился от плагинов, если бы вы реализовали их как отдельные приложения. В этом случае каждый из них будет работать в своем собственном процессе, тратя впустую еще больше оперативной памяти. Кроме того, ваша текущая реализация была бы ошибочной, так как вы застряли бы, если бы ваша служба называлась com.mydomain.chatClient.server.HostService до конца времени, так как вы не использовали <intent-filter>, чтобы отделить вопросы о том, "как служба названа внутренне". "и" как сервис называется другими отдельно установленными приложениями, которые хотят его использовать ". И если вы не не реализовали плагины как отдельные приложения, то я не вижу смысла в том, чтобы они были в отдельных сервисах, а не складывали их все в один сервис.

Кроме того, если кто-нибудь знает, как постоянно поддерживать соединение через сокет, не удерживая блокировку пробуждения в течение всего времени соединения, я хотел бы услышать это!

Если в разъеме используются беспроводные данные, а не WiFi, вам не нужно все время WakeLock. Сокет останется открытым, и входящие пакеты на этом сокете разбудят ваш код. В этот момент вам захочется взять WakeLock достаточно долго, чтобы вы могли делать все, что вы делаете с данными, когда они поступят, а затем выпустить WakeLock.

Если вы используете WiFi, этот прием не работает, поэтому потребуется WakeLock (и, вероятно, WifiLock).

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