Android: iniciar el servicio al arrancar

107

De todo lo que he visto en Stack Exchange y en otros lugares, tengo todo configurado correctamente para iniciar un IntentService cuando se inicia el sistema operativo Android. Desafortunadamente, no se inicia al arrancar y no recibo ningún error. Quizás los expertos puedan ayudar ...

Manifiesto:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.phx.batterylogger"
  android:versionCode="1"
  android:versionName="1.0"
  android:installLocation="internalOnly">

<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.BATTERY_STATS" />

<application android:icon="@drawable/icon" android:label="@string/app_name">
    <service android:name=".BatteryLogger"/>
    <receiver android:name=".StartupIntentReceiver">  
        <intent-filter>  
            <action android:name="android.intent.action.BOOT_COMPLETED" />  
        </intent-filter>  
    </receiver>
</application>

</manifest>

BroadcastReceiver para el inicio:

package com.phx.batterylogger;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class StartupIntentReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent serviceIntent = new Intent(context, BatteryLogger.class);
        context.startService(serviceIntent);
    }
}

ACTUALIZACIÓN : probé casi todas las sugerencias a continuación y agregué registros como Log.v("BatteryLogger", "Got to onReceive, about to start service");el controlador onReceive de StartupIntentReceiver, y nunca se registra nada. Así que ni siquiera está llegando al BroadcastReceiver.

Creo que estoy implementando el APK y probando correctamente, solo ejecuto Debug en Eclipse y la consola dice que lo instaló correctamente en mi tableta Xoom en \ BatteryLogger \ bin \ BatteryLogger.apk. Luego, para probar, reinicio la tableta y luego miro los registros en DDMS y verifico los servicios en ejecución en la configuración del sistema operativo. ¿Todo esto suena correcto o me falta algo? Una vez más, se agradece mucho cualquier ayuda.

Gady
fuente
1
¿Qué problema tienes? ¿No tienes IU ...?
Lalit Poptani
1
El servicio nunca comienza, ese es el problema.
Gady
¿Cómo se da cuenta de que su servicio no está comenzando, ha impreso los registros o algo por el estilo ...?
Lalit Poptani
1
No necesita registros para ver que no se está ejecutando. El sistema operativo Android expone los servicios en ejecución. Sin embargo, sería aconsejable utilizar el registro para ver si se está produciendo un error. Me atrevería a suponer que sucede antes de context.startService () si se produce un error.
Tony
1
He añadido Log.v("BatteryLogger", "Got to onReceive, about to start service");al controlador de OnReceive, y nunca aparece en los registros. Entonces el oyente está fallando (?)
Gady

Respuestas:

302

Bueno, aquí hay un ejemplo completo de una aplicación de inicio automático

Archivo AndroidManifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="pack.saltriver" android:versionCode="1" android:versionName="1.0">

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

    <application android:icon="@drawable/icon" android:label="@string/app_name">

        <receiver android:name=".autostart">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

        <activity android:name=".hello"></activity>
        <service android:enabled="true" android:name=".service" />
    </application>
</manifest>

autostart.java

public class autostart extends BroadcastReceiver 
{
    public void onReceive(Context context, Intent arg1) 
    {
        Intent intent = new Intent(context,service.class);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.startForegroundService(intent);
        } else {
            context.startService(intent);
        }
        Log.i("Autostart", "started");
    }
}

service.java

public class service extends Service
{
    private static final String TAG = "MyService";
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    public void onDestroy() {
        Toast.makeText(this, "My Service Stopped", Toast.LENGTH_LONG).show();
        Log.d(TAG, "onDestroy");
    }

    @Override
    public void onStart(Intent intent, int startid)
    {
        Intent intents = new Intent(getBaseContext(),hello.class);
        intents.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intents);
        Toast.makeText(this, "My Service Started", Toast.LENGTH_LONG).show();
        Log.d(TAG, "onStart");
    }
}

hello.java : aparecerá cada vez que inicie el dispositivo después de ejecutar la aplicación una vez.

public class hello extends Activity 
{   
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Toast.makeText(getBaseContext(), "Hello........", Toast.LENGTH_LONG).show();
    }
}
Lalit Poptani
fuente
10
+1 para un ejemplo completo. Tal vez debería cambiar mi IntentService con onHandleIntent a un servicio simple y antiguo
Gady
6
Esto lo resolvió en última instancia. El problema era una combinación de que mi servicio era un IntentService en lugar de un simple Servicio antiguo y errores en el código de servicio. La minuciosidad de esta respuesta y el inicio de sesión en Android me ayudaron a resolver mis problemas.
Gady
3
+1 para el ejemplo detallado. ¿Funcionaría esto también sin una actividad?
balas
1
La devolución de llamada onStart () está obsoleta. Debería usar onStartCommand () en su lugar.
mmBs
1
@mmBs esta respuesta tiene casi 5 años, por lo que es obvio
Lalit Poptani
3

Es posible que su servicio se cierre antes de que se complete debido a que el dispositivo se pone en suspensión después del inicio. Primero debe obtener un bloqueo de activación. Afortunadamente, la biblioteca de soporte nos da una clase para hacer esto:

public class SimpleWakefulReceiver extends WakefulBroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // This is the Intent to deliver to our service.
        Intent service = new Intent(context, SimpleWakefulService.class);

        // Start the service, keeping the device awake while it is launching.
        Log.i("SimpleWakefulReceiver", "Starting service @ " + SystemClock.elapsedRealtime());
        startWakefulService(context, service);
    }
}

