Receive broadcast in MainActivity with non static inner class - java

I need to call certain non static methods in an activity when the user interacts with buttons in notification, I tried to do it in a standalone class the extends BroadcastReceiver it works, but I don't know how call a method on the activity mentioned earlier, I tried to make an inner class, non static, edited the manifest file it was first :
<receiver android:name=".Activity$NotificationBroadcast" >
<intent-filter>
.
.
.
</intent-filter>
</receiver>
and that gives me an error saying :
FATAL EXCEPTION: main
Process: com.example.app, PID: 3189
java.lang.RuntimeException: Unable to instantiate receiver
com.example.app.Activity$NotificationBroadcast:
java.lang.InstantiationException:
the class is :
public class NotificationBroadcast extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent){
if (intent.getAction().equals(Activity.ACTION1)){
// do things
} else if (intent.getAction().equals(Activity.ACTION1)){
// do things
}else if (intent.getAction().equals(Activity.ACTION2)){
// do things
}else if (intent.getAction().equals(Activity.ACTION3)){
// do things
}else if (intent.getAction().equals(Activity.ACTION4)){
// do things
}
}
}

I'm afraid you can't make the receiver as an inner class, because when the receiver is statically instantiated, the "holder" class has to be instantiated as well. The activity instance is only created when it is meant to be active, and that's why you got the exception.
If you want the receiver to interact with the activity (by calling non-static methods in the activity class), I suggest that you should make the receiver a non-static one. This means that you need to register an instance of the receiver in OnCreate() and unregister it in OnDestroy().
For a better design, the activity instance should be passed into the receiver via its constructor as an interface, so that the receiver does not get access to the whole activity object, but is only able to access the functionality.
Manifest should have:
<receiver android:name=".NotificationBroadcast" android:enabled="false" />
An interface for the interaction (IWorker.java for example):
public interface IWorker {
public void doThis();
public void doThat();
}
The receiver (a class on its own) takes the IWorker and does something when a broadcast is received:
public class NotificationReceiver extends BroadcastReceiver {
public static final string ACTION1 = "com.yourpackage.action1";
public static final string ACTION2 = "com.yourpackage.action2";
private IWorker worker;
public NotificationReceiver() {
}
public NotificationReceiver(IWorker worker) {
this.worker = worker;
}
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION1)) {
worker.doThis();
} else if (intent.getAction().equals(ACTION2)) {
worker.doThat();
}
}
}
And the activity takes care of the receiver on its life cycle:
public class MyActivity extends Activity implements IWorker {
private NotificationReceiver receiver;
#override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// create the receiver
receiver = new NotificationReceiver(this);
IntentFilter filter = new IntentFilter();
filter.addAction(NotificationReceiver.ACTION1);
filter.addAction(NotificationReceiver.ACTION2);
// register it
registerReceiver(receiver, filter);
}
#override
protected void onDestroy() {
super.onDestroy();
if (receiver != null) {
unregisterReceiver(receiver);
receiver = null;
}
}
#override
public void doThis() {
System.out.println("Doing this...");
}
#override
public void doThat() {
System.out.println("Doing that...");
}
}
P.S. The above codes are for reference only, they're not tested and may not compile.

Related

BroadcastReceiver not called at launch

