How to pass class reference (not object) using Intent? - android

I have a scenario where there are multiple Activities and a Service.
All this Activities when need to get data from any URL, starts the Service (activity's class name is passed in Intent) and register a BroadcastReceiver to listen to responseIntent which will be sent by Service on getting the response. Service will pass the class name back in Intent along with response.
I have implemented this and it works. But the doubt is that from BroadcastReceiver's onReceive() method, how can I call a method of an activity which received a broadcast event?
Note : I want to deal with class reference but not an object. I tried this,
public void onReceive(Context context, Intent intent) {
Class<?> thisActivity = Class.forName(intent.getStringExtra("ClassName"));
thisActivity.hello(); // hello() is a public and static method
}
But it does not work.
Thank you.

You can't pass an object reference through an Intent. Imagine that Parcelable objects are just like Serializableobjects, their references are lost.
You should declare your BroadcastReceiver as an inner-class in your Activity, and then you will have a reference to the enclosing Activity. This is the way to do it.

You need to add the full package name to the 'ClassName' string, like this:
Class<?> thisActivity = Class.forName(intent.getStringExtra("com.android.youapp.ClassName"));
Note: if this class resides in a different library project you should set the string name accordingly.

How did you get your class name, which you are trying to extract from Intent's "ClassName"?
Preparing intent:
Intent i = new Intent(....);
String className = MyClass.class.getCanonicalName();
i.putExtra(CLASS_NAME, className);
Extracting intent content:
String canName = intent.getStringExtra(CLASS_NAME);
mClientClass = Class.forName(canName);
java.lang.reflect.Methodm m = mClientClass.getMethod("hello", new Class[] {});
Getting result:
Object result = m.invoke(mClientClass, new Object[] {});

Related

How do I pass data from Service to Activity in Kotlin?

Beginner warning although CS student
I have a Service named RestApiService and an activity named MainActivity.
I have a token which I got stored in RestApiService.
In link is screenshot of the RestApiService in imgur
https://imgur.com/a/Msu04xj
I only find tutorials in Java and I canĀ“t translate.
How do I get it from there to MainActivity? TIA
A way to do this is by using some database, store it there and then you can just observe the database on MainAcitivty level to get that value once its available.
An alternative would be to use shared preferences liveData which you will observe on MainActivity again but I guess that's a bit trickier
I would go with creating an entity which you will save in database using Room and then use a ViewModel component to expose liveData to the MainActivity
Easiest way- bind to the service, and define a Binder for the service with a function to get the value. Then you can just call that function to get the token. The Binder is returned to the Activity as the return from bindService().
Here's Google's example of doing so in kotlin: https://developer.android.com/guide/components/bound-services#kotlin
BroadCastReceiver will help you, in your service send a broadcast intent and in your activity you will receive your data.
You can use Local BroadcastReceiver for sending data from service to Activity
Please try this code in your RestApiService class where you get token:
val intent = Intent("RestApiData")
intent.putExtra("token", myToken)
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
In above code "RestApiData" is main key of broadcast receiver that you need for getting data in activity, "token" is key for myToken value
In Your MainActivity class use below code in onCreate method:
LocalBroadcastManager.getInstance(this).registerReceiver(tokenPassingReceiver, IntentFilter("RestApiData"))
Now use below code outside the onCreate method of activity:
private val tokenPassingReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val bundle = intent.extras
if (bundle != null) {
if (bundle.containsKey("token")) {
val tokenData = bundle.getString("token")
Log.e("MainActivity--","token--$tokenData")
}
}
}
}
For more information check this link: Kotlin Android Broadcast Intents and Broadcast Receivers
I hope it may help you.

Passing parameters to BroadcastReceiver subclass - Android

Pass additional parameters to a dynamically registered BroadcastReceiver.
The problem is basic: I want to pass parameters to a BroadcastReceiver. Can this be done? Even when the receiver is created dynamically?
Additionally, say I create an anonymous BroadcastReceiver i.e. as a variable implementation. Can I reference the encapsulating class variables? Check the code below for how I stop / start the file observer.
// Create the external media broadcast receiver.
mExternalMediaBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(final Context context, final Intent intent) {
// if action = media removed, stop the file observer.
EncapsulatingFragment.this.mFileObserver.stopWatching()
}
};
Is this valid?
Is this valid?
So long as the receiver has the same lifetime as EncapsulatingFragment.this, probably.
I want to pass parameters to a BroadcastReceiver. Can this be done? Even when the receiver is created dynamically?
Create an actual class and pass in the values to the constructor:
class WhateverReceiver extends BroadcastReceiver {
FileObserver mFileObserver;
WhateverReceiver(FileObserver observer) {
mFileObserver = observer;
}
#Override
public void onReceive(final Context context, final Intent intent) {
// if action = media removed, stop the file observer.
mFileObserver.stopWatching();
}
}
Then, in your fragment:
mExternalMediaBroadcastReceiver = new WhateverReceiver(mFileObserver);
All that being said... you might want to consider whether this logic should be implemented in your fragment. I/O-related stuff ideally lies outside of a fragment, such as in a repository object.

Pass string information from Fragment to BroadcastReceiver

