13 Şubat 2018 Salı

Android Dersleri 15 - BroadcastReceiver


15 - BroadcastReceiver

http://www.cs.dartmouth.edu/~campbell/cs65/lecture19/lecture19.html
broadcast receiver (receiver) is an Android component which allows you to register for system or application events. All registered receivers for an event are notified by the Android runtime once this event happens. ( BroadcastReceiver object, belirli bir event'i dinler, bu event gerçekleşince buna tepki verir. BroadcastReceiver object'in dinlediği event, diğer uygulamalar veya sistem tarafından gerçekleştirilecek bir event olabilir. Bu event gerçekleşince, bu event'i dinleyen tüm BroadcastReceiver object'ler bundan haberdar olup buna bir tepki verirler.  )
For example, applications can register for the ACTION_BOOT_COMPLETED system event which is fired once the Android system has completed the boot process. ( Örneğin, ACTION_BOOT_COMPLETED bir system event'idir ve Android system'i başlatıldığında yani telefon açıldığında fırlatılır(gerçekleşir, fire edilir). gerçekleşir, fire edilir.  ACTION_BOOT_COMPLETED   system event'ini dinleyen bir broadcastreceiver object tanımlayabiliriz, bu event gerçekleşince bu event'i dinleyen broadcastreceiver object'imiz  bizim tanımladığımız bir tepki verir(belirli bir kod block'u çalıştırır).   )