I need to detect when wired headset or a bluetooth one is plugged/connected so I create and register two BroadcastReceiver(s) like the following:
file ReceiverHeadsetWired.java
public class ReceiverHeadsetWired extends BroadcastReceiver {
ActivityMain main;
public ReceiverHeadsetWired(
ActivityMain activityMain
){
main = activityMain;
}
#Override
public void onReceive(
Context context,
Intent intent
) {
if (TextUtils.isEmpty(intent.getAction())) { return; }
if (Objects.equals(intent.getAction(), "android.intent.action.HEADSET_PLUG")) {
Log.d("[ReceiverHeadsetWired]", "onReceive()");
...
}
}
}
file ReceiverHeadsetBluetooth.java
public class ReceiverHeadsetBluetooth extends BroadcastReceiver {
ActivityMain main;
public ReceiverHeadsetBluetooth(
ActivityMain activityMain
){
main = activityMain;
}
#Override
public void onReceive(
Context context,
Intent intent
) {
if (TextUtils.isEmpty(intent.getAction())) { return; }
if (Objects.equals(intent.getAction(), "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED")) {
Log.d("[ReceiverHeadsetBluetooth]", "onReceive()");
...
}
}
}
Both of them are dynamically registered in onCreate method of MainActivity's Fragment and unregisterd onDestroy.
#Override
public void onCreate(
Bundle savedInstanceState
) {
super.onCreate(savedInstanceState);
ActivityMain main = (ActivityMain) getActivity();
...
registerHeadsetWiredReceiver();
registerHeadsetBluetoothReceiver();
...
}
private void registerHeadsetWiredReceiver() {
wiredHeadsetReceiver = new ReceiverHeadsetWired(main);
IntentFilter hwFilter = new IntentFilter("android.intent.action.HEADSET_PLUG");
main.registerReceiver(wiredHeadsetReceiver, hwFilter);
}
private void registerHeadsetBluetoothReceiver() {
bluetoothHeadsetReceiver = new ReceiverHeadsetBluetooth(main);
IntentFilter hbFilter = new IntentFilter("android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED");
main.registerReceiver(bluetoothHeadsetReceiver, hbFilter);
}
Now the point is that at launch only the onReceive of ReceiverHeadsetWired is called (Logcat shows the textline), but after app started both of them work as expected except a strange behaviour: the first time I connect a Bluetooth headset the related Log is written twice.
In other words when app is launched if a wired headset is plugged it will be detected but a connected bluetooth one won't.
Does anybody knows what's the problem?
Thanks in advance

Keep changes made by BroadcastReceiver

I'm stuck at this point:
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
String number = bundle.getString("Time");
GameTime.setText("" +number + " hours");
}
};
In another Activity, when a Button is pressed, the MainActivity get's an int.
Whenever I open the Activity, I cannot see the GameTime TextView with the number variable in it.
I know that the OnReceive method works, beacause I had put a toast in it, and I could see the toast after sending the int from the other Activity.
How can I keep the changes made to the TextView while changing Activities?
Thank you.
One way:
Define an interface in your activity & Implement the interface inside your activity and pass its reference to the other class and call that reference whenever you need.
Example:
a) Create an interface
public interface MyBroadcastListener{
public void doSomething(String result);
}
b) Initialize BroadCastReceiver
public class TestNotifAlarm extends BroadcastReceiver {
private MyBroadcastListener listener;
#Override
public void onReceive(Context context, Intent intent) {
listener = (MyBroadcastListener)context;
listener.doSomething("Some Result");
}
}
c) Implement the interface in Activity
public YourActivity extends AppCompatActivity implements MyBroadcastListener{
// Your Activity code
public void updateTheTextView(String t) {
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText(t);
}
#Override
public void doSomething(String result){
updateTheTextView(result); // Calling method from Interface
}
}
Another Way :
a) Put a Receiver inside your Activity class
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
textView.setText(intent.getStringExtra("extra"));
}
};
b) Register BroadCastReceiver
registerReceiver(broadcastReceiver , new IntentFilter("trigger_broadcust"));
c) Call sendBroadcast
Intent intent = new Intent("trigger_broadcust");
intent.putStringExtra("extra", "data");
sendBroadcast(intent);

Setting context on custom listener in a dialog

