14 Şubat 2018 Çarşamba

Android Dersleri 25 - AlarmManager

25 - AlarmManager
Bu dersin tamamını içeren pdf'i link'ten indirebilirsiniz :
Android AlarmManager allows you to access system alarm. ( AlarmManager class'ını kullanarak Android'in built-in system alarm'ına erişebilir ve kullanabiliriz. )
By the help of Android AlarmManager in android, you can schedule your application to run at a specific time in the future. It works whether your phone is running or not. ( AlarmManager'ı kullanarak , istediğimiz bir ileri zamanda istediğimiz bir kodu çalıştırabiliriz, uygulamamız ve hatta telefonumuz uykuda veya kapalı olsa bile. )
Example 1
Let's see a simple AlarmManager example that runs after a specific time provided by user. ( Basit bir AlarmManager örneği yaparak konuya giriş yapalım. Kullanıcının belirttiği bir ileri zamanda belirli bir kodu çalıştıran bir örnek yapalım. )
activity_main.xml
main activity layout'da sadece bir editText ve button olsun. EditText alanına kullanıcı alarm'ın kaç saniye sonra tetiklenmesini istiyorsa o saniyeyi girsin.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:id="@+id/activity_main"
   android:layout_width="match_parent"
   android:layout_height="match_parent" >

   <EditText
       android:id="@+id/time"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_alignParentLeft="true"
       android:layout_alignParentTop="true"
       android:layout_marginTop="28dp"
       android:ems="10"
       android:hint="Number of seconds"
       android:inputType="numberDecimal" />

   <Button
       android:id="@+id/button1"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_alignRight="@+id/time"
       android:layout_below="@+id/time"
       android:layout_marginRight="60dp"
       android:layout_marginTop="120dp"
       android:text="Start" />

</RelativeLayout>

MainActivity.java : The activity class starts the alarm service when the user clicks on the button. ( Kullanıcı butona tıkladığında alarm service başlatılır ve girilen saniye sonra broadcast class'ının onReceive() method'u AlarmService tarafından tetiklenir. )
MainActivity class'ı aşağıda görüldüğü kadardır, yani çok basittir.  Layout set edildikten sonra butona click listener register edilir butona tıklayınca startAlert() method'u çağırılacaktır artık.
startAlert() method'u çağırılınca, önce EditText'deki sayı okunur, bu sayı kullanıcının alarm'ın kaç saniye sonra çalışmasını istediğini belirtir:
EditText text = (EditText) findViewById(R.id.time);
int i = Integer.parseInt(text.getText().toString());

Birazdan MyBroadcastReceiver class'ını tanımlayacağız ve bu class'da onIntent() method'unu overide edeceğiz, alarmService tetiklendiğinde MyBroadcastReceiver class'ının onReceive() method'U çağırılacaktır. Bu class'a gidecek bir intent object yaratırız :
Intent intent = new Intent(this, MyBroadcastReceiver.class);

PendingIntent class'ının getBroadcast() method'unu çağırarak bir PendingIntent object yaratırız. Bu örnekte PendingIntent class'ının getBroadcast() method'Unu çağırarak PendingIntent object yarattığımıza dikkat et!! Broadcast class'ımızın onReceive() method'u alarmservice broadcast yapınca çağırılacaktır, yani broadcast'ler ile çalışıyoruz bu yüzden getBroadcast() method'Unu çağırarak PendingIntent object yaratırız. Veya şöyle düşün: önce BroadcastReceiver class'ını extend eden MyBroadcastReceiver class'ını tanımladık, sonra bu class'a gidecek bir intent object yarattık. Veya şöyle düşün. PendingIntent.getX() method'Unun aldığı 3. argument'deki intent object bir BroadcastReceiver'a gideceği için PendingIntent.getBroadcast() method'Unu kullandık.
PendingIntent pendingIntent = PendingIntent.getBroadcast( this.getApplicationContext(), 0, intent, 0 );
PendingIntent.getBroadcast() method'unu inceleyelim :
PendingIntent getBroadcast (Context context,
               int requestCode,
               Intent intent,
               int flags)
Retrieve a PendingIntent that will perform a broadcast, like calling Context.sendBroadcast().
For security reasons, the Intent you supply here should almost always be an explicit intent, that is specify an explicit component to be delivered to through Intent.setClass
context
Context: The Context in which this PendingIntent should perform the broadcast.
requestCode
int: Private request code for the sender
intent
Intent: The Intent to be broadcast.
flags
int: May be FLAG_ONE_SHOTFLAG_NO_CREATEFLAG_CANCEL_CURRENTFLAG_UPDATE_CURRENTFLAG_IMMUTABLE or any of the flags as supported by Intent.fillIn() to control which unspecified parts of the intent that can be supplied when the actual send happens.

AlarmManager object yaratırız :
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

AlarmManager object'in set() method'Unu çağırdığımız için AlarmService sadece bir kez çalışacaktır tekrar çalışmayacaktır.
1.pparametrede real time clock yani sistem saatini kullanmak istediğimizi ve alarm çalacağı zaman telefon uyuyorsa telefonu uyandırmayı istediğimizi söyleriz.
2.parametrede ise ne zaman çalışmasını istediğimizi belirtiriz, şu an ki zamanda i saniye sonra çalışmasını istedik bu örnekte.  
3. parametre olarak da pendingIntent object'i verdik:
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (i * 1000), pendingIntent);

En son, alarm'ı kurduğumuzu söyleyen bir Toast mesajı gösteririz :
Toast.makeText(this, "Alarm set in " + i + " seconds",Toast.LENGTH_LONG).show();

MainActivity class'ının tamamı aşağıda gösterilmiştir :
public class MainActivity extends Activity {
   Button b1;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       b1=(Button) findViewById(R.id.button1);

       b1.setOnClickListener(new OnClickListener() {
           @Override
           public void onClick(View v) {
               // TODO Auto-generated method stub
               startAlert();
           }
       });

   }   public void startAlert() {
       EditText text = (EditText) findViewById(R.id.time);
       int i = Integer.parseInt(text.getText().toString());
       Intent intent = new Intent(this, MyBroadcastReceiver.class);
       PendingIntent pendingIntent = PendingIntent.getBroadcast(
               this.getApplicationContext(), 234324243, intent, 0);
       AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
       alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (i * 1000), pendingIntent);
       Toast.makeText(this, "Alarm set in " + i + " seconds",Toast.LENGTH_LONG).show();
   }
}

