I want to build an app where I have to use MediaProjectionManager in a Service. But I can not solve it as 'startActivityForResult' can't use in Service class.
I really want to do this from a service, which is how I found this question. This is the closest I've came up, so just throwing this out there, till a better answer comes along. Here's a way to do it from an activity that's almost like doing it from a service:
import static your.package.YourClass.mediaProjectionManager;
public class MainActivity extends Activity {
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(null);
mediaProjectionManager = (MediaProjectionManager)getContext().getSystemService(MEDIA_PROJECTION_SERVICE);
startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), 1);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
if (resultCode == Activity.RESULT_OK) {
mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
this.finish();
}
}
}
Then in your service when ever you need permission call
private void openMainActivity() {
Intent mainIntent = new Intent(getContext(), MainActivity.class);
mainIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(mainIntent);
}
To make the activity invisible in your AndroidManifest.xml
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#android:style/Theme.NoDisplay"
android:excludeFromRecents="true"
android:screenOrientation="portrait">
</activity>
Caveats:
For a brief second the application you're screenshooting will lose focus.
For a brief second your app will be the foreground app, so don't trip over your own shoelaces
I have used same approach as here https://medium.com/#debuggingisfun/android-10-audio-capture-77dd8e9070f9
in my activity:
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(this, MediaProjectionService.class);
startForegroundService(intent);
mProjectionManager =
(MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
startActivityForResult(mProjectionManager.createScreenCaptureIntent(),
1);
}
Service itself is just some boilerplate, the notification is required if you want to run in foreground
class MediaProjectionService : Service() {
override fun onCreate() {
super.onCreate()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val builder = NotificationCompat.Builder(this, "messages")
.setContentText("streaming enabled")
.setContentTitle("Stream to e-ink")
startForeground(101, builder.build())
}
}
override fun onBind(intent: Intent): IBinder? {
return null
}
}
I am not an android expert and I am using Flutter - apperantly you also need to create a notification channel first - here is my code for Flutter Application - it's probably similar with non-flutter
class StreaminkApplication : FlutterApplication() {
override fun onCreate() {
super.onCreate()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel("messages", "Messages", NotificationManager.IMPORTANCE_LOW)
val manager = getSystemService(NotificationManager::class.java)
manager.createNotificationChannel(channel)
}
}
}
If you use application, you should change it in manifest - in my case:
<application
android:name=".StreaminkApplication"
Ok, I have managed to do this its not the cleanest of ways but works:
Local Bound Service: Make your Service a Local Bound Service, which means your service will pass a reference of itself to the the Main Activity.
Pass an Instance of the Activity to the Service : Pass the reference of your activity to the service in the Service Connection-> onServiceConnected() in the Activity class
Call the startActivityForResult: Use the Activity Instance in your service to Call the startActivityForResult function.
Note:
Upon being called the startActivityForResult will be caught in the onActivityResult() in the Activity Class. You will need to override this function in the Activity and use the service reference to return back to the service class. Also you can unbind the Activity, from the service upon completion.
I hope this makes sense, sorry for not including any code. If you have any questions ill be glad to help you in further detail.
Related
I have two Activities ActivityA and ActivityB (this one has pip mode enabled)
when ActivityB is in pip mode,ActivityA comes to the foreground now I want to finish/destroy/kill ActivityB from ActivityA is there any way to do this?
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val supportsPIP = context!!.packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
if (supportsPIP) {
enterPictureInPictureMode(mPictureInPictureParamsBuilder!!.build())
}
}
}
After checking this answer https://stackoverflow.com/a/56896347/13373099 I realized that All I had to do was just use LocalBroadcastManager
if anyone having trouble implementing this, here is what I did
in ActivityB
private val mReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) {
intent?.let { intent ->
if (intent.action == "FINISH_ACTIVITY") {
finish(); // finish/kill activity also destroys the pip
}}
}
now register the listener
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, IntentFilter("FINISH_ACTIVITY));
in ActivityA
just send a broadcast with intent action "FINISH ACTIVITY"
val intent = Intent("FINISH_ACTIVITY")
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
Another way it's to save the reference to the activity in a singleton and when you want to kill it you call finish() and the set the reference to null again.
In my android app I want to detect activity change from still to walking and start tracking location, regardless of the state of the app (in background or shut down completely).
I was able to create location tracking service which works while app in background by making it a foreground service (showing notification), but I have not been able to start tracking based on activity detection.
This is fragment of code of IntentService, which supposed to start location tracking service, after receiving intent with activity transition detected:
class ActivityDetectionIntent : IntentService(TAG) {
override fun onHandleIntent(intent: Intent?) {
val i = Intent(this#ActivityDetectionIntent, LocationTracking::class.java)
if (Build.VERSION.SDK_INT >= 26) {
startForegroundService(i)
// this followed by foregroundService call in LocationTracking service
} else {
startService(i)
}
}
// ...
}
This is the error message I'm getting:
2019-12-04 19:57:59.797 3866-15015/? W/ActivityManager: Background start not
allowed: service Intent { cmp=com.anatoliymakesapps.myapplication/.ActivityDetectionIntent
(has extras) } to com.anatoliymakesapps.myapplication/.ActivityDetectionIntent
from pid=-1 uid=10377 pkg=com.anatoliymakesapps.myapplication startFg?=false
I wonder if I miss something obvious, or maybe this whole approach is wrong and I need to try something else? Any piece of advice to achieve the desired result is appreciated.
I tried changing IntentService to JobIntentService but it made no difference, error looks the same.
Turns out intent service can not be started directly, but with help of broadcast receiver it can be achieved indirectly.
This is what I used instead of IntentService:
class ActivityTransitionBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.i(TAG, "got activity transition signal")
val i = Intent(context, LocationTrackingService::class.java)
if (Build.VERSION.SDK_INT >= 26) {
startForegroundService(context, i)
} else {
context.startService(i)
}
}
companion object {
private val TAG = ActivityTransitionBroadcastReceiver::class.java.simpleName
}
}
manifest:
<receiver android:name=".ActivityTransitionBroadcastReceiver" android:exported="true" />
I wish to use the new Activity transition API and after following the tutorial here I am not able to get the desired result.
This is the code I have for setting the activity transition I wish to detect :
public void setActivityTransitions() {
transitionList = new ArrayList<>();
ArrayList<Integer> activities = new ArrayList<>(Arrays.asList(
DetectedActivity.STILL,
DetectedActivity.WALKING,
DetectedActivity.ON_FOOT,
DetectedActivity.RUNNING,
DetectedActivity.ON_BICYCLE,
DetectedActivity.IN_VEHICLE));
for (int activity :
activities) {
transitionList.add(new ActivityTransition.Builder()
.setActivityType(activity)
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER).build());
transitionList.add(new ActivityTransition.Builder()
.setActivityType(activity)
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT).build());
}
}
And then requesting the activity transition updates :
ActivityTransitionRequest activityTransitionRequest = new ActivityTransitionRequest(transitionList);
Intent intent = new Intent(context, ActivityDetectorTransitionService.class);
intent.setAction("com.test.activityrecognition.START_ACTIVITY_TRANSITION_DETECTION_ALARM");
PendingIntent pendingIntent = PendingIntent.getService(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Task<Void> task = ActivityRecognition.getClient(context).requestActivityTransitionUpdates(activityTransitionRequest, pendingIntent);
task.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void result) {
System.out.println("onSuccess");
}
});
task.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
e.printStackTrace();
System.out.println("onFailure");
}
});
And this is the broadcastreceiver :
public class ActivityDetectorTransitionService extends BroadcastReceiver {
private static final String TAG = "ActivityDetectorTransitionService";
#Override
public void onReceive(Context context, Intent intent) {
if (ActivityTransitionResult.hasResult(intent)) {
ActivityTransitionResult activityTransitionResult = ActivityTransitionResult.extractResult(intent);
ActivityDetectorTransitionAPI.getInstance().handleActivityRecognitionResult(activityTransitionResult);
}
}
}
(The name has service in it cause initially I had kept it service but still not working.)
and in manifest :
<receiver
android:name=".tracking.activityrecognition.ActivityDetectorTransitionService">
<intent-filter>
<action android:name="com.test.activityrecognition.START_ACTIVITY_TRANSITION_DETECTION_ALARM"/>
</intent-filter>
</receiver>
You are using PendingIntent.getService() in combination with a BroadcastReceiver.
To receive pending intents with a BroadcastReceiver you have to retrieve the PendingIntent instance using PendingIntent.getBroadcast(). The corresponding developer guide concerning intents and intent filters can be found here.
Since Android 8 there are several background service limitations. Using an IntentService only works when the app is in foreground. To receive activity transition updates after the app was closed you even have to use a BroadcastReceiver. For this purpose the BroadcastReceiver has to be registered in the application manifest with the corresponding permission, as Jan Maděra already mentioned.
<receiver android:name="com.mypackage.ActivityTransitionBroadcastReceiver"
android:exported="false"
android:permission="com.google.android.gms.permission.ACTIVITY_RECOGNITION">
<intent-filter>
<action android:name="com.mypackage.ACTION_PROCESS_ACTIVITY_TRANSITIONS" />
</intent-filter>
</receiver>
Furthermore onReceive() should only respond to your specific action, since intent filters are not guaranteed to be exclusive.
public class ActivityTransitionBroadcastReceiver extends BroadcastReceiver {
public static final String INTENT_ACTION = "com.mypackage" +
".ACTION_PROCESS_ACTIVITY_TRANSITIONS";
#Override
public void onReceive(Context context, Intent intent) {
if (intent != null && INTENT_ACTION.equals(intent.getAction())) {
if (ActivityTransitionResult.hasResult(intent)) {
ActivityTransitionResult intentResult = ActivityTransitionResult
.extractResult(intent);
// handle activity transition result ...
}
}
}
}
Requesting activity transition updates using PendingIntent.getBroadcast():
ActivityTransitionRequest request = new ActivityTransitionRequest(transitionList);
Intent intent = new Intent(context, ActivityTransitionBroadcastReceiver.class);
intent.setAction(ActivityTransitionBroadcastReceiver.INTENT_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
Task<Void> task = ActivityRecognition.getClient(context)
.requestActivityTransitionUpdates(request, pendingIntent);
Be aware that activity transition updates can be received delayed. This depends on the device and can also be affected by power management restrictions.
This is an old post, but this answer might help someone.
Keep in mind that latency might actually be the problem, as it was in my case. I thought my implementation wasn't working, but in reality it was. The Activity Transitions API just has a huge delay of about 1 minute to notify you of transitions. So try walking around or driving for a few minutes to start receiving notifications.
I faced similar issue but helped me add receiver to the manifest
<receiver
android:name=".service.ActivityTransitionReceiver"
android:permission="com.google.android.gms.permission.ACTIVITY_RECOGNITION"
android:exported="false" />
I also tried the aforementioned Codelab tutorial, as well as a few other examples, but none of them worked; BroadcastReceiver.onReceive() was never called, no matter how I set it up.
What did work was to use requestActivityUpdates() instead of requestActivityTransitionUpdates(). According to the document, requestActivityTransitionUpdates() is a better choice, because it improves accuracy and consumes less power, but it's not better choice for me if it doesn't do what it's supposed to do. Here is the summary on what I did.
[AndroidManifest.xml]
<receiver
android:name=".TransitionUpdatesBroadcastReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="TRANSITION_UPDATES" />
</intent-filter>
</receiver>
// This is in your Activity/Fragment.
private val pendingIntent: PendingIntent by lazy {
val intent = Intent(context, TransitionUpdatesBroadcastReceiver::class.java)
intent.action = TRANSITION_UPDATES
PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ActivityRecognition.getClient(context)
.requestActivityUpdates(1_000, pendingIntent) <-- Here.
}
override fun onDestroy() {
super.onDestroy()
ActivityRecognition.getClient(context)
.removeActivityUpdates(pendingIntent)
}
class TransitionUpdatesBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
// Do what you need to do with intent.
}
}
At some point it seems that the following intent for an explicit class stopped working (or maybe never worked?):
Intent intent = new Intent(context, ActivityDetectorTransitionService.class);
Instead, I created the intent by passing in the action in the intent constructor, as follows:
Intent intent = new Intent("com.test.activityrecognition.START_ACTIVITY_TRANSITION_DETECTION_ALARM");
...and then I started to get callbacks successfully from the Activity Transition API.
Note that this approach is used in the latest codelab as well:
https://github.com/googlecodelabs/activity_transitionapi-codelab/blob/master/complete/src/main/java/com/google/example/android/basicactivityrecognitiontransitionsample/MainActivity.java#L134
This is more of a doubt. Currently, my code works fine, but I want to make sure I'm doing it the right way.
I have a service, which checks if the activity is running on the foreground. If it is, it sends a broadcast to the activity, so the activity updates some stuff on the screen.
I created an IntentFilter on the service:
com.harkdev.ServerStatus.SERVER_UPDATED
Here the service needs to know if the activity is on the foreground, so it uses the IsActivityRunning() method, which reads the running tasks from the ApplicationManager. This means that I need to set the GET_TASKS permission.
Being that both, the SERVICE and the ACTIVITY are on the same package, is there a better way to get this info?? And maybe try and avoid setting the GET_TASKS permission??
This is the code in my service:
if (IsActivityRunning()) {
Intent localIntent = new Intent(SERVER_UPDATED);
SendBroadcast(localIntent, null);
}
The IsActivityRunning() Method:
public bool IsActivityRunning() {
ActivityManager manager = (ActivityManager) GetSystemService(ActivityService);
IList<ActivityManager.RunningTaskInfo> runningTaskInfo = manager.GetRunningTasks(1);
ComponentName componentInfo = runningTaskInfo[0].TopActivity;
if (componentInfo.PackageName == "com.harkdev.ServerStatus")
return true;
return false;
}
And this is the code in my activity:
protected override void OnCreate (Bundle bundle) {
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
IntentFilter filter = new IntentFilter(ServerStatusCheckService.SERVER_UPDATED);
_receiver = new ServiceBroadcastReceiver ();
_receiver.Received += Receiver_Received;
RegisterReceiver(_receiver, filter);
}
First you're doing the wrong way to compare strings:
if (componentInfo.PackageName == "com.harkdev.ServerStatus")
It should be:
if ("com.harkdev.ServerStatus".equals(componentInfo.PackageName))
Second, if the service and the activity are in your app then I think the requirement to check for "same package" is not necessary.
To send information from the service to the activity, you can use ResultReceiver (available in API 3+):
When starting your service from the activity, you create a ResultReceiver, put it into the intent which starts the service.
In the service, extract the ResultReceiver and keep it. When you want to send information, use send().
In the activity, for example in onDestroy() you can trigger a command to notify the service that the ResultReceiver is invalid and it should be removed.
Edied
For example:
In your activity:
// Global variable.
private ResultReceiver mResultReceiver = new ResultReceiver() {
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
// Update the UI here...
}
}
When you start the service:
Intent i = new Intent(this, TheService.class);
// You can use different action names for different commands.
i.setAction("REGISTER_RECEIVER");
i.putExtra("ResultReceiver", mResultReceiver);
i.putExtra("ResultReceiver_ID", hashCode());
startService(i);
And in onDestroy():
Intent i = new Intent(this, TheService.class);
i.setAction("UNREGISTER_RECEIVER");
i.putExtra("ResultReceiver_ID", hashCode());
startService(i);
In your service:
import android.util.SparseArray;
// ...
private SparseArray<ResultReceiver> mReceiverMap = new SparseArray<ResultReceiver>();
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if ("REGISTER_RECEIVER".equals(intent.getAction())) {
// Extract the ResultReceiver and store it into the map
ResultReceiver receiver = intent.getParcelableExtra("ResultReceiver");
int id = intent.getIntExtra("ResultReceiver_ID", 0);
mReceiverMap.put(id, receiver);
} else if ("UNREGISTER_RECEIVER".equals(intent.getAction())) {
// Extract the ResultReceiver ID and remove it from the map
int id = intent.getIntExtra("ResultReceiver_ID", 0);
mReceiverMap.remove(id);
}
// ...
}
How to use/locate LocalBroadcastManager as described in google docs and Service broadcast doc?
I tried to google it, but there is no code available to start with?
The documents say that I should use it if I want to do broadcast internally with in my app's process but I don't know where to look for this.
Any help/comment?
Update: I know how to use Broadcasts but don't know how to get LocalBroadcastManager available in my project.
I'll answer this anyway. Just in case someone needs it.
ReceiverActivity.java
An activity that watches for notifications for the event named "custom-event-name".
#Override
public void onCreate(Bundle savedInstanceState) {
...
// Register to receive messages.
// We are registering an observer (mMessageReceiver) to receive Intents
// with actions named "custom-event-name".
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("custom-event-name"));
}
// Our handler for received Intents. This will be called whenever an Intent
// with an action named "custom-event-name" is broadcasted.
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Get extra data included in the Intent
String message = intent.getStringExtra("message");
Log.d("receiver", "Got message: " + message);
}
};
#Override
protected void onDestroy() {
// Unregister since the activity is about to be closed.
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onDestroy();
}
SenderActivity.java
The second activity that sends/broadcasts notifications.
#Override
public void onCreate(Bundle savedInstanceState) {
...
// Every time a button is clicked, we want to broadcast a notification.
findViewById(R.id.button_send).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sendMessage();
}
});
}
// Send an Intent with an action named "custom-event-name". The Intent sent should
// be received by the ReceiverActivity.
private void sendMessage() {
Log.d("sender", "Broadcasting message");
Intent intent = new Intent("custom-event-name");
// You can also include some extra data.
intent.putExtra("message", "This is my message!");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
With the code above, every time the button R.id.button_send is clicked, an Intent is broadcasted and is received by mMessageReceiver in ReceiverActivity.
The debug output should look like this:
01-16 10:35:42.413: D/sender(356): Broadcasting message
01-16 10:35:42.421: D/receiver(356): Got message: This is my message!
I'd rather like to answer comprehensively.
LocalbroadcastManager included in android 3.0 and above so you have
to use support library v4 for early releases. see instructions
here
Create a broadcast receiver:
private BroadcastReceiver onNotice= new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// intent can contain anydata
Log.d("sohail","onReceive called");
tv.setText("Broadcast received !");
}
};
Register your receiver in onResume of activity like:
protected void onResume() {
super.onResume();
IntentFilter iff= new IntentFilter(MyIntentService.ACTION);
LocalBroadcastManager.getInstance(this).registerReceiver(onNotice, iff);
}
//MyIntentService.ACTION is just a public static string defined in MyIntentService.
unRegister receiver in onPause:
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(onNotice);
}
Now whenever a localbroadcast is sent from applications' activity or
service, onReceive of onNotice will be called :).
Edit: You can read complete tutorial here LocalBroadcastManager: Intra application message passing
On Receiving end:
First register LocalBroadcast Receiver
Then handle incoming intent data in onReceive.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
lbm.registerReceiver(receiver, new IntentFilter("filter_string"));
}
public BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
String str = intent.getStringExtra("key");
// get all your data from intent and do what you want
}
}
};
On Sending End:
Intent intent = new Intent("filter_string");
intent.putExtra("key", "My Data");
// put your all data using put extra
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
In Eclipse, eventually I had to add Compatibility/Support Library by right-clicking on my project and selecting:
Android Tools -> Add Support Library
Once it was added, then I was able to use LocalBroadcastManager class in my code.
localbroadcastmanager is deprecated, use implementations of the observable pattern instead.
androidx.localbroadcastmanager is being deprecated in version 1.1.0
Reason
LocalBroadcastManager is an application-wide event bus and embraces layer violations in your app; any component may listen to events from any other component.
It inherits unnecessary use-case limitations of system BroadcastManager; developers have to use Intent even though objects live in only one process and never leave it. For this same reason, it doesn’t follow feature-wise BroadcastManager .
These add up to a confusing developer experience.
Replacement
You can replace usage of LocalBroadcastManager with other implementations of the observable pattern. Depending on your use case, suitable options may be LiveData or reactive streams.
Advantage of LiveData
You can extend a LiveData object using the singleton pattern to wrap system services so that they can be shared in your app. The LiveData object connects to the system service once, and then any observer that needs the resource can just watch the LiveData object.
public class MyFragment extends Fragment {
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
LiveData<BigDecimal> myPriceListener = ...;
myPriceListener.observe(this, price -> {
// Update the UI.
});
}
}
The observe() method passes the fragment, which is an instance of LifecycleOwner, as the first argument. Doing so denotes that this observer is bound to the Lifecycle object associated with the owner, meaning:
If the Lifecycle object is not in an active state, then the observer
isn't called even if the value changes.
After the Lifecycle object is destroyed, the observer is
automatically removed
The fact that LiveData objects are lifecycle-aware means that you can share them between multiple activities, fragments, and services.
How to change your global broadcast to LocalBroadcast
1) Create Instance
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
2) For registering BroadcastReceiver
Replace
registerReceiver(new YourReceiver(),new IntentFilter("YourAction"));
With
localBroadcastManager.registerReceiver(new YourReceiver(),new IntentFilter("YourAction"));
3) For sending broadcast message
Replace
sendBroadcast(intent);
With
localBroadcastManager.sendBroadcast(intent);
4) For unregistering broadcast message
Replace
unregisterReceiver(mybroadcast);
With
localBroadcastManager.unregisterReceiver(mybroadcast);
When you'll play enough with LocalBroadcastReceiver I'll suggest you to give Green Robot's EventBus a try - you will definitely realize the difference and usefulness of it compared to LBR. Less code, customizable about receiver's thread (UI/Bg), checking receivers availability, sticky events, events could be used as data delivery etc.
Kotlin version of using LocalBroadcastManager:
Please check the below code for registering,
sending and receiving the broadcast message.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// register broadcast manager
val localBroadcastManager = LocalBroadcastManager.getInstance(this)
localBroadcastManager.registerReceiver(receiver, IntentFilter("your_action"))
}
// broadcast receiver
var receiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent != null) {
val str = intent.getStringExtra("key")
}
}
}
/**
* Send broadcast method
*/
fun sendBroadcast() {
val intent = Intent("your_action")
intent.putExtra("key", "Your data")
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
override fun onDestroy() {
// Unregister broadcast
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver)
super.onDestroy()
}
}
An example of an Activity and a Service implementing a LocalBroadcastManager can be found in the developer docs. I personally found it very useful.
EDIT: The link has since then been removed from the site, but the data is the following:
https://github.com/carrot-garden/android_maven-android-plugin-samples/blob/master/support4demos/src/com/example/android/supportv4/content/LocalServiceBroadcaster.java
enter code here if (createSuccses){
val userDataChange=Intent(BRODCAST_USER_DATA_CHANGE)
LocalBroadcastManager.getInstance(this).sendBroadcast(
userDataChange
)
enableSpinner(false)
finish()
By declaring one in your AndroidManifest.xml file with the tag (also called static)
<receiver android:name=".YourBrodcastReceiverClass" android:exported="true">
<intent-filter>
<!-- The actions you wish to listen to, below is an example -->
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
You will notice that the broadcast receiver declared above has a property of exported=”true”. This attribute tells the receiver that it can receive broadcasts from outside the scope of the application.
2. Or dynamically by registering an instance with registerReceiver (what is known as context registered)
public abstract Intent registerReceiver (BroadcastReceiver receiver,
IntentFilter filter);
public void onReceive(Context context, Intent intent) {
//Implement your logic here
}
There are three ways to send broadcasts:
The sendOrderedBroadcast method, makes sure to send broadcasts to only one receiver at a time. Each broadcast can in turn, pass along data to the one following it, or to stop the propagation of the broadcast to the receivers that follow.
The sendBroadcast is similar to the method mentioned above, with one difference. All broadcast receivers receive the message and do not depend on one another.
The LocalBroadcastManager.sendBroadcast method only sends broadcasts to receivers defined inside your application and does not exceed the scope of your application.
I am an iOS dev, so I made a solution similar to NotificationCenter:
object NotificationCenter {
var observers: MutableMap<String, MutableList<NotificationObserver>> = mutableMapOf()
fun addObserver(observer: NotificationObserver, notificationName: NotificationName) {
var os = observers[notificationName.value]
if (os == null) {
os = mutableListOf<NotificationObserver>()
observers[notificationName.value] = os
}
os.add(observer)
}
fun removeObserver(observer: NotificationObserver, notificationName: NotificationName) {
val os = observers[notificationName.value]
if (os != null) {
os.remove(observer)
}
}
fun removeObserver(observer:NotificationObserver) {
observers.forEach { name, mutableList ->
if (mutableList.contains(observer)) {
mutableList.remove(observer)
}
}
}
fun postNotification(notificationName: NotificationName, obj: Any?) {
val os = observers[notificationName.value]
if (os != null) {
os.forEach {observer ->
observer.onNotification(notificationName,obj)
}
}
}
}
interface NotificationObserver {
fun onNotification(name: NotificationName,obj:Any?)
}
enum class NotificationName(val value: String) {
onPlayerStatReceived("on player stat received"),
...
}
Some class that want to observe notification must conform to observer protocol:
class MainActivity : AppCompatActivity(), NotificationObserver {
override fun onCreate(savedInstanceState: Bundle?) {
...
NotificationCenter.addObserver(this,NotificationName.onPlayerStatReceived)
}
override fun onDestroy() {
...
super.onDestroy()
NotificationCenter.removeObserver(this)
}
...
override fun onNotification(name: NotificationName, obj: Any?) {
when (name) {
NotificationName.onPlayerStatReceived -> {
Log.d(tag, "onPlayerStatReceived")
}
else -> Log.e(tag, "Notification not handled")
}
}
Finally, post some notification to observers:
NotificationCenter.postNotification(NotificationName.onPlayerStatReceived,null)
we can also use interface for same as broadcastManger here i am sharing the testd code for broadcastManager but by interface.
first make an interface like:
public interface MyInterface {
void GetName(String name);
}
2-this is the first class that need implementation
public class First implements MyInterface{
MyInterface interfc;
public static void main(String[] args) {
First f=new First();
Second s=new Second();
f.initIterface(s);
f.GetName("Paddy");
}
private void initIterface(MyInterface interfc){
this.interfc=interfc;
}
public void GetName(String name) {
System.out.println("first "+name);
interfc.GetName(name);
}
}
3-here is the the second class that implement the same interface whose method call automatically
public class Second implements MyInterface{
public void GetName(String name) {
System.out.println("Second"+name);
}
}
so by this approach we can use the interface functioning same as broadcastManager.