简体   繁体   中英

How to call a class which extends service using alarm manager?

I am trying to create a service for notifications, which will start after 2 minutes from booting the device(device is powered on) & will check for notifications.

Also it will be called every 2 minutes. Basically I am trying to make notifications appear to the user when necessary.

I wrote this code in my manifest:

 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.newsapp"
android:versionCode="1"
android:versionName="1.0" 
android:installLocation="internalOnly">
 <uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- For notifications /\ -->
<application
    android:allowBackup="true"
    android:icon="@drawable/logo"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >

    <receiver android:name="com.example.newsapp.MainActivity$MyReciever"
        android:enabled="true"
        android:exported="true">
<!--            android:label="MyReciever"> -->
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="android.intent.action.QUICKBOOT_POWERON" />
        <!-- for HTC devices /\ -->
    </intent-filter>
</receiver>

    <activity
        android:name="com.example.newsapp.MainActivity"
        android:label="@string/app_name"
        android:launchMode="singleInstance"
        android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
        android:theme="@android:style/Theme.NoTitleBar.Fullscreen" 
         >

        <!-- make full screen up /\ -->
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

</manifest>

And this code in Java:

  public static class NotificationService extends Service {

        private WakeLock mWakeLock;
        private Intent mintent;
        /**
         * Simply return null, since our Service will not be communicating with
         * any other components. It just does its work silently.
         */
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }

        /**
         * This is where we initialize. We call this when onStart/onStartCommand is
         * called by the system. We won't do anything with the intent here, and you
         * probably won't, either.
         */
        private void handleIntent(Intent intent) {
            // obtain the wake lock
            Log.d("NotificationService", "is in handleIntent");
            mintent = intent;
            PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
            mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NewTag");//change the newtag
            mWakeLock.acquire();

            // check the global background data setting
            ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
            if (!cm.getBackgroundDataSetting()) {
                stopSelf();
                return;
            }

            // do the actual work, in a separate thread
            new PollTask().execute(null,null,null);
        }

        private class PollTask extends AsyncTask<Object,Object,String> {
            /**
             * This is where YOU do YOUR work. There's nothing for me to write here
             * you have to fill this in. Make your HTTP request(s) or whatever it is
             * you have to do to get your updates in here, because this is run in a
             * separate thread
             */


            protected String  doInBackground(Object... params) {
                // do stuff!
                Log.d("*************************", "is in doInBackground");
                 SoapObject  request = new SoapObject(NAMESPACE, METHOD_NAME2);  
                            String result1="";
                            SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
                            envelope.setOutputSoapObject(request);
                            envelope.dotNet = true;
                            try 
                            {
                                HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
                                androidHttpTransport.call(SOAP_ACTION2, envelope);
                                //Object result = (Object)envelope.getResponse(); // when calling a webmethod with parameters                           
                                SoapObject result = (SoapObject)envelope.getResponse(); // when calling a webmethod without parameters
                                if (result!=null)           
                                {
                                    PropertyInfo innerp=new PropertyInfo();
                                    result.getPropertyInfo(0, innerp);
                                    //SoapObject sobj=(SoapObject) result.getProperty(0);
                                    result1= innerp.toString();
                                    return result1;         
                                }
                                    else 
                                    {



                                    }

                            }
                            catch (Exception e)
                            {
                                result1 = e.getMessage();

                                e.printStackTrace();
                                return null;

                            }

                        return null;
            }

            /**
             * In here you should interpret whatever you fetched in doInBackground
             * and push any notifications you need to the status bar, using the
             * NotificationManager. I will not cover this here, go check the docs on
             * NotificationManager.
             *
             * What you HAVE to do is call stopSelf() after you've pushed your
             * notification(s). This will:
             * 1) Kill the service so it doesn't waste precious resources
             * 2) Call onDestroy() which will release the wake lock, so the device
             *    can go to sleep again and save precious battery.
             */
            protected void onPostExecute(String  result) {
                // TODO Auto-generated method stub
                super.onPostExecute(result);
                stopSelf();
                if (result!=null && result.equals("true"))
                {

                    //new doWork2().execute(null,null,null);
                }
                else
                {

                }
            }
        }

        /**
         * This is deprecated, but you have to implement it if you're planning on
         * supporting devices with an API level lower than 5 (Android 2.0).
         */
        @Override
        public void onStart(Intent intent, int startId) {
            handleIntent(intent);
        }

        /**
         * This is called on 2.0+ (API level 5 or higher). Returning
         * START_NOT_STICKY tells the system to not restart the service if it is
         * killed because of poor resource (memory/cpu) conditions.
         */
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.d("NotificationService*************************", "is in onStartCommand");
            handleIntent(intent);
            return START_NOT_STICKY;
        }

        /**
         * In onDestroy() we release our wake lock. This ensures that whenever the
         * Service stops (killed for resources, stopSelf() called, etc.), the wake
         * lock will be released.
         */
        public void onDestroy() {
            super.onDestroy();
            mWakeLock.release();
        }
    }
    public static class MyReciever extends BroadcastReceiver {//remove static later

        @Override
        public void onReceive(Context arg0, Intent arg1) {
            // TODO Auto-generated method stub
            //If this BroadcastReceiver was launched through a <receiver> tag, then the object is no longer alive after returning from this function
            // TODO Auto-generated method stub
            // in our case intent will always be BOOT_COMPLETED, so we can just set
            // the alarm
            // Note that a BroadcastReceiver is *NOT* a Context. Thus, we can't use
            // "this" whenever we need to pass a reference to the current context.
            // Thankfully, Android will supply a valid Context as the first parameter
            target = arg0;
            Log.d("BootReciever", "is in onRecieve");
            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(arg0);
            int minutes = prefs.getInt("interval",2);//change the 2- is the value to return if this doesn't return a value
            AlarmManager am = (AlarmManager) arg0.getSystemService(Context.ALARM_SERVICE);
            Intent i = new Intent(arg0, NotificationService.class);//or com.example.newsapp.MainActivity.NotificationService.class

           // arg0.startService(i);//lets try this
            PendingIntent pi = PendingIntent.getService(arg0, 0, i, 0);
            am.cancel(pi);//removes any alarm with matching intent
            // by my own convention, minutes <= 0 means notifications are disabled
            if (minutes > 0) {
                am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                    SystemClock.elapsedRealtime() + minutes*60*1000,
                    minutes*60*1000, pi);
                Log.d("BootReciever", "minutes>0");
            }
            Toast.makeText(arg0, "onRecieve", Toast.LENGTH_LONG).show();
        }


    }