I created a very simple listener interface that looks like this:
public interface ReportDialogListener {
void shouldRemoveBlockedUser();
}
Now, in my ReportDialog class which is defined like this:
public class ReportDialog extends Dialog implements View.OnClickListener {}
I want to implement this listener and send callback for a certain action. However, when I do send callback after a certain action... my mDialogListener variable is null.
Where do I set the context?
This is what I tried:
private ReportDialogListener mDialogListener;
#Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
try {
mDialogListener = (ReportDialogListener) getContext();
} catch (ClassCastException e) {
}
}
#Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
mDialogListener = null;
}
But when I call mDialogListener.shouldRemoveBlockedUser();, mDialogListener is null...
Also- I made sure my main activity was implementing ReportDialogListener... thanks
Implement Listener in MainActivity
Public class MainActivity implements ReportDialogListener {
ReportDialogListener reportDialogListener ;
public void onCreate(Bundle saveInstanceState){
reportDialogListener =this;
}
#override
public void shouldRemoveBlockedUser(){
}
}
Pass reportDialogListener object to other class or activity and call the listener method reportDialogListener.shouldRemoveBlockedUser();
If this main activity implements the interface, do not use the activity context. Use this instead. mDialogListener = this;
Also i do not see where you implement the interface,only the View onClick interface you have actually implemented.
public class ReportDialog extends Dialog implements View.OnClickListener
to
public class ReportDialog extends Dialog implements View.OnClickListener,ReportDialogListener
To implement the interface in another, either you define it in the constructor of the calling program, or devise a method that does it.
Since my main activity was actually sending this when creating an instance of ReportDialog :
if (mReportDialog == null) {
mReportDialog = new ReportDialog(this);
}
I was able to assign it to a variable in the constructor of ReportDialog
public ReportDialog(Activity activity) {
super(activity);
mActivity = activity;
init();
}
Then, use it like this:
mDialogListener = (ReportDialogListener) mActivity;
Works perfectly.

Attach and instantiate Service into Application.java

I am trying attach and instantiate a variable that is a Service, before start the first Activity.
I am trying this:
Application.java
public class ApplicationBase extends Application {
public ServiceDoSport mServiceDoSport;
#Override
public void onCreate() {
startService(new Intent(this, ServiceDoSport.class));
super.onCreate();
}
}
ServiceDoSport.java:
public class ServiceDoSport extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
// attach service to main application
ApplicationBase mApplication = (ApplicationBase) getApplication();
mApplication.mServiceDoSport = this;
}
}
But the onCreate method of the first Activity is called before than Service has been attached and instantiated to ApplicationBase.
How I can do this?
What I doing wrong?
I am trying attach and instantiate a variable that is a Service, before start the first Activity
You cannot guarantee that will happen. startService() is asynchronous, and you have no way to guarantee that it will start before an activity does.

Implementing a listener for multiple event listeners of different classes (activity, fragment, etc), in Android

MyApplication application class has a listener that notifies an event listener (MainActivity - fragment activity) when fetchUpdates method is called.
Setup (showing only relavant part):
(1) MyApplication
public class MyApplication extends Application {
OnFetchStartListener mCallbackFetchStart = null;
public void setOnFetchStartListener(Activity activity) {
try {
mCallbackFetchStart = (OnFetchStartListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFetchStartListener");
}
}
public interface OnFetchStartListener {
public void onFetchStartListener();
}
public synchronized void fetchUpdates() {
// Informing listeners on fetchUpdates() start
if (mCallbackFetchStart != null) {
mCallbackFetchStart.onFetchStartListener();
}
String[] mURLs = getURLs();
new DownloadDataAsyncTask().execute(mURLs[0], mURLs[1]);
}
}
(2) MainActivity - FragmentActivity:
public class MainActivity extends SherlockFragmentActivity implements
MyApplication.OnFetchStartListener
static MyApplication myApp;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myApp = (MyApplication) getApplication();
}
#Override
protected void onResume() {
myApp.setOnFetchStartListener(this);
super.onResume();
}
#Override
public void onFetchStartListener() {
//Some stuff
}
}
Question
How can I setup the listener in the application class to notify multiple event listeners? The event listeners may be of different classes, not just FragmentActivities.
I can create different listeners in the application class to notify different event listeners (a listener in the application class for each event listener) when fetchUpdates is called, but this doesn't strike me as very efficient.
About me
I just started programming. So detailed explanations are much appreciated.
Progress
Rciovati Suggested using EventBus. This solution might work, but will have to introduce a new (third-party) library in to the project.
I'm still looking for a solution without having to use a third-party library.

Categories