MyBroadcastReceiver.java : BroadcastReceiver class'ını extend eden basit bir class tanımlarız bu class'ın onReceive() method'unu override ederiz. AlarmService çalıştığında bu method çağırılacaktır. Yani örneğin alarm'ı 3 dk. sonraya kurdun, alarm 3 dk. sonra çalışınca onReceive() çağırılır dolayısıyla yapmak istediğin işi onReceive() method'u içerisine yaz. Bu örnekte onReceive() method'u çağırılınca br müzik çalacaktır ve toast mesajı gösterilecektir, bu müzik için raw diye bir klasör yarattım ve bu klasöre alrm.mp3 isimli müzik dosyasını koydum:

import android.media.MediaPlayer;

public class MyBroadcastReceiver extends BroadcastReceiver {
   MediaPlayer mp;
   @Override
   public void onReceive(Context context, Intent intent) {
       mp=MediaPlayer.create(context, R.raw.alrm   );
       mp.start();
       Toast.makeText(context, "Alarm....", Toast.LENGTH_LONG).show();
   }
}

AndroidManifest.xml'de BroadcastReceiver'ı tanıtırım :
<receiver android:name="MyBroadcastReceiver" >  
</receiver>  
Output :
android alarmmanager example output 1  android alarmmanager example output 1  android alarmmanager example output 1

There are three static PendingIntent factory methods which can be used to obtain a PendingIntent object : ( PendingIntent class'ının aşağıda gösterilen method'ları çağırılarak PendingIntent object yaratırız: )
   public static PendingIntent getActivity(Context context, int requestCode, Intent intent, int flags)
   public static PendingIntent getBroadcast(Context context, int requestCode, Intent intent, int flags)
   public static PendingIntent getService(Context context, int requestCode, Intent intent, int flags)