I am using ACTION_UNINSTALL_PACKAGE to uninstall packages and am trying to retrieve the application name of the removed package after it is removed. I can only seem to get the package name. I cannot use ApplicationInfo on the package name since the package is already gone. I tried passing the value into the intent but since it goes to another activity that is not owned by me UninstallerActivity it is not there. I couldn't figure out how to pass the string into the IntentFilter data field since I need to use it for package name. I am not using sendBroadcast so I cannot use that.
#Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
intent.setData(Uri.parse("package:"+packageName));
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.PACKAGE_REMOVED");
intentFilter.addDataScheme("package");
mContext.registerReceiver(mUninstallReceiver, intentFilter);
startActivity(intent);
}
private BroadcastReceiver mUninstallReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action != null) {
if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
Uri intentData = intent.getData();
//the above only contains package name
}
}
}
}
How do I pass the application name to this broadcast receiver?
Update
I ended up just using a member variable which isn't what I totally wanted, but it works.
How do I pass the application name to this broadcast receiver?
Define your own custom subclass of BroadcastReceiver, where you supply a PackageManager to the constructor
Have that constructor gather whatever information it needs from the PackageManager
Create an instance of that BroadcastReceiver before you call startActivity()
Hold onto that BroadcastReceiver object somewhere so you can unregister it as soon as you receive your broadcast
If there is a possibility that the user might request to uninstall 2+ apps before the first uninstall completes, have onReceive() confirm that the broadcast it received is for the package it is tracking, as with this plan, you will have 2+ BroadcastReceiver objects outstanding at any point in time
There are other possible ways of organizing this (e.g., Map of package name to data, so you only need one receiver), but they will all be along the same lines: collect the data you need before you uninstall, so that you have the data by the time you receive the broadcast.

Android Broadcast from Service To Activity

I am trying to send a Broadcast from a service out to an Activity. I can verify the broadcast is sent from within the service, but the Activity doesn't pick up anything.
Here is the relevant service code:
Intent i = new Intent(NEW_MESSAGE);
i.putExtra(FriendInfo.USERNAME, StringUtils.parseBareAddress(message.getFrom()));
i.putExtra(FriendInfo.MESSAGE, message.getBody());
i.putExtra("who", "1");
sendBroadcast(i);
And the receiving end in the activity class:
public class newMessage extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
if(action.equalsIgnoreCase(IMService.NEW_MESSAGE)){
Bundle extra = intent.getExtras();
String username = extra.getString(FriendInfo.USERNAME);
String message = extra.getString(FriendInfo.MESSAGE);
String who = extra.getString("who");
}
}
}
The BroadcastReceiver is defined within an Activity. I am registering the receiver in the onCreate method of the Activity, not in the Manifest file.
I'm stumped as to why it won't rec. anything.
Any insight?
EDIT
Registering takes place as follows:
registerReceiver(messageReceiver, new IntentFilter(IMService.NEW_MESSAGE));
Where "messageReceiver" is defined as
private newMessage messageReceiver = new newMessage();
IMService.NEW_MESSAGE is merely a string = "NewMessage"
I'm not sure if it is specific to the set up, or if it is a fix in general, but moving the register/unregister to the onResume/onPause _respectively_ and not registering in the onCreate solved the problem for me.
Try this two things:
Use manifest file to register receiver(but it barely helps)
Try make your Receiver a regular class, not inner one.
Inner class broadcast receiver will not be able to handle broadcast(means it unable to locate that class ).
So make it as a separate class
Definitely it will work.

Android Communication between Broadcast Receiver and MainActivity (Send data to activity)

I've a simple Main Activity which has to stop till an SMS is received... How can I launch a method from the MainActivity within the BroadcastReceiver's onReceive() Method?
Is there away with Signal and Wait? Can I pass something with a pending Intent, or how can I implement this communication?
Communication from BroadcastReceiver to Activity is touchy; what if the activity is already gone?
If I were you I'd set up a new BroadcastReceiver inside the Activity, which would receive a CLOSE message:
private BroadcastReceiver closeReceiver;
// ...
closeReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//EDIT: receiving parameters
String value = getIntent().getStringExtra("name");
//... do something with value
finish();
}
};
registerReceiver(closeReceiver, new IntentFilter(CLOSE_ACTION));
Then from the SMS BroadcastReceiver you can send out this action:
Intent i = new Intent(CLOSE_ACTION);
i.putExtra("name", "value"); //EDIT: this passes a parameter to the receiver
context.sendBroadcast(i);
I hope this helps?
I had the exact same problem, I tried using intent but i was unsuccessful
The easiest way to use it would be using static methods and static variables
MainActivity.java
public static void stopsms()
{
/*
some code to stop the activity
*/
}
SMSReceiver.java
at the end call this function
MainActivity.stopsms();
It works amazing if your code does not affect when you use static methods and variables. Let me know if you need any help.
The problem with registering a second receiver within the activity, however, is that it will not be persistent like registering in the manifest... thus, although, this solution may work, will only work if the activity is running in background.
it's easy, use interface like that:
1) in your broadcast receiver create an interface.
public interface ChangeListener{
public void functionWhoSendData(String type);
public void etc();
}
and instantiate that interface in your broadcast receiver, use it:
public void onReceive(....
String data=functionWhereYouReceiveYouData();
ChangeListener.functionWhoSendData(data);
}
And in your activity, make it implements your interface

Categories

Resources