Now, the onReceive function is called, but my PROBLEM is that the NotificationService class DOES NOT START as a service, I believe that it is NOT CALLED. I just want to call the onStartCommand function in NotificationService class, so it will call the handleIntent method & then it will check for notifications by calling a web service method.

When the 2 minutes pass & it's time to start the NotificationService I get this logcat:

    02-25 11:22:30.927: D/dalvikvm(288): GC_CONCURRENT freed 1967K, 35% free 5820K/8916K, paused 87ms+10ms, total 204ms
02-25 11:22:34.319: E/ThrottleService(288): problem during onPollAlarm: java.lang.IllegalStateException: problem parsing stats: java.io.FileNotFoundException: /proc/net/xt_qtaguid/iface_stat_all: open failed: ENOENT (No such file or directory)
02-25 11:23:13.998: D/ExchangeService(603): Received deviceId from Email app: null
02-25 11:23:13.998: D/ExchangeService(603): !!! deviceId unknown; stopping self and retrying
02-25 11:23:19.067: D/ExchangeService(603): !!! EAS ExchangeService, onCreate
02-25 11:23:19.077: D/ExchangeService(603): !!! EAS ExchangeService, onStartCommand, startingUp = false, running = false
02-25 11:23:19.087: D/ExchangeService(603): !!! EAS ExchangeService, onStartCommand, startingUp = true, running = false
02-25 11:23:19.097: W/ActivityManager(288): Unable to start service Intent { act=com.android.email.ACCOUNT_INTENT } U=0: not found
02-25 11:23:19.097: D/ExchangeService(603): !!! Email application not found; stopping self
02-25 11:23:19.127: E/ActivityThread(603): Service com.android.exchange.ExchangeService has leaked ServiceConnection com.android.emailcommon.service.ServiceProxy$ProxyConnection@40d2b0e0 that was originally bound here
02-25 11:23:19.127: E/ActivityThread(603): android.app.ServiceConnectionLeaked: Service com.android.exchange.ExchangeService has leaked ServiceConnection com.android.emailcommon.service.ServiceProxy$ProxyConnection@40d2b0e0 that was originally bound here
02-25 11:23:19.127: E/ActivityThread(603):  at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:969)
02-25 11:23:19.127: E/ActivityThread(603):  at android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:863)
02-25 11:23:19.127: E/ActivityThread(603):  at android.app.ContextImpl.bindService(ContextImpl.java:1418)
02-25 11:23:19.127: E/ActivityThread(603):  at android.app.ContextImpl.bindService(ContextImpl.java:1407)
02-25 11:23:19.127: E/ActivityThread(603):  at android.content.ContextWrapper.bindService(ContextWrapper.java:473)
02-25 11:23:19.127: E/ActivityThread(603):  at com.android.emailcommon.service.ServiceProxy.setTask(ServiceProxy.java:157)
02-25 11:23:19.127: E/ActivityThread(603):  at com.android.emailcommon.service.ServiceProxy.setTask(ServiceProxy.java:145)
02-25 11:23:19.127: E/ActivityThread(603):  at com.android.emailcommon.service.ServiceProxy.test(ServiceProxy.java:191)
02-25 11:23:19.127: E/ActivityThread(603):  at com.android.exchange.ExchangeService$7.run(ExchangeService.java:1850)
02-25 11:23:19.127: E/ActivityThread(603):  at com.android.emailcommon.utility.Utility$2.doInBackground(Utility.java:551)
02-25 11:23:19.127: E/ActivityThread(603):  at android.os.AsyncTask$2.call(AsyncTask.java:287)
02-25 11:23:19.127: E/ActivityThread(603):  at java.util.concurrent.FutureTask.run(FutureTask.java:234)
02-25 11:23:19.127: E/ActivityThread(603):  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
02-25 11:23:19.127: E/ActivityThread(603):  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
02-25 11:23:19.127: E/ActivityThread(603):  at java.lang.Thread.run(Thread.java:856)
02-25 11:23:19.127: W/ActivityManager(288): Unable to start service Intent { act=com.android.email.ACCOUNT_INTENT } U=0: not found
02-25 11:23:19.237: E/StrictMode(603): null
02-25 11:23:19.237: E/StrictMode(603): android.app.ServiceConnectionLeaked: Service com.android.exchange.ExchangeService has leaked ServiceConnection com.android.emailcommon.service.ServiceProxy$ProxyConnection@40d2b0e0 that was originally bound here
02-25 11:23:19.237: E/StrictMode(603):  at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:969)
02-25 11:23:19.237: E/StrictMode(603):  at android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:863)
02-25 11:23:19.237: E/StrictMode(603):  at android.app.ContextImpl.bindService(ContextImpl.java:1418)
02-25 11:23:19.237: E/StrictMode(603):  at android.app.ContextImpl.bindService(ContextImpl.java:1407)
02-25 11:23:19.237: E/StrictMode(603):  at android.content.ContextWrapper.bindService(ContextWrapper.java:473)
02-25 11:23:19.237: E/StrictMode(603):  at com.android.emailcommon.service.ServiceProxy.setTask(ServiceProxy.java:157)
02-25 11:23:19.237: E/StrictMode(603):  at com.android.emailcommon.service.ServiceProxy.setTask(ServiceProxy.java:145)
02-25 11:23:19.237: E/StrictMode(603):  at com.android.emailcommon.service.ServiceProxy.test(ServiceProxy.java:191)
02-25 11:23:19.237: E/StrictMode(603):  at com.android.exchange.ExchangeService$7.run(ExchangeService.java:1850)
02-25 11:23:19.237: E/StrictMode(603):  at com.android.emailcommon.utility.Utility$2.doInBackground(Utility.java:551)
02-25 11:23:19.237: E/StrictMode(603):  at com.android.emailcommon.utility.Utility$2.doInBackground(Utility.java:549)
02-25 11:23:19.237: E/StrictMode(603):  at android.os.AsyncTask$2.call(AsyncTask.java:287)
02-25 11:23:19.237: E/StrictMode(603):  at java.util.concurrent.FutureTask.run(FutureTask.java:234)
02-25 11:23:19.237: E/StrictMode(603):  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
02-25 11:23:19.237: E/StrictMode(603):  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
02-25 11:23:19.237: E/StrictMode(603):  at java.lang.Thread.run(Thread.java:856)
02-25 11:23:19.237: W/ActivityManager(288): Unbind failed: could not find connection for android.os.BinderProxy@40e43db8
02-25 11:23:19.277: D/dalvikvm(603): GC_CONCURRENT freed 358K, 17% free 2448K/2928K, paused 74ms+4ms, total 144ms
02-25 11:23:41.287: W/ActivityManager(288): Unable to start service Intent { flg=0x4 cmp=com.example.newsapp/.MainActivity$NotificationService (has extras) } U=0: not found

