Service mit AlarmManager

  • 7 Antworten
  • Neuster Beitrag
B

Braesident

Ambitioniertes Mitglied
Threadstarter
Hallo Leute,

ich weiß, zu diesem Thema gibt es schon etliches im Netz und auch hier.. trotzdem komm ich nicht weiter.

Ein Service soll ca. alle halbe Std. ausgeführt werden. (im Moment alle 60 sek nur Text in eine Datei schreiben - Später http requests und responses)

Nicht funktionierend auf Huawei P30 pro mit Android 9 /api 28
minSdkVersion 21
targetSdkVersion 28

Nachdem es gedauert hat den Receiver für BOOT_COMPLETED gestartet zu bekommen will der Service nicht starten.
Wobei ich mir nicht sicher bin ob es am alarmManager oder Service liegt.
Java:
// Manifest
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/NoActionBar">
        
        <receiver
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">

            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
                <action android:name="android.intent.action.QUICKBOOT_POWERON"/>
                <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
            </intent-filter>
        </receiver>

        ...

        <service android:name=".MyService"
            android:enabled="true">

        </service>
    </application>


// MyBroadcastReceiver
public class MyBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        
        write();
        Log.d("MYBROADCAST", "INCOMMING");

        switch (intent.getAction()){
            case ACTION_BOOT_COMPLETED:
                Log.d("MYBROADCAST", "BOOT COMPLETED"); // Bis hier alles Super

                AlarmManager alarmManager = (AlarmManager)context.getSystemService(ALARM_SERVICE);

                Intent serviceIntent = new Intent(context, RollcardService.class);
                PendingIntent pendingIntent = PendingIntent.getService(context, 0, serviceIntent, 0);

                Calendar calendar = Calendar.getInstance();
                calendar.setTimeInMillis(System.currentTimeMillis() + 1000*60);

                //alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000*60, pendingIntent);
                alarmManager.setWindow(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000*60, pendingIntent);

                break;
        }
    }

    private void write(){

        File folder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);
        File file = new File(folder, "MyService.txt");

        try {
            folder.mkdirs();
            if (!file.exists()) file.createNewFile();

            FileOutputStream outputStream = new FileOutputStream(file, true);
            outputStream.write("ON_RECEIVE \n".getBytes());
            outputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}


// MyService
public class RollcardService extends Service {


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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        //Toast.makeText(getApplicationContext(), "EXECUTE", Toast.LENGTH_LONG).show();
        Log.d("MY_SERVICE", "EXECUTE");

        File folder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);
        File file = new File(folder, "MyService.txt");

        Date currentTime = Calendar.getInstance().getTime();

        try {
            folder.mkdirs();
            if (!file.exists()) file.createNewFile();

            FileOutputStream outputStream = new FileOutputStream(file, true);
            outputStream.write(currentTime.toString().getBytes());
            outputStream.write("\n".getBytes());
            outputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        stopSelf();
        //return super.onStartCommand(intent, flags, startId);
        return START_NOT_STICKY;
    }

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

nun hab ich schon einiges gelesen und gehört... wie z.B. das ein Service unter api 28 nicht mehr gestartet werden könne... ich habe einige ansätze probiert doch leider hat bis jetzt nichts funktioniert.

Hat da jemand eine Idee ?
 
J

jogimuc

Erfahrenes Mitglied
Hallo

Zum Alarmmanager da würde ich nicht „setWindows“ benutzen sondern „setRepeating“
Dann sollte der auch augerufen werden. bedenke das ca. 1min bei aktiver Activity oder ca. 3-5 min bei Activity im Hintergrund vom System gemacht wird. Kleiner meistens nicht.
AlarmManager | Android Developers


Schreiben auf den ExternalStorage wird wohl auch nicht so gehen.
Erstens musst du ab API 23 auch die Permissen zur Laufzeit vom User erfragen.
Permissions overview | Android Developers

zweitens ab API 26 wirst du nicht mehr mit den Standard File Operationen arbeiten Können und mit API 29
Manage scoped external storage access | Android Developers
Open files using storage access framework | Android Developers
 
Zuletzt bearbeitet:
B

Braesident

Ambitioniertes Mitglied
Threadstarter
Hallo jogimuc,

danke mal wieder für deine schnelle Reaktion.
Deine Info zur API 29 ist ja schonmal ein netter Hinweis was mich demnächst erwartet.

setWindow war nur ein Versuch nachdem setRepeating nicht funktioniert hat (deswegen auch noch als Kommentar im Code)
für den den Intervall hab ich zum testen auch 60 sek eingestellt