BroadcastReceiver is the base class for components that receive(listen) and react to events. ( Bir broadcastreceiver object bir event'i dinler, bu event gerçekleşince tepki verir. )
- Events are represented as Intents. ( Event, bir intent object'dir. Event, intent, broadcast eş anlamlıdır. BroadcastReceiver ve receiver da eş anlamlıdır. )
- Event are broadcasted system-wide. ( Bir event gerçekleşince bundan bu event'i dinleyen tüm uygulamaların BroadcastReceiver'ları haberdar olabilir. Yani sen sınıfın içinde bağırıyorsun zil çaldıııı diyorsun ve bunu sınıftaki herkes duyuyor ve herkes mola moduna geçiyor, kimisi dışarı çıkıyor kimisi yemeğini yiyor vs. )
- Interested BroadcastReceivers receive Intent via onReceive(). (BroadcastReceivers object'ler, intent'i onReceive() method'u ile alırlar. )

        BroadcastReceivers have no user interface. (BroadcastReceiver'ların UI'ı yoktur.)

        BroadcastReceivers get registered to receive specific intents. (BroadcastReceiver object tüm event'leri değil sadece bizim belirledğimiz event'leri dinler. Örneğin, ACTION_BOOT_COMPLETED system event'ini dinle deriz. Ama ACTION_BOOT_COMPLETED system event'ini dinlemesini söylemezsek dinlemez. )
        We can register a BroadcastReceiver object to an event(intent) in two ways:( BroadcastReceiver object'in, bir event'i dinlemesini 2 yolla sağlayabiliriz. )
1 -Statically in AndroidManifest.xml
2 - Dynamically with Context.registerReceiver()

        BroadcastReceiver is the base class for code that will receive intents sent by sendBroadcast(). ( sendBroadcast() method'u ile bir intent gönderilir, yani bir event gerçekleşir. Bu event gerçekleşince, bunu dinleyen broadcastReceiver object'in onReceive() method'u invoke edilir. )

        If you don't need to send broadcasts across applications, consider using this class with LocalBroadcastManager instead of the more general facilities described below. This will give you a much more efficient implementation (no cross-process communication needed) and allow you to avoid thinking about any security issues related to other applications being able to receive or send your broadcasts. ( Eğer sadece system event'lerini dinleyecek bir broadcastreceiver object'e ihtiyacımız varsa, LocalBroadcastManager object'i kullanabiliriz. LocalBroadcastManager object bu iş için daha verimlidir ve daha güvenlidir. )
        You can either dynamically register an instance of this class with Context.registerReceiver() or statically publish an implementation through the<receiver> tag in your AndroidManifest.xml. (BroadcastReceiver object'inin bir event'i dinlemesini 2 farklı yolla sağlayabiliriz : 1 - Static olarak. AndroidManiferst.xml dosyasında <receiver> tag'ını kullanarak.     2 - Dinamik olarak. Bunun için Context.registerReceiver() method'u kullanılır.   )

         Note:    If registering a receiver in your Activity.onResume()  implementation, you should unregister it in Activity.onPause(). (You won't receive intents when paused, and this will cut down on unnecessary system overhead). Do not unregister in Activity.onSaveInstanceState(), because this won't be called if the user moves back in the history stack. ( Activity'mizin onResume() method'unun implementation'ında bir receiver object'in bir event'i dinlemesini dinamik olarak sağladıysak, activity'mizin onPause() method'unda receiver object'in bu event'i artık dinlememesini söylemeliyiz. Bu sayede şunu sağlamış oluruz, pause state'e geçildiğinde intent almayacağız(yani event'i dinlemeyeceğiz), dolayısıyla gereksiz işyükünden kurtulmuş olacağız. Event'i unregister etme işini activity'nin onSaveInstanceState() method'unda yapmak yanlıştır, çünkü kullanıcı geri tuşuna basarak backstack'deki activity'lere geçebilir.  )
public class A extends Activity
{
        onResume()
        {
                Context.registerReceiver() çağırarak
                BroadcastReceiver object'in, A event'ini dinlemesini
                dinamik olarak sağladık.             
        }
        onPause()
        {
                BroadcastReceiver object, A event'ini dinlemesin.
        }
}

       The implementing class for a receiver extends the BroadcastReceiver class.If the event for which the broadcast receiver has registered happens, the onReceive() method of the receiver is called by the Android system. ( Kendi BroadcastReceiver class'ımızı yazmak istiyorsak, BroadcastReceiver class'ını extend eden bir class yazarız. BroadcastReceiver object'in register edildiği event gerçekleşirse, BroadcastReceiver object'in onReceive() method'u çağırılır otomatik olarak. )

Creating a Custom Broadcast Receiver Class

      A broadcast receiver is implemented as a subclass of BroadcastReceiver class and overriding the onReceive() method where each message is received as a Intent object parameter. (Aşağıda MyReceiver isimli bir custom BroadcastReceiver implement ettik. MyReceiver class'ında onReceiver() methoD'Unu da implement etmek zorundayız.)
public class MyReceiver extends BroadcastReceiver {
   @Override
   public void onReceive(Context context, Intent intent) {
      Toast.makeText(context, "Intent Detected.", Toast.LENGTH_LONG).show();
   }
}


There are two major types of broadcasts that can be received: ( 2 çeşit broadcast vardır. )
·         Normal broadcasts (sent with Context.sendBroadcast) are completely asynchronous. All receivers of the broadcast are run in an undefined order, often at the same time. This is more efficient, but means that receivers cannot use the result or abort APIs included here. These receivers cannot return results or abort their broadcast. (Context.sendBroadcast() method'uyla gönderilen broadcast'ler normal broadcast'dir. Broadcast'in, broadcastreceiver'lara gönderilmesi asenkron bir şekilde olur, belirli bir sıra yoktur, genellikle yaklaşık olarak aynı anda gönderilir. Broadcast'i bir receiver'a gönderme işleminin tamamlanmasını beklemeye gerek yoktur, başka bir receiver'a daha broadcast gönderilebilir. Normal broadcast, en verimli broadcast çeşididir. Dezavantajı ise şudur, bir receiver'a broadcast göndermek için diğer bir receiver'a broadcast gönderilmesini beklemeye gerek olmadığı için, broadcast'i alan receiver'ın return ettiği result'ı kullanamayız. Normal broadcast alan receiver'lar sonucu return etmezler ve broadcast işlemini durduramazlar.)
·         Ordered broadcasts (sent with Context.sendOrderedBroadcast) are delivered to one receiver at a time. sendOrderedBroadcast() method belongs to the Context class of Android. This is the type of broadcast which is sent in a synchronous manner i.e. one by one to each listener.  As each receiver executes in turn, it can propagate a result to the next receiver, or it can completely abort the broadcast so that it won't be passed to other receivers. The order receivers run in can be controlled with the android:priority attribute of the matching intent-filter; receivers with the same priority will be run in an arbitrary order.  ( Context. sendOrderedBroadcast() method'uyla gönderilen broadcast'ler Ordered Broadcast'dir. sendOrderedBroadcast(), Context class'ının bir method'udur. Broadcast, receiver'lara aynı anda gönderilmez, sırayla gönderilir, broadcast'in bir receiver'a gönderilme işlemi başarılı bir şekilde tamamlanmadan bir sonraki receiver'a broadcast gönderilemez. Normal broadcast'lere göre şu 2 avantajı vardır:
  - Bir broadcast, receiver'lara sırayla gönderilir. Receiver'lardan birinin broadcast'i aldıktan sonra return ettiği bir result'ı(onReceiver() method'unun return ettiği değeri) başka bir receiver kullanabilir.
  - Broadcast, receiver'lara sırayla gönderildiği için, receiver'lardan birisi broadcast işlemini durdurabilir(abort edebilir), artık bu broadcast ölmüştür sonraki receiver'lara gönderilmeyecektir.
Broadcast'in receiver'lara gönderilme sırasını android:priority attribute'ünü set ederek ayarlayabiliriz. Priority'si aynı olan receiver'lar, broadcast'i rastgele bir sırayla alırlar.  )
In other words, The purpose of this method is to broadcast to listening receivers in a serialized manner and receive the result back to the calling activity. Another key advantage of sendOrderedBroadcast is that we can set the priority of BroadcastReceiver. This way all the BroadcastReceivers listening to that specific broadcast will receive that specific broadcast in an ordered manner. Now since we are receiving broadcasts in an ordered way, there might exist a case, when you wish to interrupt the flow of receivers, you can do it with abortBroadcast().
Sticky broadcasts:- A Sticky Broadcast is a Broadcast that stays around following the moment it is announced to the system. Most Broadcasts are sent, processed within the system and become quickly inaccessible. However, Sticky Broadcasts announce information that remains accessible beyond the point at which they are processed. A typical example is the battery level Broadcast. Unlike most Broadcasts, the battery level can be retrieved within applications beyond the point at which it was sent through the system.This means that apps can find out whatever the last battery level broadcast was. ( Bir sticky broadcast, bir receiver'a gönderildiği andan sonra da erişilebilir kalır. Normal broadcast ve ordered broadcast'ler receiver'a geldikleri anda erişilebilirdir, bu andan sonra ise bu broadcast'lere erişilemez. Örneğin, batarya seviyesi broadcast'ini düşünelim. Çoğu broadcast'in aksine, batarya seviyesi bradcast'i receiver'lara gönderildikten sonra da erişilebilirdir. )
       Here's an abstract example of how one might use a sticky broadcast: ( Aşağıdaki örnekte bir intent(event,broadcast) yaratılmıştır. Sonra bu broadcast sendStickyBroadcast() method'u çağırılarak gönderilmiştir.  Dolayısıyla gönderilen broadcast, bir sticky broadcast'dir.  )
Intent intent = new Intent("some.custom.action");
intent.putExtra("some_boolean", true);
sendStickyBroadcast(intent);
       If you are listening for this broadcast in an Activity that was frozen (onPause), you could miss the actual event. This allows you to check the broadcast after it was fired (onResume). ( Eğer bir activity'nin onPause() method'unda bu broadcast'i dinliyorsanız, broadcast geldiğinde bu broadcast'i elinizden kaçırdınız demektir. Ancak bu broadcast sticky broadcast olduğu için, bu broadcast'e activity resume moduna geçtiğinde erişmek mümkündür.  )
-*-*-*-

Note that, although the Intent class is used for sending and receiving these broadcasts, the Intent broadcast mechanism here is completely separate from Intents that are used to start Activities with Context.startActivity(). There is no way for a BroadcastReceiver to see or capture Intents used with startActivity(); likewise, when you broadcast an Intent, you will never find or start an Activity. These two operations are semantically very different: starting an Activity with an Intent is a foreground operation that modifies what the user is currently interacting with; broadcasting an Intent is a background operation that the user is not normally aware of. ( Context.startActivity() ve sendBroadcast() method'ları parametre olarak Intent object alırlar. Ancak bu 2 mekanizma tamamen farklıdır. Context.startActivity(intent) method'u çağırıldığında intent object yeni bir activity başlatmak için kullanılır, kullanıcının gördüğü UI değişir, bu method'un broadcast mekanizmasıyla alakası yoktur. sendBroadcast(intent) method'u çağırıldığında ise intent object BroadcastReceiver'lara broadcast(intent) göndermek için kullanılır, bu kullanıcının çoğunlukla farkında olmadığı bir background operation'dır, activity başlatmak ile alakası yoktur. Bu iki fonksiyonun mantığı tamamen farklıdır.   )
Security
        Broadcasts are meant to be used across applications. This makes them open to abuse.
       Receivers used with the Context APIs are by their nature a cross-application facility, so you must consider how other applications may be able to abuse your use of them. (BroadcastReceiver uygulamalar arasında haberleşmeyi sağladığı için, uygulamanızın bu mekanizmayı nasıl kullandığına dikkat etmelisiniz, diğer uygulamaların bunu kötüye kullanmamaları için dikkatli olmalısınız. ) Some things to consider are:
·        The Intent namespace is global. Make sure that Intent action names and other strings are written in a namespace you own, or else you may inadvertently conflict with other applications.
( Intent namespace, global'dir. Dolayisiyla unique bir intent ismi kullanmalısınız. )
·        When you use registerReceiver(BroadcastReceiver, IntentFilter), any application may send broadcasts to that registered receiver. You can control who can send broadcasts to it through permissions described below.
( registerReceiver() method'Unu çağırarak bir BroadcastReceiver'ın bir event'i dinlemesini sağlarız. Artık herhangi bir uygulama bu event'i fire ederek bizim BroadcastReceiver'ımıza broadcast(intent) gönderebilir. Dolayısıyla tanımladığımız BroadcastReceiver'a kimlerin broadcast(intent) gönderebileceğini kontrol altına almalıyız. Peki nasıl ? Permission'ları kullanarak. )
·        When you publish a receiver in your application's manifest and specify intent-filters for it, any other application can send broadcasts to it regardless of the filters you specify.
To prevent others from sending to it, make it unavailable to them with android:exported="false".
( Statik olarak bir BroadcastReceiver'ın bir event'i dinlemesini sağlarsak, yani manifest.xml dosyasında receiver ve intent-filters element'lerini kullanarak bir BroadcastReceiver'ın bir event'i dinlemesini sağlarsak, hangi intent-filter'ları kullanırsak kullanalım fark etmez tüm uygulamalar bize broadcast gönderebilir. Bunu engellemek için android:exported="false" demeliyiz ki tüm uygulamaların bize broadcast gönderebilme açığını kapatalım ve sadece intent-filter ile specify edilen uygulamalar bize broadcast gönderebilsin.   )
·        When you use sendBroadcast(Intent) or related methods, normally any other application can receive these broadcasts. You can control who can receive such broadcasts through permissions described below.
Alternatively, starting with ICE_CREAM_SANDWICH, you can also safely restrict the broadcast to a single application with Intent.setPackage
(sendBroadcast(Intent) method'unu çağırdığımızda, bu event'i dinleyen tüm uygulamalar bu broadcast'i alabilir. Bunu kontrol etmek mümkündür, gönderilen broadcast'i kimlerin alabileceğini permissions'ları kullanarak kısıtlayabiliriz. Dolayısıyla dinlediği event fire edilen bir receiver, gerekli permission'lara sahip olmadığı için bu broadcast'i alamaz. Alternatif olarak, Intent.setPackage() method'unu çağırarak sadece bir uygulamaya broadcast gönderecek şekilde kısıtlama yapmak da mümkündür. )

Local Broadcast Manager

        None of these issues exist when using LocalBroadcastManager, since intents broadcast it never go outside of the current process.
       If you only want to broadcast intents within your app then use the local broadcast manager and you won’t have these security problems.
( Eğer sadece broadcastreceiver'ımızı sadece kendi uygulamamızın process'i içerisindeki event'lere register edeceksek, yani broadcast mekanizmasını sadece kendi uygulamamız içerisinde kullanacaksak local broadcast manager'i kullanmalıyız. local broadcast manager kullanırsak herhangi bir güvenlik endişemiz olmaz. )
       Helper to register for and send broadcasts of Intents to local objects within your process. This has a number of advantages over sending global broadcasts with sendBroadcast(Intent) ( Dinlediğimiz intent de, broadcast gönderme işlemi de process'imiz içerisinde olmalıdır. ) :
       You know that the data you are broadcasting won't leave your app, so don't need to worry about leaking private data. ( Broadcast ettiğimiz yani gönderdiğimiz data'nın uygulamamızın dışına çıkmayacağını biliriz. Dolayısıyla özel verilerin dışarıya sızmayacağından, broadcast edilen edilen verinin uygulama içerisinde kalacağından emin oluruz. )
       It is not possible for other applications to send these broadcasts to your app, so you don't need to worry about having security holes they can exploit. ( Diğer uygulamaların local broadcast'lerini bizim uygulamamıza göndermeyeceğinden emin olduğumuz için, uygulamamızda diğer uygulamaların kullanabileceği bir güvenlik açığı olmadığını biliriz.  )
       It is more efficient than sending a global broadcast through the system. ( Local broadcast göndermek, global broadcast göndermekten daha verimlidir. )

       Access permissions can be enforced by either the sender or receiver of a broadcast. ( Bir broadcast'in göndericisi veya alıcısı erişim izinlerini belirleyebilir. )
       To enforce a permission when sending, you supply a non-null permission argument to sendBroadcast(Intent, String) orsendOrderedBroadcast(Intent, String, BroadcastReceiver, android.os.Handler, int, String, Bundle). Only receivers who have been granted this permission (by requesting it with the <uses-permission> tag in their AndroidManifest.xml) will be able to receive the broadcast. ( Broadcast gönderirken, sendBroadcast() method'una permission argument'i vererek erişim izni kısıtlaması tanımlayabiliriz. Bu durumda sadece bu permission'a sahip olan receiver'lar bu broadcast'i alabilecektir, yani AndroidManifest.xml dosyalarında <uses-permission> element'ini kullanarak bu permission'a sahip olan receiver'lar bu broadcast'i alabilecektir. )
       To enforce a permission when receiving, you supply a non-null permission when registering your receiver -- either when callingregisterReceiver(BroadcastReceiver, IntentFilter, String, android.os.Handler) or in the static <receiver> tag in your AndroidManifest.xml. Only broadcasters who have been granted this permission (by requesting it with the <uses-permission> tag in their AndroidManifest.xml) will be able to send an Intent to the receiver. ( Broadcast alırken, registerReceiver() method'una permission argument'i vererek veya AndroidManifest.xml dosyasındaki <receiver> element kullanılarak erişim izni kısıtlaması tanımlayabiliriz. Bu durumda sadece bu permission'a sahip olan broadcaster'lar broadcast gönderebilecektir, yani AndroidManifest.xml dosyalarında <uses-permission> element'ini kullanarak bu permission'a sahip olan uygulamalar broadcast gönderebilecektir. )
Özetle,
- receiver'da erişim izni kısıtlaması tanımlayabiliriz, bu receiver'a sadece ilgili erişim yetkisine sahip uygulamalar broadcast gönderebilir.
- broadcaster gönderirken erişim izni kısıtlaması tanımlayabiliriz, bu broadcaster sadece erişim yetkisine sahip olan receiver'lara broadcast gönderebilir.
See the Security and Permissions document for more information on permissions and security in general.
Receiver Lifecycle
        A BroadcastReceiver object is only valid for the duration of the call to onReceive(Context, Intent). Once your code returns from this function, the system considers the object to be finished and no longer active. (BroadcastReceiver object sadece onReceive() method'u çalışmaktayken geçerlidir. onReceive() method'u return ettikten sonra BroadcastReceiver object artık ölmüştür, bu object artık yoktur geçerli değildir. )
       This has important repercussions to what you can do in an onReceive(Context, Intent) implementation: anything that requires asynchronous operation is not available, because you will need to return from the function to handle the asynchronous operation, but at that point the BroadcastReceiver is no longer active and thus the system is free to kill its process before the asynchronous operation completes. ( onReceive() method'unun içerisinde asynchronous bir işlem yapamayız, asynchronous bir fonksiyon çağıramayız. Çünkü asynchronous method'u çağırdığımızda, asynchronous method return etmeden sonraki satırlardaki kodların çalıştırılmaya devam ettiğini hatırlayalım. Dolayısıyla bir müddet sonra onReceive() method'u return edecektir dolayısıyla BroadcastReceiver object artık aktif olmayacaktır ancak bu sırada asynchronous method hala return etmemiş olacaktır. BroadcastReceiver object aktif olmadığı için process sistem tarafından her an kill edilebilir ancak asenkron method hala return etmemiştir hala çalışmaktadır. Tehlikeyi anladın mı!! Eveeet!! )
        In the case of a statically published BroadcastReceiver (defined in an application's manifest with the <receiver> tag), Android is free to kill its process after onReceive(Context, Intent) returns. Your async operation wouldn't stop due to a GC, it would stop due to Android killing the process that is hosting it.
       If the code you want to execute in your BroadcastReceiver can be ran synchronously then that would be the easiest approach. I'm assuming that isn't possible though.
       So, either run your receiver code synchronously or use a Service to keep your asynchronous operation alive long enough to complete.
       (Of course this all applies only if you are statically registering your receiver in an otherwise inactive app. If you are dynamically registering it from within some other active component (say, an Activity), then that component could manage your async operation. See this answer for more info on that.)
       There are two ways to use a BroadcastReceiver, and you did not indicate which you are using.
       One for a receiver registered by some other component -- like an Activity -- via registerReceiver(). This receiver will live for as long as it is registered, and so its data may last for more than one onReceive() call. The component that registered the receiver would be responsible for persisting the data.
       The other is to register your receiver in the manifest. Those, per the quoted passage in cdonner's answer, will go away after a single onReceive() call. Your receiver will need to persist its data itself, to a database, flat file, or whatever.
       Since Android API 11 you can call the goAsync() method. This method returns an object of the PendingResult type. The Android system considers the receiver as alive until you call the PendingResult.finish() on this object. With this option you can trigger asynchronous processing in a receiver. As soon as that thread has completed, its task calls finish() to indicate to the Android system that this component can be recycled. (http://www.vogella.com/tutorials/AndroidBroadcastReceiver/article.html .  )
(     BroadcastReceiver'ı static olarak publish ettiysek (Uygulamamızın AndroidManifest.xml dosyasında <receiver> tag'ını kullanarak bir broadcast'e register olduysak ) :
- onReceive() method'u return ettikten sonra, broadcastReceiver object'e erişilemez, Android process'imizi(uygulamamızı) her an kill edebilir. Dolayısıyla onReceive() method'u içinde çalışan bir asenkron işlem varsa durdurulur. BroadcastReceiver sürdürmek istediği verileri kendisi sürdürmek zorundadır.
- onReceive(Context, Intent) method'unda asenkron bir kod çalıştıracaksak, process'imizin canlı kalması ve asenkron işlemimizin aktif kalması sürdürülmesi için Service de kullanmalıyız.
- Android API 11 ile birlikte, goAsync() method'u geldi. Bu method PendingResult object return eder. PendingResult object'in finish() method'unu çağırana kadar BroadcastReceiver canlı kalır. Bu sayede artık BroadcastReceiver'ı static olarak publish etsek bile onReceive() method'unda goAsync() method'unu çağırarak asenkron bir işlem yapabiliriz. Asenkron işlem tamamlanınca goAsync() method'unun return ettiği PendingResult object'in finish() method'u çağırılarak, asenkron işlemin bittiği onReceive() method'una haber verilir, artık broadcastReceiver object recycle edilebilir yani garbage collector tarafından öldürülebilir.
       BroadcastReceiver'ı dynamic olarak publish ettiysek ( Aktif bir bileşende, örneğin bir activity'de veya fragment'da Context.registerReceiver() method'unu çağırarak bir broadcast'e register olduysak )
- Bu aktif bir bileşen, activity veya fragment, asenkron işlemi yönetecektir. İlgili activity broadcastReceiver'a registered olduğu müddetçe broadcastReceiver object yaşayacaktır.
onReceive() method'u return ettikten sonra da broadcastReceiver object yaşayacaktır. The component that registered the receiver would be responsible for persisting the data, yani activity verinin tutulmasından sorumludur,hangi veriden bahsettiğini anlamadım.

onReceive(Context, Intent) method'unda senkron bir kod çalıştıracaksak hiçbir şey dert etmemize gerek yoktur çünkü broadcast object ve process hep canlı kalacaktır ancak onReceive() method'unda uzun süren senkron işlemler yapılmamalıdır aksi takdirde bu senkron işlemler bitmeden onReceive() method'u return edemez bu da sorunlara yol açabilir. )
       In particular, you may not show a dialog or bind to a service from within a BroadcastReceiver. For the former, you should instead use the NotificationManager API. For the latter, you can use Context.startService() to send a command to the service. ( BroadcastReceiver'ın içerisinde bir dialog göstermek zorunda değiliz bunun için NotificationManager kullanılmalıdır, ayrıca bir service'a bind etmek zorunda da değiliz. bunun için ise Context.startService() method'u kullanılmalıdır diye açıkladım ama Anlamadım ne demek istediğini?? )
Process Lifecycle
        A process that is currently executing a BroadcastReceiver (that is, currently running the code in its onReceive(Context, Intent) method) is considered to be a foreground process and will be kept running by the system except under cases of extreme memory pressure. (Bir BroadcastReceiver'ı çalıştırmakta olan bir process, yani onReceive() method'undaki kodu çalıştırmakta olan bir process, foreground'dadır, yani aşırı memory kullanımı olmadığı müddetçe sistem tarafından çalıştırılmaya devam edecektir. )
       Once you return from onReceive(), the BroadcastReceiver is no longer active, and its hosting process is only as important as any other application components that are running in it.
       This is especially important because if that process was only hosting the BroadcastReceiver (a common case for applications that the user has never or not recently interacted with), then upon returning from onReceive() the system will consider its process to be empty and aggressively kill it so that resources are available for other more important processes.
       This means that for longer-running operations you will often use a Service in conjunction with a BroadcastReceiver to keep the containing process active for the entire time of your operation.
       (onReceive() method'u return ettikten sonra artık BroadcastReceiver object aktif değildir dolayısıyla bu broadcastreceiver'ı içeren process artık foreground'da olmayabilir, foreground'da olup olmamasını bu process'de çalışan diğer application component'lere bağlıdır.
       Bu önemlidir çünkü process sadece bu BroadcastReceiver'ı içeriyorsa, onReceive() method'u return ettikten sonra, sistem artık process'in boş olduğunu düşünecektir, dolayısıyla bu process'i öldürüp resource'ları daha önemli diğer process'lere vermek isteyecektir.
       Bu şu anlama gelir : Uzun süren işlemlerde, Service ve BroadcastReceiver'ı birlikte kullanmalıyız ki broadcastreceiver'ı içeren process uzun süren işlem boyunca aktif kalabilsin. service sürekli olarak broadcastreceiver'ın onReceive() method'unu çağıracak bu sayede broadcastreceiver'ı içeren process sürekli olarak foreground'da kalacak. diye açıkladım emin )

- The implementing class for a receiver extends the BroadcastReceiver class.
- If the event for which the broadcast receiver has registered happens, the onReceive() method of the receiver is called by the Android system.
System broadcasts
       Several system events are defined as final static fields in the Intent class. Other Android system classes also define events, e.g., the TelephonyManager defines events for the change of the phone state.
The following table lists a few important system events.
Event      Description
Intent.ACTION_BOOT_COMPLETED      Boot completed. Requires the android.permission.RECEIVE_BOOT_COMPLETED permission
Intent.ACTION_POWER_CONNECTED   Power got connected to the device.
Intent.ACTION_POWER_DISCONNECTED     Power got disconnected to the device.
Intent.ACTION_BATTERY_LOW     Triggered on low battery. Typically used to reduce activities in your app which consume power.
Intent.ACTION_BATTERY_OKAY   Battery status good again.
-------
From tutorialspoint :
There are following two important steps to make BroadcastReceiver works for the system broadcasted intents.
·        Defining the Broadcast Receiver subclass.
·        Registering Broadcast Receiver
( Herhangi bir broadcast'i dinleyen custom bir broadcast nasıl inşa edilir? BroadcastReceiver subclass'ı tanımlayıp bu broadcastReceiver'ın bir broadcast'i dinlemesini sağlayarak.  )
       A broadcast receiver is implemented as a subclass of BroadcastReceiver class and overriding the onReceive() method where each message is received as a Intent object parameter. ( MyReceiver isimli bir BroadcastRecever subclass'ı tanımlayalım ve bu class'da onReceive() method'unu override edelim. Bu receiver'a gönderilen intent object hakkında bilgi almak için onReceive() method'unun aldığı 2. parametre olan Intent object'i inceleyelim. )
public class MyReceiver extends BroadcastReceiver {
   @Override
   public void onReceive(Context context, Intent intent) {
      Toast.makeText(context, "Intent Detected.", Toast.LENGTH_LONG).show();
   }
}
       An application listens for specific broadcast intents by registering a broadcast receiver in AndroidManifest.xml file. Consider we are going to register MyReceiver for system generated event ACTION_BOOT_COMPLETED which is fired by the system once the Android system has completed the boot process. ( MyReceiver isimli broadcastReceiver class'ımızı tanımladıktan sonra bu class'ın bir broadcast'i dinlemesini sağlamalıyız. AndroidManifest.xml dosyasında <receiver> element'ini kullanarak broadcastReceiver class'ımızın bir broadcast'i dinlemesini static olarak sağlayalım.
       AndroidManifest.xml dosyasında bir <receiver> element yazalım. <receiver> element'in android:name attribute'üne, yukarıda tanımladığımız broadcastReceiver subclass'ı olan MyReceiver'ın ismini veririz. <receiver> element'i içinde <intent-filter> element, <intent-filter> element içinde <action> element yazarız. <action> element'in android:name attribute'üne ise, broadcastReceiver'ımızın dinleyeceği broadcast'in(intent'in,event'in) ismini yazarız. Bu örnekte MyReceiver isimli bir broadcastReceiver subclass tanımladık. Sonra AndroidManifest.xml dosyasında, bu broadcastReceiver'ın android.intent.action.BOOT_COMPLETED intent'ini dinlemesini sağladık. Bu intent telefon açılırken sistem tarafından broadcast edilir. Dolayısıyla telefon açıldığında, bu broadcast'i dinleyen MyReceiver isimli broadcastReceiver class'ının onReceiver() method'u invoke edilir.  )

<application
   android:icon="@drawable/ic_launcher"
   android:label="@string/app_name"
   android:theme="@style/AppTheme" >
   <receiver android:name="MyReceiver">
      <intent-filter>
         <action android:name="android.intent.action.BOOT_COMPLETED">
         </action>
      </intent-filter>
   </receiver>
</application>
Now whenever your Android device gets booted, it send broadcast to BroadcastReceiver MyReceiver and onReceive() method of MyReceiver class is called.
 broadcast


Built-in intent'leri veya custom intent'leri broadcast edebiliriz :

1 . Broadcasting Built-in Intents

There are several system generated events defined as final static fields in the Intent class. The following table lists a few important system events. (Intent class'ında final static olarak tanımlanmış intent'lerden bazıları aşağıdaki tabloda gösterilmiştir. Bu intent'ler Android sistem tarafından otomatik olarak broadcast edilirler. )
Sr.No
Event Constant & Description
1
android.intent.action.BATTERY_CHANGED
Sticky broadcast containing the charging state, level, and other information about the battery.
2
android.intent.action.BATTERY_LOW
Indicates low battery condition on the device.
3
android.intent.action.BATTERY_OKAY
Indicates the battery is now okay after being low.
4
android.intent.action.BOOT_COMPLETED
This is broadcast once, after the system has finished booting.
5
android.intent.action.BUG_REPORT
Show activity for reporting a bug.
6
android.intent.action.CALL
Perform a call to someone specified by the data.
7
android.intent.action.CALL_BUTTON
The user pressed the "call" button to go to the dialer or other appropriate UI for placing a call.
8
android.intent.action.DATE_CHANGED
The date has changed.
9
android.intent.action.REBOOT
Have the device reboot.

 

2 . Broadcasting Custom Intents

       If you want your application itself should generate and send custom intents then you will have to create and send those intents by using the sendBroadcast() method inside your activity class. If you use the sendStickyBroadcast(Intent) method, the Intent is sticky, meaning the Intent you are sending stays around after the broadcast is complete. ( Custom bir Intent nasıl broadcast edilir? Intent object yaratılır. Intent object'in setAction() method'u ne için kullanılıyor anlamadım. Sonra sendBroadcast() veya sendOrderedBroadcast() veya sendStickyBroadcast() method'u çağırılır, bu method'lara argument olarak intent object verilir. )
public void broadcastIntent(View view) {
   Intent intent = new Intent();
   intent.setAction("com.tutorialspoint.CUSTOM_INTENT");
   sendBroadcast(intent);
}
This intent com.tutorialspoint.CUSTOM_INTENT can also be registered in similar way as we have regsitered system generated intent. ( MyReceiver isimli BroadcastReceiver subclass'ının ismini <receiver> element'İnin android:name attribute'üne veririz.gönderdiğimiz intent'in içerdiği action'ı, receiver'ın dinlemesini static olarak sağlamak için AndroidManifest.xml dosyası yazarız aşağıdaki gibi. )
<application
   android:icon="@drawable/ic_launcher"
   android:label="@string/app_name"
   android:theme="@style/AppTheme" >
   <receiver android:name="MyReceiver">
      <intent-filter>
         <action android:name="com.tutorialspoint.CUSTOM_INTENT">
         </action>
      </intent-filter>
   </receiver>
</application>

Example :
MainActivity.java : ( MainActivity'de tüm gerekli lifecycle method'larının olduğunu varsayalım. Aşağıda sadece onCreate() method'unu gösterdik. Ayrıca broadcastIntent() isimli bir method tanımladık. Main layout'a bir buton koyacağız ve bu butona basınca broadcastIntent() method'unun çağırılmasını sağlayacağız. Bu method'un içerisinde bir Intent yarattık sonra setAction() method'unu çağırdık bu method'un ne işe yaradığını bilmiyorum. Sonra sendBroadcast(intent) method'unu çağırarak intent'in(broadcast'in) gönderilmesini sağladık. )
package com.example.tutorialspoint7.myapplication;
import ...

public class MainActivity extends Activity
{
   @Override
   public void onCreate(Bundle savedInstanceState)
   {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
   }

   // broadcast a custom intent. 
   public void broadcastIntent(View view)
   {
      Intent intent = new Intent();
      intent.setAction("com.tutorialspoint.CUSTOM_INTENT");
       sendBroadcast(intent);
   }
}

MyReceiver.java: (BroadcastReceiver class'ını extend eden bir class tanımlayalım, b class'da onReceive() method'unu implement edelim. Bu receiver'ın dinlediği event, intent gerçekleşince bu class'daki onReceive() method'u çağırılacaktır otomatik olarak. Peki bu receiver'ın bir Broadcast'e register olmasını nasıl sağlayabiliriz? Dinamik olarak veya static olarak. Bu örnekte static olarak sağladık. AndroidManifest.xml dosyasında <receiver> element yazarız, <receiver> element'in android:name attribute'üne MyReceiver class'ımızın ismini veririz. <receiver> element'inin içindeki <intent-filters> element'inin içindeki <action> element'inin android:name attribute'üne dinlediğim custom event ismini veririz. Böylece MyReceiver class'ımızdaki onReceive() method'unun hangi action(event,broadcast,intent) gerçekleştiğinde çağırılacağını da belirlemiş oluruz. )
package com.example.tutorialspoint7.myapplication;
import ...
public class MyReceiver extends BroadcastReceiver
{
   @Override
   public void onReceive(Context context, Intent intent)
   {
      Toast.makeText(context, "Intent Detected.", Toast.LENGTH_LONG).show();
   }
}
AndroidManifest.xml :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.example.tutorialspoint7.myapplication">
   <application
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:supportsRtl="true"
      android:theme="@style/AppTheme">     
      <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="MyReceiver">
         <intent-filter>
            <action android:name="com.tutorialspoint.CUSTOM_INTENT">
            </action>
         </intent-filter>
      </receiver>

   </application>

</manifest>
res/layout/activity_main.xml ( Layout'a bir butona koyduğumuza dikkat et. Bu butona basınca custom intent'imiz broadcast edilecektir, yani kendisini dineleyen broadcastreceiver'lara gönderilecektir )
<RelativeLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:paddingLeft="@dimen/activity_horizontal_margin"
   android:paddingRight="@dimen/activity_horizontal_margin"
   android:paddingTop="@dimen/activity_vertical_margin"
   android:paddingBottom="@dimen/activity_vertical_margin"
   tools:context=".MainActivity">
  
   <TextView
      android:id="@+id/textView1"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Example of Broadcast"
      android:layout_alignParentTop="true"
      android:layout_centerHorizontal="true"
      android:textSize="30dp" />
     
   <TextView
      android:id="@+id/textView2"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Tutorials point "
      android:textColor="#ff87ff09"
      android:textSize="30dp"
      android:layout_above="@+id/imageButton"
      android:layout_centerHorizontal="true"
      android:layout_marginBottom="40dp" />
     
   <ImageButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:id="@+id/imageButton"
      android:src="@drawable/abc"
      android:layout_centerVertical="true"
      android:layout_centerHorizontal="true" />
     
   <Button
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:id="@+id/button2"
      android:text="Broadcast Intent"
      android:onClick="broadcastIntent"
      android:layout_below="@+id/imageButton"
      android:layout_centerHorizontal="true" />

</RelativeLayout>
Uygulamayı başlattığımızda aşağıdaki gibi bir ekran karşımıza çıkar.
Android Broadcast Demo

       Now to broadcast our custom intent, let's click on Broadcast Intent button, this will broadcast our custom intent "com.tutorialspoint.CUSTOM_INTENT" which will be intercepted by our registered BroadcastReceiver i.e. MyReceiver and as per our implemented logic a toast will appear on the bottom of the the simulator as follows (Butona basınca custom intent'İmiz, kendisini dinleyen broadcastrecceiver'lara broadcast edilecektir, dolayısıyla MyReceiver'a da broadcast edilecektir ve MyReceiver'ın onReceive() method'u çağırılarak ekranda aşağıdaki toast yazı gösterilecektir. )
Android Broadcast Intent
You can try implementing other BroadcastReceiver to intercept system generated intents like etc. ( Bu örneği değiştirip, system generated intent'ler(system boot up, date changed, low battery) gerçekleştiğinde, BroadcastReceiver'ımıza broadcast edilecek hale getirebiliriz.  )

intent.setAction() nedir?? Acil öğrenmelisin!!!! intent.setAction'a herhangi bir string verebiliriz. mesela "omer" diyebiliriz. Sonra ise "omer" diye bir broadcast geldi mi diye dinlemeliyiz.
-------
https://github.com/JimSeker/BroadCastReceiver

8_BroadCastDemo1

        Bu projede şu 6 dosya gereklidir. Bunların üzerinden tek tek geçeceğiz.
MainActivity.java
MyReceiver.java
AndroidManifest.xml
fragment_main.xml
activity_main.xml
MainFragment.java
        A simple demo of broadcast receiver and custom intent. The fragment has the code to send the broadcast. This code will register a dynamic intent-filter for Action2 action one is static registered in the manifest file. ( Bu örnekte custom bir broadcastreceiver class tanımlayacağız. Fragment'daki butonlara tıklayınca broadcast gönderilir. Bu kodda 2 farklı broadcast yapılır, broadcastreceiver'lardan biri dinamik olarak diğeri ise static olarak(AndroidManifest.xml'de tanımlanarak) register edilmiştir. )
Point 1 :  MainActivity'yi inceleyerek işe başlayalım. Bu örnekteki MainActivity class'ının ismi, başka projelerde farklı olabilir, başka projelerdeki MainActivity'ye karşılık gelen activity'yi bulmak için AndroidManifest.xml dosyasına bakarız. Bir activity'nin başlangıç activitysi olmasını şu koddaki <intent-filter> tag'ının altındaki action ve category tag'ları belirler:
        <activity
            android:name=".MainActivity"
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
Point 2 :  MainActivity class'ında 2 tane public static final String variable tanımlanmıştır. Bu variable'lara istediğimiz string değerini assign edebiliriz. Bunlar bizim custom intent'lerimizdir, bu intent'leri MainFragment class'ından göndeririz(broadcast ederiz), bunun sonucunda MyReceiver class'ının onReceive() method'u çağırılır. Bu intent'leri public yapmamız sayesinde, MainFragment class'ında MainActivity.ACTION1 ve MainActivity.ACTION2 diyerek bu intent'lere erişebiliriz. 1.broadcast'e static olarak register olacağımız için AndroidManifest.xml dosyasında action android:name="edu.cs4730.bcr.mystaticevent"/> deriz dolayısıyla static intent'in değerini değiştirmek istiyorsak, bu intent'in hem MainActivity.java'daki hem de AndroidManifest.xml'deki değerini değiştirmeliyiz. Aşağıdaki kod şunu der, main package'daki MyReceiver class'ında BroadcastReceiver tanımlanmıştır, edu.cs4730.bcr.mystaticevent isimli bir broadcast(intent,event) gönderilirse MyReceiver class'ındaki onReceive() method'u çalıştırılır otomatik olarak.
        <receiver
            android:name=".MyReceiver"
            android:enabled="true"
            android:exported="true" >
             <intent-filter >
                        <action android:name="edu.cs4730.bcr.mystaticevent"/>
            </intent-filter>
        </receiver>

Point 3 :  MainActivity class'ının onCreate() method'unda, setContentView(R.layout.activity_main); diyerek main layout olarak activity_main.xml set edilir. activity_main.xml şöyledir:
<FrameLayout    android:id="@+id/container"  />
Yani layout'a sadece FrameLayout tag koyulur. Sonra
getSupportFragmentManager().beginTransaction() .add(R.id.container, new MainFragment()).commit(); diyerek container id'li element'in yerine yani FrameLayout'un yerine MainFragment class'ından elde edilen layout yani fragment_main.xml koyulur. Sonuç olarak kullanıcının gördüğü layout fragment_main.xml'dir.

Point 4 :  MainFragment class'ının layout'u nerede belirlenmiştir? MainFragment class'ının onCreateView() method'unda inflater.inflate() method'unun return ettiği view'i return ederek :
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
        // Inflate the layout for this fragment
        View myView = inflater.inflate(R.layout.fragment_main, container, false);
         return myView;
}
        Fragment'ın layout'u fragment_main.xml olarak belirlenmiştir. fragment_main.xml dosyasının içeriği aşağıda gösterilmiştir.
<LinearLayout  android:id="@+id/LinearLayout1">
    <Button
                android:id="@+id/button1"
                android:text="Send Static intent" />
        <Button
                android:id="@+id/button2"
                android:text="Send Dynamic Intent" />
</LinearLayout>
        Root element LinearLayout'dur, linearlayout içerisinde id'leri button1 ve button2 olan 2 tane buton vardır. Bu butonlara tıklayınca alınacak aksiyonu da gene onCreateView() method'unda belirleriz. 

Point 5:   MainActivity class'ının scope'unda, MyReceiver type'ında bir reference variable tanımlarız. onCreate() method'unda, MyReceiver class'ından bir object yaratırız ve mReceiver isimli reference vairable'ın bu object'e refer etmesini sağlarız.
        MainActivity class'ının onResume() method'unda, registerReceiver() method'una argument olarak MyReceiver object'i ve new intentFilter(ACTION2) object'i veririz. Böylece, ACTION2 broadcast geldiğinde MyReceiver object'in onReceive() method'unun çalışmasını sağlarız.
        MainActivity class'ının onPause() method'unda ise unregisterReceiver(mReceiver) method'unu çağırarak Broadcastreceiver'ın broadcast'i dinlemesini durdururuz.
MainActivity.java
package edu.cs4730.broadcastdemo1;
import ...
public class MainActivity extends AppCompatActivity {
        public static final String ACTION1="edu.cs4730.bcr.mystaticevent";
        public static final String ACTION2="edu.cs4730.bcr.mydynamicevent";
       
        String TAG = "MainActivity";
        MyReceiver mReceiver;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                if (savedInstanceState == null) {
                     getSupportFragmentManager().beginTransaction() .add(R.id.container, new MainFragment()).commit();
                }
               
                //need to initialize the variable here. 
                mReceiver = new MyReceiver();
        }

        @Override
        public void onResume() {
                super.onResume();
                registerReceiver(mReceiver,  new IntentFilter(ACTION2));
                //Log.v(TAG, "receiver should be registered");
        }
        @Override
        protected void onPause() {
                unregisterReceiver(mReceiver);
                Log.v(TAG, "receiver should be unregistered");
                super.onPause();
        }
}
activity_main.xml
<FrameLayout   android:id="@+id/container"   />

        action1 statically register edilmiştir AndroidManifest.xml dosyası kullanılarak. action2 ise MainActivity'nin onResume() ve onPause() method'larında dinamik olarak register ve unregister edilir.
The variables ACTION1 and ACTION2 variable'ları MainActivity.java'da declare edilmiştir.
        ACTION1 ve ACTION2 broadcast'lerinden birisi gerçekleşince, MyReceiver class'ının onReceiver() method'u invoke edilir.
MyReceiver.java
package edu.cs4730.broadcastdemo1;
import ...
public class MyReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
                Toast.makeText(context, "Received an intent.", Toast.LENGTH_SHORT).show();
                if (intent.getAction().equals(MainActivity.ACTION1))
                {
                        Toast.makeText(context, "We received an intent for Action1.", Toast.LENGTH_SHORT).show();
                }
                else if (intent.getAction().equals(MainActivity.ACTION2))
                {
                        Toast.makeText(context, "We received an intent for Action2.", Toast.LENGTH_SHORT).show();
                }
        }
}

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="edu.cs4730.broadcastdemo1">

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

Text Box: edu.cs4730.bcr.mystaticevent broadcast'i gerçekleşince current package'ın altındaki(. bu anlama gelir) MyReceiver class'ının onReceive() method'u çağırılır.        <receiver
            android:name=".MyReceiver"
            android:enabled="true"
            android:exported="true" >
               <intent-filter >
                      <action android:name="edu.cs4730.bcr.mystaticevent"/>
               </intent-filter>
        </receiver>
    </application>

</manifest>

(Main layout'daki tek element olan FrameLayout(id'si container'dır) yerine, MainFragment class'ının layout'u olan fragment_main.xml koyulur. Bu MainActivity class'ında
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
     getSupportFragmentManager().beginTransaction() .add(R.id.container, new MainFragment()).commit();
}
denilerek yapılır. fragment_main.xml'de 2 tane butona vardır. Bu butonlara basınca intent broadcast edilir. Bunları da MainFragment class'ının onCreateView() method'undaimplement ederiz.
MainFragment.java
package edu.cs4730.broadcastdemo1;
import ...
// This is code demo to send two different custom intents.
public class MainFragment extends Fragment {
        String TAG= "MainFragment";
        public MainFragment() {
                // Required empty public constructor
        }
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
                // Inflate the layout for this fragment
                View myView = inflater.inflate(R.layout.fragment_main, container, false);

                //setup button to send an intent for static registered receiver.
                myView.findViewById(R.id.button1).setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(View view) {
                               Intent i = new Intent(MainActivity.ACTION1);
                               getActivity().sendBroadcast(i);
                        }
                });
               
                //setup button to send an intent for dynamic registered receiver, which is registered in MainActivity.
                myView.findViewById(R.id.button2).setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(View view) {
                               Intent i = new Intent(MainActivity.ACTION2);
                               getActivity().sendBroadcast(i);
                               Log.v(TAG, "Should have sent the broadcast.");
                        }
                });
                return myView;
        }
}

fragment_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="edu.cs4730.broadcastdemo1.MainFragment" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Send Static intent" />
    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Send Dynamic Intent" />
</LinearLayout>

8_BroadCastDemo2

        Bu projede şu 6 dosya gereklidir. Bunların üzerinden tek tek geçeceğiz :
MainActivity.java
activity_main.xml
AndroidManifest.xml
MyReceiver.java
MainFragment.java
fragment_main.xml
        This app is using the launch mode of singleTop, so long as it is the top process and new one will not be launched, instead it will get a new intent via NewItent(), which is what I want for the demo of some of the system broadcast via the receiver. ( Bu örnekte custom bir broadcastreceiver class tanımlayacağız. Ancak custom bir broadcast göndermeyeceğiz. Bir broadcastReceiver'ın aşağıdaki system broadcast'lerini dinlemesini ve bu broadcastlerden birisi gelirse broadcastReceiver'ın bir aksiyon almasını sağlayacağız.
android.intent.action.ACTION_POWER_CONNECTED
android.intent.action.ACTION_POWER_DISCONNECTED
android.intent.action.BATTERY_LOW
android.intent.action.BATTERY_OKAY

Point 1 :  MyReceiver isimli broadcastreceiver'ın yukarıdaki system broadcast'lerini dinlemesi static olarak(AndroidManifest.xml'de tanımlanarak) sağlanmıştır. 
        Ayrıca bu örnekte, MainActivity'nin launch mode'u singleTop'dır. Dolayısıyla bu activity onResume() moddayken yani en üstte çalışan process iken, bu activity'ye yeni bir intent, broadcast geldiğinde, yeni bir activity yaratılmayacaktır, activity'nin onNewIntent() method'u çağırılacaktır. )
Point 2 :  MainActivity class'ının onCreate() method'unda, setContentView(R.layout.activity_main); diyerek main layout olarak activity_main.xml set edilir.  activity_main.xml'in içeriği şöyledir:
<FrameLayout    android:id="@+id/container"  />
Yani layout'a sadece FrameLayout tag koyulur. Sonra
getSupportFragmentManager().beginTransaction() .add(R.id.container, new mFragment()).commit(); diyerek container id'li element'in yerine yani FrameLayout'un yerine MainFragment class'ından yaratılmış olan mFragment isimli object'in layout'u yani fragment_main.xml koyulur. Sonuç olarak kullanıcının gördüğü layout, fragment_main.xml'dir.

Point 3 :  MainFragment class'ının layout'u nerede belirlenmiştir? MainFragment class'ının onCreateView() method'unda inflater.inflate() method'unun return ettiği view'i return ederek :
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
        // Inflate the layout for this fragment
        View myView = inflater.inflate(R.layout.fragment_main, container, false);
        return myView;
}
        Fragment'ın layout'u fragment_main.xml olarak belirlenmiştir. fragment_main.xml dosyasının içeriği aşağıda gösterilmiştir. Kullanıcı main layout'da bunu görür, çünkü main layout'daki tek element olan container id'li FrameLayout element'i yerine bu layout koyulmuştur runtime'da activity class'ının içerisindeki onCreate() method'unda.
<LinearLayout>
    <TextView
        android:id="@+id/textView1"
        android:text="Status" />
</LinearLayout>
        Root element LinearLayout'dur, linearlayout içerisinde sadece bir textView vardır. Bu textView'in içeriği onCreateView() method'unda set edilir.

Point 4 :
android.intent.action.ACTION_POWER_CONNECTED
android.intent.action.ACTION_POWER_DISCONNECTED
android.intent.action.BATTERY_LOW
android.intent.action.BATTERY_OKAY
intent'lerinden birisi broadcast edilince MyReceiver class'ının onReceive() method'u çağırılır. onReceive() method'unda, önce Intent object yaratılır. Sonra intent object'in addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) method'u çağırılır, bu intent object'i kullanarak activity olmayan bir class'dan activity başlatmak istediğimiz( context.startActivity() ) için intent object'in addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)  method'u çağırılmak zorundadır.
        Sonrasında broadcastreceiver'a gelen intent'in ismine göre bir if block'a girilir, Intent object'in mStatus isimli variable'ına 1-4 arasında  bir değer verilir. Sonra context.startActivity(i) method'u çağırılır, bu method argument olarak intent alır. context.startActivity(i) method'u çağırılınca yeni bir activity yaratılmak istenir ancak activity'nin launch mode'u singleTop olduğu için bu activity'ye bir intent gönderilir ama yeni bir activity yaratılmaz, MainActivity class'ının sırayla onPause(),onNewIntent() ve onResume() method'ları çağırılır.
        MyReceiver class'ının onReceive() method'unda set edilip gönderilen intent'deki Bundle object, MainActivity class'ının onNewIntent() method'unda intent.getExtras() method'u çağırılarak elde edilir. Sonra bu Bundle'da saklanan mStatus isimli variable'ın değeri okunur ve MainFragment object'in setstat(info) çağırılarak fragment'In içerdiği textview'deki text güncellenir.

Activity'de bu intent'in tuttuğu variable elde edilir.

Point 5 : MainActivity class'ının onCreate() method'undaki aşağıdaki satırları şöyle yorumladım ancak emin değilim:
                int info = 0;
                Bundle extras = getIntent().getExtras();
                if (extras != null) {
                        info = extras.getInt("mStatus",0);
                }
                mFragment = new MainFragment(info);
Yeni bir broadcast geldiğinde context.startActivity() method'u çağırılacaktır. Ancak MainActivity class'ı foreground'da olduğu müddetçe MainActivity class'ından yeni bir activity yaratılmayacaktır, yani MainActivity class'ının onCreate() method'u çağırılmayacaktır. Ancak bu activity arka plana geçerse örneğin home tuşuna bastık sonra bu uygulamaya geri döndük. Bu durumda onCreate() method'u tekrar çağırılacaktır ve MainActivity'yi başlatan intent'deki mStatus variable okunacaktır ve MainFragment class'ından bir object yaratırken MainFragment() constructor'a argument olarak verilecektir.
getIntent : Return the intent that started this activity.
If you start an Activity with some data, for example by doing
Intent intent = new Intent(context, SomeActivity.class);
intent.putExtra("someKey", someData);
you can retrieve this data using getIntent in the new activity:
Intent intent = getIntent();
intent.getExtra("someKey") ...


MainActivity.java
package edu.cs4730.broadcastdemo2;
import ...
public class MainActivity extends AppCompatActivity {
        MainFragment mFragment=null;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
               
                int info = 0;
                Bundle extras = getIntent().getExtras();
                if (extras != null) {
                        info = extras.getInt("mStatus",0);
                }
                mFragment = new MainFragment(info);

                if (savedInstanceState == null) {
                        getSupportFragmentManager().beginTransaction()
                                       .add(R.id.container, mFragment).commit();
                }
        }
        @Override
        protected void onNewIntent(Intent intent) {
                super.onNewIntent(intent);
                int info = 0;
                Bundle extras = intent.getExtras();
                if (extras != null) {
                        info = extras.getInt("mStatus",0);
                }
                mFragment.setstat(info);
        }
}

activity_main.xml
<FrameLayout   android:id="@+id/container"  />

AndroidManifest.xml
MyReceiver.java
package edu.cs4730.broadcastdemo2;
import ...
public class MyReceiver extends BroadcastReceiver {
        public MyReceiver() {
        }

        @Override
        public void onReceive(Context context, Intent intent) {
                Log.v("myReceiver", "received an intent");
                Intent i = new Intent(context, MainActivity.class);
                i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);   //required when start an activity from a non activity.
               
              if (intent.getAction().equals(Intent.ACTION_BATTERY_LOW)){
                        Log.v("myReceiver", "battery low");
                        i.putExtra("mStatus", 1);  //battery low
                        context.startActivity(i);
                }
              else if (intent.getAction().equals(Intent.ACTION_BATTERY_OKAY)){
                        Log.v("myReceiver", "battery okay");
                        i.putExtra("mStatus", 2);  //battery okay
                        context.startActivity(i);
                }
             else if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)){
                        Log.v("myReceiver", "ac on");
                        i.putExtra("mStatus", 3);  //charging/on power
                        context.startActivity(i);
            } else if (intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)){
                        Log.v("myReceiver", "ac off");
                        i.putExtra("mStatus", 4);  //disconnected from power.
                        context.startActivity(i);
                }
        }
}

MainFragment.java
        MainFragment class'ından bir object yaratırken constructor'a verilen argument, MainFragment class'ının scope'undaki mStatus variable'a assign edilir. MainFragment() argumentsiz çağırılırsa mStatus'ün default değeri olan 0 kullanılır.
        onCreateView() method'unda, inflater.inflate() method'u çağırılarak fragment'ın layout'u olarak kullanılacak olan View object elde edilir. Ardından view object'deki textView id'li element elde edilir. Ekrandaki TextView element'de gösterilecek değer, setStatus(mStatus) method'u çağırılarak set edilir.



fragment_main.xml
<LinearLayout    android:id="@+id/LinearLayout1" >
    <TextView android:id="@+id/textView1"  android:text="Status"  />
</LinearLayout>

https://www.youtube.com/watch?v=ZE_oCluEZ3c
https://blog.mindorks.com/android-activity-launchmode-explained-cbc6cf996802#.qyl1vpnlt bu linki incelemedim ancak faydalı bir link'e benziyor incelemende fayda olabilir.
BroadcastNoti. isimli örneğe devam etmeden önce NotificationManager, Notification, AlarmManager 'ı öğren.


Hiç yorum yok:

Yorum Gönder