luego, en su Servicio, asegúrese de liberar el bloqueo de activación:

    @Override
    protected void onHandleIntent(Intent intent) {
        // At this point SimpleWakefulReceiver is still holding a wake lock
        // for us.  We can do whatever we need to here and then tell it that
        // it can release the wakelock.

...
        Log.i("SimpleWakefulReceiver", "Completed service @ " + SystemClock.elapsedRealtime());
        SimpleWakefulReceiver.completeWakefulIntent(intent);
    }

No olvide agregar el permiso WAKE_LOCK:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
phreakhead
fuente
1
Estoy teniendo el mismo problema. ¿Te importaría ayudarme? ¡Gracias! stackoverflow.com/questions/35373525/starting-my-service
Ruchir Baronia
2

Lo siguiente debería funcionar. Lo he verificado. Puede que tu problema esté en otro lugar.

public class MyReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("TAG", "MyReceiver");
        Intent serviceIntent = new Intent(context, Test1Service.class);
        context.startService(serviceIntent);
    }
}




public class Test1Service extends Service {
    /** Called when the activity is first created. */
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("TAG", "Service created.");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("TAG", "Service started.");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        Log.d("TAG", "Service started.");
    }
    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }
}




<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.test"
      android:versionCode="1"
      android:versionName="1.0"
      android:installLocation="internalOnly">
    <uses-sdk android:minSdkVersion="8" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.BATTERY_STATS" 
    />
<!--        <activity android:name=".MyActivity">
            <intent-filter>  
                <action android:name="android.intent.action.MAIN" /> 
                <category android:name="android.intent.category.LAUNCHER"></category> 
            </intent-filter>
       </activity> -->
        <service android:name=".Test1Service" 
                  android:label="@string/app_name"
                  >
        </service>
        <receiver android:name=".MyReceiver">  
            <intent-filter>  
                <action android:name="android.intent.action.BOOT_COMPLETED" /> 
            </intent-filter>  
        </receiver> 
    </application>
</manifest>
Vivek
fuente
Gracias por esto, pero aun así no funcionó. Los registros ni siquiera muestran que llega a StartupIntentReceiver. ¿Alguna otra idea?
Gady
1
¿Tu código funciona en el emulador? ¿Puedes recibir la intención en el emulador?
Vivek
Probé en el emulador y obtengo un error en DDMS, pero parece que al menos el servicio está intentando iniciarse, aunque ninguna de mis Log()declaraciones está allí y el dispositivo emulador no muestra que mi servicio se esté ejecutando en la configuración del sistema operativo. Aquí está el error en DDMS: System.err - at com.phx.batterylogger$1.onReceive(BatteryLogger.java:43)¿ Eso significa que el problema está en la línea 43 de mi servicio BatteryLogger?
Gady
2

Encontré una manera de hacer que su aplicación funcione bien cuando el dispositivo se reinicia, siga los pasos a continuación para tener éxito.

Archivo AndroidManifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="pack.saltriver" android:versionCode="1" android:versionName="1.0">
<uses-permission 
android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<application android:icon="@drawable/icon" android:label="@string/app_name">

<activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <receiver android:name=".UIBootReceiver" android:enabled="true" 
    android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </receiver>
     <service android:name=".class_Service" />
</application>

UIBootReceiver

public class UIBootReceiver extends BroadcastReceiver {

private static final String TAG = "UIBootReceiver";
@Override

    public void onReceive(Context context, Intent arg1)
    {
        Toast.makeText(context, "started", Toast.LENGTH_SHORT).show();
        Intent intent = new Intent(context,class_Service.class);
        context.startService(intent);
    }
  }

Se solicita permiso para no tener que administrar el ahorro de batería para esta aplicación para que pueda ejecutarla en segundo plano de manera estable.

Declare este código en onCreate () de la clase MainActivity:

   Intent myIntent = new Intent();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        myIntent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
        myIntent.setData(Uri.parse("package:" + 
   DeviceMovingSpeed.this.getPackageName()));
    }
    startActivity(myIntent);
Huy TRAN
fuente
1

Parece muy similar al mío, pero uso el nombre completo del paquete para el receptor:

<receiver android:name=".StartupIntentReceiver">

Yo tengo:

<receiver android:name="com.your.package.AutoStart"> 
ciscogambo
fuente
Sí, fue un poco complicado solucionar el problema, así que es mejor publicar un ejemplo de Hola mundo.
Lalit Poptani
1

Tuve éxito sin el paquete completo, ¿sabe dónde se interrumpe la cadena de llamadas? Si depura con Log()'s, ¿en qué momento deja de funcionar?

Creo que puede estar en su IntentService, todo esto se ve bien.

Phix
fuente
He añadido Log.v("BatteryLogger", "Got to onReceive, about to start service");al controlador de OnReceive, y nunca aparece en los registros. Entonces el oyente está fallando (?)
Gady
¿Qué hace que el receptor de transmisión se inicie cuando se inicia el teléfono? ¡Gracias!
Ruchir Baronia
Chico. No he tocado Android en algunos años. Lo siento @Ruchir
Phix
0

Solo para facilitar la búsqueda, como se menciona en los comentarios, esto no es posible desde 3.1 https://stackoverflow.com/a/19856367/6505257

MrKew
fuente
Eso no es cierto, como lo indica Think Twice Code Once en la sección de comentarios de la misma respuesta.
Ricardo A.
Una explicación más detallada para apoyar mi argumento: stackoverflow.com/questions/20441308/…
Ricardo A.
Hace mucho tiempo que no hago nada con Android, pero tienes razón, es posible. No son necesarios otros argumentos. (
Editaré