zum ExternalStorage: die Permission hab ich erfragen lassen in dem ich die App mal geöffnet habe... der Receiver schreibt auch erfolgreich die Zeile "ON_RECEIVE"

Ich hab den Intervall nun auf 5min gestellt... die Verzögerung bei 1min belassen... und setRepeating benutzt
es funktioniert trotzdem nicht

In der LOGCAT hab ich jetzt aber folgende Zeile gefunden:
2019-11-01 15:56:21.506 1171-1602/? W/AlarmManager: mIsScreenOn is: true, WAKEUP alarm trigger action = null package name is: com.mein.package tag: *walarm*:com.mein.package/.MyService window:225000 originWhen:1294186 when:1294187 maxWhen:1519187
Beitrag automatisch zusammengefügt:

jogimuc schrieb:
Dann sollte der auch augerufen werden. bedenke das ca. 1min bei aktiver Activity oder ca. 3-5 min bei Activity im Hintergrund vom System gemacht wird.
Der Service wird doch gestartet ohne das ich eine Activity öffne... oder hab ich da was falsch verstanden?

Also sollte jedenfalls... wenn ich meine App öffne möchte ich ja möglichst aktuelle Daten schon zur Verfügung haben
 
Zuletzt bearbeitet:
J

jogimuc

Erfahrenes Mitglied
Der Service wird doch gestartet ohne das ich eine Activity öffne... oder hab ich da was falsch verstanden?
Frage wird den dein Receiver überhaut aufgerufen?
Kommt der Log.d("MYBROADCAST", "INCOMMING");
Log.d("MYBROADCAST", "BOOT COMPLETED");

Wenn nicht startest du den Alarm gar nicht.

Der Receiver wird eigentlich nur beim Handy Neustart aufgerufen sonst nicht.
Bei der Meldung QUICKBOOT_POWERON" ist nicht in der Switch.

Also sollte jedenfalls... wenn ich meine App öffne möchte ich ja möglichst aktuelle Daten schon zur Verfügung haben
Wenn du deine App startest soltest du den Alarm auch dort starten. Sonst startet er nie.
 
B

Braesident

Ambitioniertes Mitglied
Threadstarter
jogimuc schrieb:
Frage wird den dein Receiver überhaut aufgerufen?
Kommt der Log.d("MYBROADCAST", "INCOMMING");
Log.d("MYBROADCAST", "BOOT COMPLETED");
Ja, beide Logs werden aufgerufen... Natürlich nur nach Neustart.
jogimuc schrieb:
Wenn du deine App startest soltest du den Alarm auch dort starten. Sonst startet er nie.
Mein Ziel war ja den Alarm zu starten um etwas im Hintergrund erledigen zu lassen.
 
J

jogimuc

Erfahrenes Mitglied
Ich würde das estwas anders machen.

In dem Services in der onCreate würde ich den Alarmmanager starten der den Service aufruft.
In der Activity würde ich auch den Service Staren.
In dem Receiver auch den Service.


Service and BOOT_COMPLETED on Android O
 
B

Braesident

Ambitioniertes Mitglied
Threadstarter
Danke jogimuc,

wie in deinem Link schon erwähnt... Service's können nicht mehr als Backgroundprozess gestartet werden (und zwar ab API 26).
Im Link wurde der JobIntentService beschrieben... ich habe mich für den JobService entschieden. In Zusammenhang mit JobInfo und JobScheduler.

Dabei erfolgt die Implementierung in meiner MainActivity. Dort wird der Service gestartet und bleibt auch je nach Einstellung nach einem Neustart aktiv.
Der kürzeste Intervall ist wohl ab API 24 (Nougat) 15min.

Java:
ComponentName componentName = new ComponentName(this, MyJobService.class);
JobInfo jobInfo = new JobInfo.Builder(123, componentName)
       .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
       .setPersisted(true)  // erfordert RECEIVE_BOOT_COMPLETED Permission
       .setPeriodic(1000*30) // wird vom System auf 15*60000 hoch gesetzt
       .build();

JobScheduler scheduler = (JobScheduler)getSystemService(JOB_SCHEDULER_SERVICE);
int rsltCode = scheduler.schedule(jobInfo);
 
markus.tullius

markus.tullius

Experte
Wenn du ein klassischen Service benutzt, muss er als Foreground-Service laufen. Sonst wird er immer nach kurzer Zeit beendet, wenn die App in den Hintergrund geht. Das gilt ab Android 8.0 (Level 26).
Dazu gehört auch eine Benachrichtigung, (Notification).
Die Gründe sind ganz simpel:
Batterie sparen,
Der Nutzer weiß immer, das ein Service läuft (Malware)

Background Execution Limits | Android Developers
 
Oben Unten