Android запускает мою службу до того, как собственное расширение Air вызовет ее

Я разрабатываю мобильное приложение Air (Flex) для Android, которое использует Air Native Extension (ANE), чтобы использовать некоторые функции платформы, которые иначе нельзя было бы использовать (по крайней мере, насколько мне известно). Одной из функций платформы, которую я хочу использовать, являются службы, в частности службы, которые запускаются как процессы переднего плана (используя метод startForeground()). Когда я вызываю службу из своего ANE, все работает как часы, служба запускается правильно и делает то, что нужно, но проблема в том, что Android, кажется, пытается запустить ее независимо от моего кода, что, конечно, приводит к ошибкам, которые появляются в LogCat. Когда я запускаю приложение в режиме отладки в Flash Builder и использую его какое-то время, проверяя, что сервис работает отлично и не выдает ошибок, после того, как я закрываю его из Flash Builder (не из Eclipse ADT, что я тоже мог) через пару секунд появляются следующие ошибки:

01-16 10:56:06.953: E/AndroidRuntime(9757): java.lang.RuntimeException: Unable to start service com.mycompany.myextension.services.MyService@41594a50 with Intent { cmp=air.QOE.debug/com.mycompany.myextension.services.MyService }: java.lang.NullPointerException
01-16 10:56:06.953: E/AndroidRuntime(9757):     at com.mycompany.myextension.services.MyService.onStartCommand(MyService.java:37) 

Кажется очевидным, что Android пытается запустить службу, но, поскольку ее дизайн предназначен для работы внутри ANE — расширение инициализировано, но его контекст уже удален — происходит сбой, потому что он не может получить доступ к переменным, которые инициализируются в контексте, следовательно, заканчивается сбоем или ошибкой при первом использовании контекстной переменной в коде (строка 37). Я думаю, что это связано с тем, как я объявил службу в своем файле манифеста Android. Далее идет часть XML:

<application android:debuggable="true">
              <service android:enabled="true" android:exported="true" android:name="com.mycompany.myextension.services.MyService">    
                        <intent-filter>
                                 <action android:name="air.com.mycompany.myextension.DO_CUSTOM_ACTION"/>
                        </intent-filter>
                </service>
</application>

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

РЕДАКТИРОВАТЬ: Сервисный код

package com.mydomain.myapplicationextension.services;

import java.util.Timer;

import com.adobe.fre.FREContext;
import com.mydomain.myapplicationextension.myapplicationextension;
import com.mydomain.myapplicationextension.components.HttpServiceTask;

import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;

public class MyApplicationService extends Service {

    private Timer timer;  

    @Override
    public IBinder onBind(Intent arg0) {
        // Log.d("MyApplicationService", "onBind()");
        return null;
    }
    
    @Override
    public void onCreate() {
        // Log.d("MyApplicationService", "onCreate()");
        super.onCreate();
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // Log.d("MyApplicationService", "onStartCommand(): " + myapplicationextension.applicationID);
                
        Context appContext = myapplicationextension.applicationContext;     
        Intent launchIntent = appContext.getPackageManager().getLaunchIntentForPackage(myapplicationextension.appPackageName);      
        PendingIntent pendingLaunchIntent = PendingIntent.getActivity(appContext, 0, launchIntent, 0);
        
        FREContext extContext = myapplicationextension.extensionContext;
        int icon = extContext.getResourceId("drawable.notification_icon");
        
        Notification notification = new Notification.Builder(appContext)
                                                    .setContentTitle(myapplicationextension.applicationID)
                                                    .setContentText(myapplicationextension.notificationMessage)
                                                    .setSmallIcon(icon)
                                                    .setContentIntent(pendingLaunchIntent)
                                                    .build();
        startForeground(1,notification);
        // Log.d("MyApplicationService", "startForegroundService()");
        
        if(myapplicationextension.checkStatus)
        {
            timer = new Timer("Printer");
            HttpServiceTask serviceTask = new HttpServiceTask(timer, launchIntent,myapplicationextension.statusServiceURL, myapplicationextension.triggerResponse);
            timer.schedule(serviceTask, 0, 2000);
            // Log.d("MyApplicationService", "startTimer()");
        }
        
        return START_STICKY;
    }
    
    @Override
    public void onDestroy() {
        // Log.d("MyApplicationService", "onDestroy():");
        if(myapplicationextension.checkStatus)
        {
            timer.cancel();
            timer = null;
            // Log.d("MyApplicationService", "onDestroy(): timer.cancel():");
        }
        super.onDestroy();
    }
}

person SebastianT    schedule 16.01.2014    source источник
comment
Вы регистрируете какой-либо BroadcastReceiver для запуска службы?   -  person Delcasda    schedule 18.01.2014
comment
@ Делкасда, нет. Я запускаю службу, вызывающую startService() из native function. Внутри onStartCommand() я использую startForeground(). Таким образом, BroadcastReceiver не используется. Любые другие идеи?   -  person SebastianT    schedule 20.01.2014
comment
вы используете возврат START_STICKY; в onStartCommand? Это заставляет службу автоматически запускаться, но было бы легко, если бы вы хотя бы разместили какой-то код из своей службы.   -  person Delcasda    schedule 20.01.2014
comment
@Делькасда. Да, я использую START_STICKY в onStartCommand?. Как вы мне посоветуете это сделать. Я отредактировал пост и добавил код услуги.   -  person SebastianT    schedule 21.01.2014


Ответы (1)


Когда в телефоне заканчивается память и он убивает службу до того, как она завершит выполнение. START_STICKY указывает ОС воссоздать службу после того, как у нее будет достаточно памяти, и снова вызвать onStartCommand() с нулевым намерением. START_NOT_STICKY сообщает ОС, чтобы она больше не создавала службу заново. Существует также третий код START_REDELIVER_INTENT, который сообщает ОС воссоздать службу И повторно доставить то же самое намерение onStartCommand().

START_STICKY и START_NOT_STICKY

У меня есть ANE, использующий START_STICKY, который продолжает запускать службу

person Delcasda    schedule 21.01.2014
comment
Я думаю, что это правильно, но у меня есть только один вопрос. Когда служба воссоздается, что происходит с переменными, свойствами и задачами, которые были созданы до того, как служба была уничтожена (из-за проблем с памятью)? Они начинаются как нулевые или все будет, как было раньше? Вызывается ли метод onCreate() снова перед onStartCommand()? - person SebastianT; 21.01.2014
comment
Я не знаю, но вы можете легко найти переопределение метода onCreate и добавление этого: Toast.makeText(this, служба запускается при создании, Toast.LENGTH_SHORT).show(); - person Delcasda; 21.01.2014
comment
Если вы считаете, что это ответ, отметьте его как принятый ответ. - person Delcasda; 21.01.2014
comment
Чтобы ответить на мой вопрос, он вызывает onCreate() перед вызовом onStartCommand() при воссоздании после его уничтожения из-за проблем с памятью. По крайней мере, это то, что показывает мой журнал. Спасибо за помощь. - person SebastianT; 21.01.2014
comment
Как вы думаете, вы могли бы взглянуть на вопрос, который вызвал этот ответ? :) stackoverflow.com/questions/21268922/ - person SebastianT; 22.01.2014