I have a broadcast receiver in my app which is fired every time the user gets an incoming call. Now, when it happens, I need the broadcast receiver to invoke a specific method in a specific activity. Now, I tried to make this method static and therefore available, but something tells me it is a very bad idea.
Accordingly, I tried to instantiate the broadcast receiver inside my activity without declaring it in my manifest but the problem is - when the app is off, the activity dosn't exist and therefore I can't invoke my method.
So my question is - How can I invoke this method when the broadcast receiver is fired up, without making it "public static"?
Here is my activity code(I have deleted the irrelevant parts)
package com.silverfix.ringo.activities;
import com.silverfix.ringo.R;
import com.silverfix.ringo.activities.fragments.DataManagerFragment;
import android.app.ActionBar;
import android.app.Activity;
import android.app.FragmentTransaction;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
public class RingtonesActivity extends Activity{
private DataManagerFragment dataManagerFragment;
private IntentFilter filter;
private BroadcastReceiver phoneCall;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ringtones);
ActionBar ab = getActionBar();
ab.setDisplayShowTitleEnabled(false);
ab.setDisplayHomeAsUpEnabled(true);
dataManagerFragment = new DataManagerFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(dataManagerFragment, "DataManagerFragment");
ft.commit();
filter = new IntentFilter();
filter.addAction("android.intent.action.PHONE_STATE");
phoneCall = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
dataManagerFragment.act();
}
};
registerReceiver(phoneCall, filter);
}
}
You can use observers , like
public class MyReceiver extends BroadcastReceiver {
public MyReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
ObservableObject.getInstance().updateValue(intent);
}
}
public class MainActivity extends Activity implements Observer {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ObservableObject.getInstance().addObserver(this);
}
#Override
public void update(Observable observable, Object data) {
Toast.makeText(this, String.valueOf("activity observer " + data), Toast.LENGTH_SHORT).show();
}
}
public class ObservableObject extends Observable {
private static ObservableObject instance = new ObservableObject();
public static ObservableObject getInstance() {
return instance;
}
private ObservableObject() {
}
public void updateValue(Object data) {
synchronized (this) {
setChanged();
notifyObservers(data);
}
}
}
Receiver can be used via manifest.
ObservableObject - must be singleton.
This might help: how can I notify a running activity from a broadcast receiver?
Also, you can try using Observers
Something like:
public class BroadcastObserver extends Observable {
private void triggerObservers() {
setChanged();
notifyObservers();
}
public void change() {
triggerObservers();
}
}
In your broadcast receiver:
#Override
public void onReceive(Context context, Intent intent) {
BroadcastObserver bco = new BroadcastObserver();
bco.change();
}
and the Activity:
public class YourActivity extends Activity implements
Observer {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BroadcastObserver bco = new BroadcastObserver();
bco.addObserver(this);
}
#Override
public void update() {
//TODO: call your desired function
}
}
If anyone needs two-way communication between a BroadcastReceiver and a Activity, I wrote this utility class which simplifies invoking Methods on each other while still being memory-safe.
https://gist.github.com/Jenjen1324/4a0c03beff827082cb641fc8fe2c4e71
Related
I have a class which doesn't extend Activity or Fragment. It is a independent class. I would like to use that class to control an Activity start and finish.
public class MyActivityManager() {
public MyActivityManager(Context context) {
mContext = context;
}
public void startMainActivity() {
Intent intent = new Intent(mContext, MainActivity.class);
mContext.startActivity(intent);
}
public void closeMainActivity() {
// how can I close the started main activity from the other function here?
}
}
As you can see, I started MainActivity from one function, and in another function, I would like to close the MainActivity started. But how can I have a reference to the started MainActivity?
(My main purpose is to let upper caller to use this MyActivityManager to start and close MainActivity)
If the current way is not possible, how to achieve what I want?
//Try the below code and let me know if any issues.
package com.example.raghavendrapai.myapplication;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
registerReceiver(mCloseReceiver, new IntentFilter("close_main_activity"));
}
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mCloseReceiver);
}
private BroadcastReceiver mCloseReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("close_main_activity")) {
finish();
}
}
};
}
// And in your class
package com.example.raghavendrapai.myapplication;
import android.content.Context;
import android.content.Intent;
/**
* Created by raghavendra.pai on 08/03/18.
*/
public class MyActivityManager {
private Context mContext;
public MyActivityManager(Context context) {
mContext = context;
}
public void startMainActivity() {
Intent intent = new Intent(mContext, MainActivity.class);
mContext.startActivity(intent);
}
public void closeMainActivity() {
Intent intent = new Intent("close_main_activity");
mContext.sendBroadcast(intent);
}
}
Using Android LiveData I'd like to be able to unregister and register many BroadcastReceivers in the onInactive() and onActive() call backs. So I want to do something like this:
public class BroadcastRecieverLiveData extends LiveData<BroadCastReciever> {
private BroadcastReciever reciever;
private Context context;
public BroadcastRecieverLiveData(Context context) {
this.context = context;
}
#Override
protected void onActive() {
IntentFilter filter = new IntentFilter();
filter.addAction("SOME_ACTION");
filter.addAction("SOME_OTHER_ACTION");
reciever = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//do something based on the intent's action
}
};
registerReceiver(reciever, filter);
}
#Override
protected void onInactive() {
if (reciever != null) {
context.unregisterReceiver(reciever);
}
}
}
I was thinking this could be a design pattern to be clean up of code instead of relaying on onDestroy. What are your thoughts on using LiveData this way? There is an example of using it here
I think for receivers, you should implement LifecycleObserver.
As per LiveData documentation from Google codelab,
Caution: Storing a reference to a Context or View in a ViewModel can
result in memory leaks. Avoid fields that reference instances of the
Context or View classes. The onCleared() method is useful to
unsubscribe or clear references to other objects with a longer
lifecycle, but not for clearing references to Context or View objects.
So, You should not do context intensive operation in LiveData.
Instead, take an example of below implementation,
import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleObserver;
import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.OnLifecycleEvent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
public class ReceiverManager implements LifecycleObserver {
private final Context mContext;
private final MyBrodacastReceiver myBrodacastReceiver;
public ReceiverManager(LifecycleOwner lifecycleOwner,
Context context) {
mContext = context;
myBrodacastReceiver = new MyBrodacastReceiver();
lifecycleOwner.getLifecycle().addObserver(this);
}
#OnLifecycleEvent(Lifecycle.Event.ON_START)
void registerYourReceiver() {
mContext.registerReceiver(myBrodacastReceiver, new IntentFilter());
}
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void unRegisterYourReceiver() {
mContext.unregisterReceiver(myBrodacastReceiver);
}
private static class MyBrodacastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
}
}
}
Thanks.
Trust me I have spent so much time searching for solutions but it doesnt seem to work for me. I have a really simple code where i would like my phone to discover bluetooth devices (yet). Here is the code (processing).
import android.app.Application;
import android.app.Activity;
import android.os.Bundle;
import android.content.IntentFilter;
import android.content.Intent;
import android.content.Context;
import android.content.BroadcastReceiver;
import java.util.Set;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
BluetoothAdapter BT = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> pairedDevices = BT.getBondedDevices();
BroadcastReceiver BCR = new BroadcastReceiver2();
void setup(){
BT.enable();
registerReceiver(BCR, new IntentFilter(BluetoothDevice.ACTION_FOUND));
if(!BT.isDiscovering()) BT.startDiscovery();
}
void draw(){
//
}
public class BroadcastReceiver2 extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent){
disDevName = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
print("Discovered: ");
println(disDevName);
if(disDevName == "XCHAN_PC") BTFound = true;
}
}
Here is the error:
The function "registerReceiver(BroadcastReceiver, IntentFilter)" does not exist
This is because PApplet has no registerReceiver method but instead, in Context. But I do not know how to get the context. I tried puting this code:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
and get the context out using this:
MainActivity act = new MainActivity();
con = act.getApplicationContext();
//...
//then this
con.registerReceiver(BCR, new IntentFilter(BluetoothDevice.ACTION_FOUND));
of it but it would say "Null Context".
Any help would be very appreciated.
try this
In your Activity class:
public class MyActivity extends Activity {
private MyClass myClass = null; //MyClass is your bluetooth utility class
#Override
public void onResume(Bundle savedInstanceState) {
super.onResume(savedInstanceState);
// ...pass context
myClass = new MyClass(this);
}
#Override
public void onPause() {
if (myClass != null) {
myClass.unregisterReceiver(this);
myClass = null;
}
super.onPause();
}
}
Now in your MyClass use:
public class MyClass {
private BroadcastReceiver myReceiver = null;
public MyClass(Context context) {
myReceiver = new MyBroadcastReceiver();
context.registerReceiver(myReceiver, new IntentFilter(
BluetoothDevice.ACTION_ACL_CONNECTED));
context.registerReceiver(myReceiver, new IntentFilter(
BluetoothDevice.ACTION_ACL_DISCONNECTED));
context.registerReceiver(myReceiver, new IntentFilter(
BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED));
}
public void unregisterReceiver(Context context) {
context.unregisterReceiver(this);
}
}
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
// do some stuff
}
}
}
I have a BroadcastReceiver which receives broadcast sent to a Fragment.
I'm getting the broadcast but how can I call a method from the Fragment itself?
I basically need to update a List once the broadcast arrives, the List & update method are part of the Fragment.
public class FragmentReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action != null && action.equals("AllTasksFragmentUpdate"))
{
//
}
}
}
Registering the receiver:
#Override
public void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
getActivity().registerReceiver(new FragmentReceiver(), new IntentFilter("AllTasksFragmentUpdate"));
}
How can I call the method from the Fragment?
You can implement your broadcast reciever in the following way:
import android.app.Fragment;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.adobe.libs.connectors.R;
public class YourFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater,
#Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
//Start listening for refresh local file list LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mYourBroadcastReceiver,
new IntentFilter(<YOUR INTENT FILTER>));
return inflater.inflate(R.layout.your_fragment_layout, null, true);
}
#Override
public void onDestroyView() {
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mYourBroadcastReceiver);
}
private final BroadcastReceiver mYourBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Now you can call all your fragments method here
}
};
}
In your onReceive() method, you can find your fragment by its tag name (the name using which you instantiated your fragment) and call its public method.
SampleFragment fragment = (SampleFragment) getSupportFragmentManager().findFragmentByTag(<fragment_tag_name>);
if (fragment != null && fragment.isAdded()) {
fragment.method(); //Call any public method
}
Hope this helps !
Supposing that you have an Activity named MyActivity and at some point in your code, you want to make a broadcast to be received by a Fragment named MyFragment. You can do it like this:
In MyActivity, use LocalBroadcastManager to make the broadcast with a filter:
String filter = "thisIsForMyFragment";
Intent intent = new Intent(filter); //If you need extra, add: intent.putExtra("extra","something");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
In MyFragment, inside onCreateView() add this to register the receiver:
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(myBroadcastReceiver,
new IntentFilter("thisIsForMyFragment"));
Following, In MyFragment (outside onCreateView()) create the receiver method to receive the broadcast:
private final BroadcastReceiver myBroadcastReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, android.content.Intent intent) {
Toast.makeText(getActivity(), "Broadcast received!", Toast.LENGTH_SHORT).show();//Do what you want when the broadcast is received...
}
};
Finally, in MyFragment add this to unregister the receiver onDestroyView:
#Override
public void onDestroyView()
{
super.onDestroyView();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(myBroadcastReceiver);
}
activity!!.registerReceiver(receiver, IntentFilter(DataKeys.STATUS))
Anyone know if I can receive my main Activity's onStop, onPause and onResume callbacks inside another class / object?
I've got a broadcast receiver that lives inside another class (a WebView). I use the receiver to detect when the network goes down and switch to a local copy of my page with some useful content. I need to un-register the broadcast receiver when onStop/onPause are called and re-register it during onResume.
I can do this by hand (I added a couple public methods to a class that extends WebView to do just that) , but it'd be nice to have Android just call it for me.
edit: Sure, here's the class, I'd like it to be able to receive get a callback from Android when my main activity's onStop gets called without having to call startInternetMonitoring() / stopInternetMonitoring():
package com.glimmersoft.spent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.util.AttributeSet;
import android.util.Log;
import android.webkit.WebSettings;
import android.webkit.WebView;
/**
* #author Jer
*
*/
public class OfflineWebView extends WebView {
private BroadcastReceiver receiver;
private IntentFilter filter;
private Context myContext;
public OfflineWebView(Context context,AttributeSet attrs) {
super(context, attrs);
WebSettings webSettings = this.getSettings();
webSettings.setJavaScriptEnabled(true);
myContext = context;
}//END CLASS CONSTRUCTTOR
/**
* #param internetOn The URL to display in this OfflineWebView when there is an active Internet connection.
* #param internetOff The URL to display in this OfflineWebView if there is no active Internet connection.
*/
public void setPages(final String internetOn, final String internetOff){
final OfflineWebView finalThisRef = this;
filter = new IntentFilter();
filter.addAction(SpendConstants.ANDROID_CONNECTIVITY_CHANGED);
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager cm=(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if(cm.getActiveNetworkInfo()!=null&&cm.getActiveNetworkInfo().isConnected()){// TODO: THIS FAILES IF
finalThisRef.loadUrl(internetOn);
}else{
finalThisRef.loadUrl(internetOff);
}
}//END IF/ELSE
};
myContext.registerReceiver(receiver, filter);
}//END FUNCTION SETPAGES
public void startInternetMonitoring(){
myContext.registerReceiver(receiver, filter);
}//END METHOD STARTINTERNETMONITORING
public void stopInternetMonitoring(){
myContext.unregisterReceiver(receiver);
}//END METHOD STOPINTERNETMONITORING
}//END CLASS OfflineWebView
Thanks all!
Instead of putting your BroadcastReceiver inside your OfflineWebView, make it a static class you register maybe in a base Activity and have it a hold a reference to your OfflineWebView. When onReceive is called, you can then reference your OfflineWebView to load your online/offline content.
file: MyBaseActivity.java
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.webkit.WebView;
public class MyBaseActivity extends Activity {
private static final String ANDROID_CONNECTIVITY_CHANGED = "android.net.conn.CONNECTIVITY_CHANGE";
protected static final ConnectivityBroadcastReceiver sReceiver = new ConnectivityBroadcastReceiver();
private static final IntentFilter sFilter = new IntentFilter(ANDROID_CONNECTIVITY_CHANGED);
static class ConnectivityBroadcastReceiver extends BroadcastReceiver {
private String internetOnUrl = "your online url";
private String internetOffUrl = "your offline url";
WebView offlineWebView;
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager cm = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
// only do your online/offline loading if we have a webview set
if (offlineWebView != null) {
if (cm.getActiveNetworkInfo() != null
&& cm.getActiveNetworkInfo().isConnected()) {
offlineWebView.loadUrl(internetOnUrl);
} else {
offlineWebView.loadUrl(internetOffUrl);
}
}
}
}
#Override
public void onStart() {
super.onStart();
// register receiver
registerReceiver(sReceiver, sFilter);
}
#Override
public void onStop() {
super.onStop();
// unregister receiver
unregisterReceiver(sReceiver);
}
}
file: MyActivity.java
import android.R;
import android.os.Bundle;
import android.webkit.WebView;
public class MyActivity extends MyBaseActivity {
private WebView mWebView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// load your content root
setContentView(R.layout.main_layout);
// find your webview
mWebView = (WebView)findViewById(R.id.webView);
}
#Override
public void onStart() {
super.onStart();
// set your webview in the OfflineBroadcastReceiver
sReceiver.offlineWebView = mWebView;
}
#Override
public void onStop() {
super.onStop();
// clear your webview from the OfflineBroadcastReceiver
sReceiver.offlineWebView = null;
}
}