These return PendingIntent instances which can be used to ( Bu method'ların return ettiği PendingIntent object şunlar için kullanılabilir : )
- start an activity,
- perform a broadcast, or
- start a service,
respectively.



Scheduling Repeating Alarms
Alarms (based on the AlarmManager class) give you a way to perform time-based operations outside the lifetime of your application. For example, you could use an alarm to initiate a long-running operation, such as starting a service once a day to download a weather forecast. ( Alarm'ları kullanarak örneğin günde bir kez hava durumunu indiren bir service'i başlatabiliri. )

Alarms have these characteristics:
  • They let you fire Intents at set times and/or intervals. ( Alarmlar, belirli bir zamanda, belirli periyodlarla, örneğin saat 21.30'da 10dk aralıklarla intent fire etmeyi sağlarlar. )
  • You can use them in conjunction with broadcast receivers to start services and perform other operations. (Alarmlar'ları broadcast receiver'lar ile birlikte kullanarak service başlatabiliriz ve diğer işlemleri yapabiliriz.  )
  • They operate outside of your application, so you can use them to trigger events or actions even when your app is not running, and even if the device itself is asleep. ( Alarmlar uygulamamızın dışarısında çalışırlar. Dolayısıyla uygulamamız çalışmıyor bile olsa, hatta telefon uykuda bile olsa, alarm'ları kullanarak istediğimiz event'i veya action'ı tetikleyebiliriz. )
  • They help you to minimize your app's resource requirements. You can schedule operations without relying on timers or continuously running background services. ( Alarm'lar, uygulamanızın resource gereksinimlerini minimize etmeye yardım eder. Timer'lara ve arka planda sürekli çalışan service'lere gerek kalmadan sadece alarm'ları kullanarak işlerimizi schedule edebiliriz. )
Note: For timing operations that are guaranteed to occur during the lifetime of your application, instead consider using the Handler class in conjunction with Timer and Thread. This approach gives Android better control over system resources. ( Uygulamanız'ın yaşam döngüsü içerisinde gerçekleşecek işlemler için timing kurmak istiyorsanız, Handler, Timer ve Thread class'larını birlikte kullanmalısınız. Ancak uygulamanızdan bağımsız bir timing mekanizması kurmak istiyorsanız AlarmManager class'ı kullanmalısınız. Doğru kararı vermek system resource'larının daha verimli kullanılmasını sağlar. )
Understand the Trade-offs
A repeating alarm is a relatively simple mechanism with limited flexibility. It may not be the best choice for your app, particularly if you need to trigger network operations. A poorly designed alarm can cause battery drain and put a significant load on servers. ( Tekrar tekrar çalan alarm'ı geliştirmek basittir ama flexibility sınırlıdır. Kötü design edilmiş bir alarm bataryayı hızlı tüketebilir ve server'lara aşırı yük bindirebilir. )
Best practices
Every choice you make in designing your repeating alarm can have consequences in how your app uses (or abuses) system resources. For example, imagine a popular app that syncs with a server. If the sync operation is based on clock time and every instance of the app syncs at 11:00 p.m., the load on the server could result in high latency or even "denial of service." Follow these best practices in using alarms: ( Tekrarlayan bir alarm tasarlarken yaptığımız her seçim, uygulamamızın system kaynaklarını nasıl kullanacağını etkiler. Örneğin, server ile senkronize olan popüler bir uygulamayı mesela facebook'u düşünelim. App'ın tüm instance'ları için Senkronize olma işlemi clock time'a göre 11.00 pm'de olacaksa, server'a aşırı yük binebilir bu da high latency'ye ve denial of service'e sebep olabilir. Alarm geliştirirken aşağıda anlatılan best practice'lere dikkat etmeliyiz. )
  • Add randomness (jitter) to any network requests that trigger as a result of a repeating alarm: ( Tekrarlayan alarmlar sonucunda tetiklenecek network request'lerine biraz randomness(rastgelelik) eklemeliyiz. )
    • Do any local work when the alarm triggers. "Local work" means anything that doesn't hit a server or require the data from the server. ( Alarm tetiklenince herhangi bir local work yapılır. Local work, server'a request göndermek haricindeki herhangi bir şeydir. )
    • At the same time, schedule the alarm that contains the network requests to fire at some random period of time. ( Network request'i tetikleyecek olan alarm'ı rastgele bir periyodda çalışacak şekilde schedule ederiz.  )
  • Keep your alarm frequency to a minimum. ( Alarm frequency'yi minimum yapmalıyız. )
  • Don't wake up the device unnecessarily (this behavior is determined by the alarm type, as described in Choose an alarm type). ( Device'ı gereksiz yere uyandırmayın. Device'ı uyandırıp uyandırmamayı alarm type'ı belirler.)
  • Don't make your alarm's trigger time any more precise than it has to be. (Alarm'ınızın tetikleneceği zamanı olması gerektiğinden daha kesin yapmayın, alarm'ınızın tetikleneceği zaman konusunda biraz flexible olun.)
Use setInexactRepeating() instead of setRepeating(). When you use setInexactRepeating(), Android synchronizes repeating alarms from multiple apps and fires them at the same time. This reduces the total number of times the system must wake the device, thus reducing drain on the battery. As of Android 4.4 (API Level 19), all repeating alarms are inexact. Note that while setInexactRepeating() is an improvement over setRepeating(), it can still overwhelm a server if every instance of an app hits the server around the same time. Therefore, for network requests, add some randomness to your alarms, as discussed above. ( setRepeating() method'unu değil setInexactRepeating() method'unu kullanın. setInexactRepeating() method'unu kullandığımızda, android birden fazla uygulamadan repeating alarm'ları aynı anda senkronize eder ve aynı anda alarm'ları fire eder. Bu da device'ı daha az defa uyandırmamızı sağlar, dolayısıyla bataryayı daha az tüketmiş oluruz. Android 4.4 'den itibaren, tüm repeating alarm'lar inaxact'dır. setInexactRepeating() method'u, setRepeating() method'unun geliştirilmiş hali olmasına rağmen bir uygulamanın tüm instance'ları aynı anda server'a  request gönderirse setInexactRepeating() method'u da server'ı yorabilir. Dolayısıyla network request'ler için, alarm'larınıza randomness eklemelisiniz yukarıda anlatıldığı gibi. )
  • Avoid basing your alarm on clock time if possible. ( Mümkünse alarm'ınızı clock time göre ayarlamayın. )
Repeating alarms that are based on a precise trigger time don't scale well. Use ELAPSED_REALTIME if you can. The different alarm types are described in more detail in the following section. ( Duvar saatine göre kesin bir zamana mesela pazartesi 08.09'da çalması beklenen repeating alarm'lar iyi ölçeklendirilemezler(ölçeklendirmek nedir anlamadım. Yani düzgün çalışmayabilir falan demek istemiş olabilir.) Mümkünse ELAPSED_REALTIME alarm çeşidini kullanmalısınız. )
Set a Repeating Alarm

As described above, repeating alarms are a good choice for scheduling regular events or data lookups. A repeating alarm has the following characteristics: ( Regular event'ler için tekrarlanan alarm'lar kurmak iyi bir seçimdir. Bir tekrarlanan alarm'lar şu 4 şeye sahiptir: )
  • A alarm type. For more discussion, see Choose an alarm type. ( Alarm çeşidi. RTC(Real Time Clock) mu Elapsed Real Time mı. Wake Up mı değil mi vs. Alarm çeşitlerini birazdan öğreneceğiz. )
  • A trigger time. If the trigger time you specify is in the past, the alarm triggers immediately. ( Alarm'ın tetikleneceği zaman örneğin çarşamba 21.00. Trigger time geçimişteki bir zaman ise, alarm'ı kurunca alarm anında tetiklenir. )
  • The alarm's interval. For example, once a day, every hour, every 5 seconds, and so on. ( Alarm'ın hangi periyodla tetikleneceği. Örneğin, günde bir, saatte bir veya 5 saniyede bir. )
  • A pending intent that fires when the alarm is triggered. When you set a second alarm that uses the same pending intent, it replaces the original alarm. ( Alarm tetiklenince, bir pending intent fire edilir(fırlatılır). Eğer aynı pending intent'i kullanarak başka bir alarm kurarsak bu alarm önceki alarm'ın yerine geçer. )
Choose an alarm type
One of the first considerations in using a repeating alarm is what its type should be. ( Bir repeating alarm seçerken dikkate almamız gereken en önemli konu alarm'ın type'ıdır. )
There are two general clock types for alarms: "elapsed real time" and "real time clock" (RTC). Elapsed real time uses the "time since system boot" as a reference, and real time clock uses UTC (wall clock) time. This means that elapsed real time is suited to setting an alarm based on the passage of time (for example, an alarm that fires every 30 seconds) since it isn't affected by time zone/locale. The real time clock type is better suited for alarms that are dependent on current locale. ( 2 genel saat çeşidi vardır:
- elapsed real time,
- real time clock (RTC)
Elapsed real time : Telefon açıldıktan sonra geçen zamanı referans alır. Belli bir sürenin geçmesi ile tetiklenecek bir alarm kurmak için uygundur, örneğin 30 sn.'de bir tetiklenecek bir alarm kurmak için uygundur çünkü zaman ülke konumundan etkilenmez.
RTC : UTC'yi yani wall clock time'ı yani gerçek duvar saati zamanına dayanır. Bulunulan ülkenin saatine bağımlı olan alarm'lar için uygundur. )
Both types have a "wakeup" version, which says to wake up the device's CPU if the screen is off. This ensures that the alarm will fire at the scheduled time. This is useful if your app has a time dependency—for example, if it has a limited window to perform a particular operation. If you don't use the wakeup version of your alarm type, then all the repeating alarms will fire when your device is next awake. ( Her iki alarm çeşidinin de wakeup versiyonu vardır. Wake up versiyonu, eğer ekran kapalıysa CPU'yu uyandırmayı sağlar. Bu da alarm'ın belirlenen sürede tetikleneceğini garantiler. Eğer wake versiyonu olmayan bir alarm type'ı kullanırsanız, tüm tekrarlanan alarmlar telefonunuzun ekranı açıkken çalışacaktır. )
If you simply need your alarm to fire at a particular interval (for example, every half hour), use one of the elapsed real time types. In general, this is the better choice. ( Eğer alarm'ınızın belirli aralıklarla fire olmasını istiyorsanız, örneğin alarm'ınızın yarım saatte bir fire olmasını istiyorsanız, elapsed real time type'ında bir alarm kullanın. Genellikle en iyi seçim budur. )
If you need your alarm to fire at a particular time of day, then choose one of the clock-based real time clock types. Note, however, that this approach can have some drawbacks—the app may not translate well to other locales, and if the user changes the device's time setting, it could cause unexpected behavior in your app. Using a real time clock alarm type also does not scale well, as discussed above. We recommend that you use a "elapsed real time" alarm if you can. ( Alarm'ınızın günün belirli bir zamanında çalmasını istiyorsanız, clock-based real time clock type'ında bir alarm kullanmalısınız. Ancak bu yaklaşımın bazı dezavantajları vardır: uygulama farklı bir yerel saate düzgün çevrilemez, kullanıcı saat ayarlarını değiştirirse uygulamada beklenmedik davranışlar görülebilir. RTC alarm çeşidini kullanmak  iyi ölçeklendirilemez esnek değildir yukarıda anlatıldığı gibi. Mümkünse elapsed real time kullanmanız tavsiye edilir. )
Here is the list of types: ( Alarm type'ları şunlardır: )
  • ELAPSED_REALTIME—Fires the pending intent based on the amount of time since the device was booted, but doesn't wake up the device. The elapsed time includes any time during which the device was asleep. (Telefonun boot edilmesinden sonra geçen zamanı referans alır. Ancak bu alarm çeşidi cihazı uyandırmaz. )
  • ELAPSED_REALTIME_WAKEUP—Wakes up the device and fires the pending intent after the specified length of time has elapsed since device boot. ( Telefonun boot edilmesinden sonra geçen zamanı referans alır. Bu alarm çeşidi cihazı uyandırır. )
  • RTC—Fires the pending intent at the specified time but does not wake up the device. ( Belirli bir zamanda pending intent'i fırlatır. Ancak bu alarm çeşidi cihazı uyandırmaz. )
  • RTC_WAKEUP—Wakes up the device to fire the pending intent at the specified time. ( Belirli bir zamanda pending intent'i fırlatır. Bu alarm çeşidi cihazı uyandırır. )
ELAPSED_REALTIME_WAKEUP examples

Here are some examples of using ELAPSED_REALTIME_WAKEUP. (Telefonun boot edilmesinden sonra geçen zamanı referans alarak çalışan ve cihazı uyandıran bir alarm çeşidi olan ELAPSED_REALTIME_WAKEUP 'ı kullanarak bir örnek yapalım. )
Bu kodları Samsung Note 4(Android 6.0) telefonumda çalıştırınca sorun yoktu ancak HTC One S telefonumda çalıştırınca Calendar class'ıyla ilgili şöyle bir hata aldım :
- no class def found android.icu.util.Calendar
Çözüm : Instead of importing android.icu.util.calendar, try importing java.util.Calendar. The android.icu.util.calendar is the ICU replacement for java.util.Calendar but it's only available starting from API 24. So, it will only work on the devices which is API 24 and above. (android.icu.util.calendar API 24 ve üzeri cihazlarda çalışır, daha düşük API'lar için java.util.Calendar'ı kullanmalısınız diyor.  )

Wake up the device to fire the alarm in 30 minutes, and every 30 minutes after that: ( Alarm'ı kurduktan 30 dk. sonra ve bundan sonra da her 30 dk.'da bir pending intent fire edilir. )
30 dk'da bir PendingIntent fire etmek istediğimiz için, AlarmManager object'in setInexactRepeating() method'unu çağırırız.
Alarm type'ını bu method'a vereceğimiz 1. argument belirler, bu örnekte bu method'a 1. argument olarak AlarmManager.ELAPSED_REALTIME_WAKEUP verdik.
Bu method'Un aldığı 2.argument PendingIntent'in fire edileceği zamanı belirler :  SystemClock.elapsedRealtime() + 0.5 saat   diyerek alarm kurulduktan yarım saat sonra PendingIntent'in fire edilmesini set ederiz.
Bu method'un aldığı 3. argument, PendingIntent'in yarım saat aralıklarla fire edilmesini söyler.
Bu method'un aldığı 4. argument, fırlatılacak olan AlarmIntent object'dir.
Bu alarm kurulduğundan itibaren yarım saatte bir cihazı uyandırır ve PendingIntent fırlatır.
// Hopefully your alarm will have a lower frequency than this!
alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR,
        AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);

Wake up the device to fire a one-time (non-repeating) alarm in one minute: ( Kurulduktan 1 dk. sonra cihazı uyandırıp PendingIntent fırlatacak bir alarm tanımlayalım.
Bu alarm'In sadece 1 kez tetiklenmesini istediğimiz için yani tekrarlayan bir alarm olmadığı için AlarmManager object'in set() method'Unu çağırırız.
Alarm type'ını set() method'una vereceğimiz 1. argument belirler, bu örnekte bu method'a 1. argument olarak AlarmManager.ELAPSED_REALTIME_WAKEUP verdik.
Bu method'Un aldığı 2.argument PendingIntent'in fire edileceği zamanı belirler :  SystemClock.elapsedRealtime() + 60 * 1000 ms   diyerek alarm kurulduktan 60 saniye yani 1 dk sonra PendingIntent'in fire edilmesini belirtiriz.
Alarm tekrarlamayacağı için, alarm periyodunu belirten bir parametre almaz set() method'u.
set() method'unun aldığı 3. argument, fırlatılacak olan PendingIntent object'dir.
Bu alarm kurulduktan 1 dk sonra cihazı uyandırır ve PendingIntent fırlatır: )
private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
...
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);

alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() +
        60 * 1000, alarmIntent);

RTC examples
Here are some examples of using RTC_WAKEUP. ( Telefonun gerçek saatini referans alarak çalışan ve cihazı uyandıran bir alarm çeşidi olan RTC'yi kullanarak örnekler yapalım. )
Wake up the device to fire the alarm at approximately 2:00 p.m., and repeat once a day at the same time: ( Tam olarak saat 2.00 pm'de cihazı uyandırıp intent fırlatacak ve bunu her gün yapacak bir alarm kuralım :   )
Calendar class'Inın getInstance() method'unu çağırarak bir Calendar object yaratırız. Bu object'in setter method'larını kullanarak alarm'ın tam olarak çalmasını istediğimiz günü,saati,dakikayı, saniyeyi set edeceğiz.  Bu örnekte takvim'de saati 14 olarak set ediyoruz alarm'ın saat 14'de tetiklenmesini istediğimiz için.
Her gün bu PendingIntent'i fire etmek istediğimiz için, AlarmManager object'in setInexactRepeating() method'unu çağırırız.
Alarm type'ını bu method'a vereceğimiz 1. argument belirler, bu örnekte bu method'a 1. argument olarak AlarmManager.RTC_WAKEUP verdik.
Bu method'Un aldığı 2.argument PendingIntent'in fire edileceği zamanı belirler :  calendar.getTimeInMillis() diyerek PendingIntent'in saat tam 14.00'da fire edilmesini söyleriz.
Bu method'un aldığı 3. argument olan AlarmManager.INTERVAL_DAY PendingIntent'in 1 günlük periyotlarla yani her gün saat 14'de fire edilmesini söyler.
Bu method'un aldığı 4. argument, fırlatılacak olan AlarmIntent object'dir.
Bu alarm kurulduğundan itibaren her gün saat 14'de PendingIntent fire eder.

// Set the alarm to start at approximately 2:00 p.m.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 14);

// With setInexactRepeating(), you have to use one of the AlarmManager interval
// constants--in this case, AlarmManager.INTERVAL_DAY.
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),  AlarmManager.INTERVAL_DAY,  alarmIntent);

Wake up the device to fire the alarm at precisely 8:30 a.m., and every 20 minutes thereafter: ( Aşağıdaki örnekte, saat tam 8.30 am'de ve bundan sonraki her 20 dk.'da bir, device uyandırılır ve alarm fire edilir. )
Aşağıda önce bir AlarmManager object yaratılır. Sonra AlarmReceiver isimli BroadcastReceiver class'ına gidecek bir intent object yaratılır, sonra PendingIntent class'ının getBroadcast() method'una bu intent object verilerek PendingIntent object elde edilir.
Sonra bir Calendar object yaratılr, sonra calendar object'in setTimeInMillis(System.currentTimeMillis()) method'u çağırılarak takvimin zamanı current time olarak set edilir, sonra bu object'İn setter method'ları çağırılarak saat 8.30'da bir olay set edilir.
En son AlarmManager object'in setRepeating() method'u çağırılır.
private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
...
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);

// Set the alarm to start at 8:30 a.m.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 8);
calendar.set(Calendar.MINUTE, 30);

// setRepeating() lets you specify a precise custom interval--in this case,
// 20 minutes.
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
        1000 * 60 * 20, alarmIntent);

Projemde setExact() method'u kullandığımda şu hatayı aldım :
java.lang.NoSuchMethodError: android.app.AlarmManager.setExact
Çözüm : Basically, .setExact(...); method requires API 19 & above (it's just a way to bypass the optimization android provides, for maximizing battery life). ( setExact method'u API 19 ve üzerinde çalışır, bu method batarya ömrünü arttırmaya yarayan optimizasyonlar yapar. API 19 ve üzerinde bu method'Un çalışmasını, API 19 altı için ise set() method'Unun çalışmasını aşağıdaki gibi sağlarız : )
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
  // only for kitkat and newer versions
  android.app.AlarmManager.setExact(int type, long triggerAtMillis, PendingIntent operation);
} else {
  android.app.AlarmManager.set(int type, long triggerAtMillis, PendingIntent operation);
}

Decide how precise your alarm needs to be
As described above, choosing the alarm type is often the first step in creating an alarm. A further distinction is how precise you need your alarm to be. For most apps, setInexactRepeating() is the right choice. When you use this method, Android synchronizes multiple inexact repeating alarms and fires them at the same time. This reduces the drain on the battery. ( Yukarıda anlatıldığı gibi, bir alarm yaratırken karar verilmesi gerekn ilk şey alarm type'dır. 2. olarak karar vermemiz gereken şey ise, alarm'ımızın ne kadar dakik(kesin) olacağına karar vermektir. Çoğu uygulama için, setInexactRepeating() method'unu kullanmak en doğru seçimdir. Bu method'u kullanırsak, Android birden fazla inexact repeating alarm'ı senkronize eder ve bu alarm'ları aynı anda fire eder. Bu da batarya kullanımını azaltır.  )
For the rare app that has rigid time requirements—for example, the alarm needs to fire precisely at 8:30 a.m., and every hour on the hour thereafter—use setRepeating(). But you should avoid using exact alarms if possible. ( Katı zaman requeirement'ları olan bir uygulama var dyelim, örneğin alarm tam olarak 8.30'da fire olacak ve bundan sonra tamı tamına 1 saat aralıklarla fire olacak diyelim. Böyle bir uygulama yapmak istiyorsak  setRepeating() method'unu kullanmalıyız. Ancak mümkünse exact alarm'lar kullanmaktan kaçınmalıyız. )
With setInexactRepeating(), you can't specify a custom interval the way you can with setRepeating(). You have to use one of the interval constants, such as INTERVAL_FIFTEEN_MINUTESINTERVAL_DAY, and so on. See AlarmManager for the complete list. ( setInexactRepeating() method'unda custom interval(aralık,periyot) seçemeyiz, şu constant interval'lerden birisini kullanabiliriz sadece : INTERVAL_FIFTEEN_MINUTES , INTERVAL_DAY , vs.
setRepeating() method'unda ise custom interval seçebiliriz.  )
Cancel an Alarm


Depending on your app, you may want to include the ability to cancel the alarm. To cancel an alarm, call cancel() on the Alarm Manager, passing in the PendingIntent you no longer want to fire. For example: ( Kurmuş olduğunuz bir alarm'ı cancel etmek için, AlarmManager object'in cancel(pendingIntent) method'unu çağırırız. cancel() method'una argument olarak pendingIntent object veririz. )
// If the alarm has been set, cancel it.
if (alarmMgr!= null) {
    alarmMgr.cancel(alarmIntent);
}
Start an Alarm When the Device Boots

By default, all alarms are canceled when a device shuts down. To prevent this from happening, you can design your application to automatically restart a repeating alarm if the user reboots the device. This ensures that the AlarmManager will continue doing its task without the user needing to manually restart the alarm. ( Default olarak, device kapatıldığında tüm alarm'lar iptal edilir. Bunun olmasını önlemek için, uygulamamızı öyle geliştirmeliyiz ki, cihaz reboot olduğunda uygulamamızdaki repeating alarm otomatik olarak restart olsun. Bu sayede kullanıcının alarm'ı tekrar kurmasına gerek kalmayacaktır. Bunun için aşağıdaki adımları uygularız : )

Here are the steps:
  1. Set the RECEIVE_BOOT_COMPLETED permission in your application's manifest. This allows your app to receive the ACTION_BOOT_COMPLETED that is broadcast after the system finishes booting (this only works if the app has already been launched by the user at least once):  ( AndroidManifest.xml dosyasında RECEIVE_BOOT_COMPLETED permission'ını(izni) alırız. Bu izin şunu sağlar : cihaz boot olunca uygulamamıza ACTION_BOOT_COMPLETED broadcast'i gönderir. Bunun çalışması için uygulamamızın en az bir kere launch edilmesi böylece uygulamamızın bu izni alması gereklidir:  )
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  1. Implement a BroadcastReceiver to receive the broadcast:  (  Broadcast gelince çalışacak bir BroadcastReceiver class'ı tanımlarız. Broadcast gelince bu class'ın onReceive() method'u çağırılır, bu method'da gelen broadcast action'ı BOOT_COMPLETED mıdır diye check ederiz, öyleyse cihaz yeni boot edilmiştir alarm'ı burada set ederiz. )
public class SampleBootReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
            // Set the alarm here.
        }
    }
}
  1. Add the receiver to your app's manifest file with an intent filter that filters on the ACTION_BOOT_COMPLETED action: ( AndroidManifest.xml dosyasında tanımladığımız BroadcastReceiver class'ını tanıtırız ayrıca hangi action gelince bu class'ın çalışacağını da belirtiriz. Bu örnekte BOOT_COMPLETED action broadcast edilince SampleBootReceiver class'ının onReceive() method'u çağırılacaktır: )
<receiver android:name=".SampleBootReceiver"
        android:enabled="false">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"></action>
    </intent-filter>
</receiver>

Notice that in the manifest, the boot receiver is set to android:enabled="false". This means that the receiver will not be called unless the application explicitly enables it. This prevents the boot receiver from being called unnecessarily. You can enable a receiver (for example, if the user sets an alarm) as follows:  ( Yukarıda AndroidManifest.xml dosyasında SampleBootReceiver'ı tanıtırken kullandığımız receiver element'in android:enabled attribute'Ünü false olarak set ettik. Yani uygulamada bu attribute explicity enable edilmezse, bu BroadcastReceiver class'ı pasif kalacaktır, cihaz boot edildiğinde fırlatılan action'ı yakalamayacaktır. Bu sayede boot receiver class'ımızın gereksiz yere çağırılmasını önleriz. Bu receiver'ı kullanıcı bir alarm kurduğu zaman aşağıdaki gibi set ederiz : )
ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
PackageManager pm = context.getPackageManager();

pm.setComponentEnabledSetting(receiver,
        PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
        PackageManager.DONT_KILL_APP);
Once you enable the receiver this way, it will stay enabled, even if the user reboots the device. In other words, programmatically enabling the receiver overrides the manifest setting, even across reboots. The receiver will stay enabled until your app disables it. ( Receiver'ı yukarıdaki şekilde enable ettikten sonra, artık cihaz kapatılsa bile bu receiver hep aktif(enabled) olarak kalacaktır. Diğer bir deyişle receiver'ı yukarıdaki gibi enable ederek manifest ayarlarını override etmiş oluruz, reboot olsa bile bu ayar değişmez.  )

You can disable a receiver (for example, if the user cancels an alarm) as follows: ( Kullanıcı alarm'ı iptal ederse, ilgili receiver'ı aşağıdaki gibi disable edebiliriz : )
ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
PackageManager pm = context.getPackageManager();

pm.setComponentEnabledSetting(receiver,
        PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
        PackageManager.DONT_KILL_APP);


For more reference :
Output :

http://code4reference.com/2012/07/tutorial-on-android-alarmmanager/


Hiç yorum yok:

Yorum Gönder