15 - BroadcastReceiver
http://www.cs.dartmouth.edu/~campbell/cs65/lecture19/lecture19.html
A 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.
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.
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. )
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>
<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