Any ideas? Thanks in advance.

A small example:

This is working code. It wakes CPU every 10 minutes until the phone turns off.

Add to Manifest.xml:

...
<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
...
<receiver  android:process=":remote" android:name="Alarm"></receiver>
...

Code:

    package YourPackage;
    import android.app.AlarmManager;
    import android.app.PendingIntent;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.os.PowerManager;
    import android.widget.Toast;

    public class Alarm extends BroadcastReceiver 
    {    
         @Override
         public void onReceive(Context context, Intent intent) 
         {   
             PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
             PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
             wl.acquire();

             // Put here YOUR code.
             Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_LONG).show(); // For example

             wl.release();
         }

     public void SetAlarm(Context context)
     {
         AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
         Intent i = new Intent(context, Alarm.class);
         PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
         am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 * 10, pi); // Millisec * Second * Minute
     }

     public void CancelAlarm(Context context)
     {
         Intent intent = new Intent(context, Alarm.class);
         PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
         AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
         alarmManager.cancel(sender);
     }
 }

Set Alarm from Service:

package YourPackage;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;

public class YourService extends Service
{
    Alarm alarm = new Alarm();
    public void onCreate()
    {
        super.onCreate();       
    }

    public void onStart(Context context,Intent intent, int startId)
    {
        alarm.SetAlarm(context);
    }

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

If you want set alarm repeating at phone boot time:

Add permission to Manifest.xml:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>
...
<receiver android:name=".AutoStart">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"></action>
    </intent-filter>
</receiver>
...

And create new class:

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

public class AutoStart extends BroadcastReceiver
{   
    Alarm alarm = new Alarm();
    @Override
    public void onReceive(Context context, Intent intent)
    {   
        if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED"))
        {
            alarm.SetAlarm(context);
        }
    }
}

Also a note: Alarms are wiped off once phone is rebooted, you might have to implement a boot broadcast receiver to make it persistent. Make sure you dont do that runtime, you need to implement it in the Manifest else when your app is not in background you will not receive any broadcasts.

Please take into consideration the fact that at boot time resources are highly contended, so instead of firing the service you should wait some time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM