Here I am creating an online application that depends only on Internet.
So whenever there is a network error it must notify user. For that, I have created a BroadcastReciver that receives call when network connection gets lost(Internet).
All this works perfectly. Now what I need is that I have to call a method of Activity from this Broadcast Receiver, where I have created an Alert Dialogue.
I have read many answers on stack-overflow.com that I can declare that method static and call by using only Activity name,
e.g MyActivityName.myMethod()
But I can't declare my method static, because I am using Alert Dialogue there and it shows me error on line,
AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
that Cannot use this in a static context.
So, how can I call a method of Activity(must not static and without starting that activity) from a Broadcast Receiver ?
And can I get Activity(or fragment) name from Broadcast Receiver which is currently running?
try this code :
your broadcastreceiver class for internet lost class :
public class InternetLostReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
context.sendBroadcast(new Intent("INTERNET_LOST"));
}
}
in your activity add this for calling broadcast:
public class TestActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
registerReceiver(broadcastReceiver, new IntentFilter("INTERNET_LOST"));
}
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// internet lost alert dialog method call from here...
}
};
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(broadcastReceiver);
}
}
INTERFACE: Keep BroadCastReceiver and Activity code separate!
You can make a CallBackListener interface. The interface will work as a bridge between BroadcastReceiver and Activity.
1) Create a CallbackListener
interface ConnectionLostCallback{
public void connectionLost();
}
2) Provide ConnectionLostCallback in your BroadcastReceiver
public class MyBroadcastReceiver extends BroadcastReceiver{
private ConnectionLostCallback listener;
public MyBroadcastReceiver(ConnectionLostCallback listener ){
this.listener = listener //<-- Initialze it
}
#Override
public void onReceive(Context context, Intent intent) {
listener.connectionLost();
}
}
3) Implement the ConnectionLostCallback in your Activity and override the method
YourActvity extends AppcompatActivity implements ConnectionLostCallback{
// Your Activity related code //
// new MyBroadcastReceiver(this); <-- create instance
private void showAlertMessage(){
AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
}
#Override
public void connectionLost(){
showAlertMessage(); //<--- Call the method to shoe alert dialog
}
}
Relevant link:
If you want to know how to make a BroadcastReceiver independent of any
activity ie How can you reuse the same BroadCastReceiver with
different Activities? Then READ THIS
Add a boolean variable in you activity from where you are open alertdialog
boolean isDialogOpened = false;
// in broadcast recever check
if(isDialogOpened) {
alertDialog();
}
And replace your code for alertdialog with this one
public void alertDialog() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
alertDialog.setMessage("Network not found.");
alertDialog.setPositiveButton("Check Setting",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
alertDialog.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
alertDialog.setOnDismissListener(new OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
isDialogOpened = false;
}
});
alertDialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
isDialogOpened = false;
}
});
alertDialog.show();
}
Pass your Activity's context to BroadcastReceiver's contructor.
public class ResponseReceiver extends BroadcastReceiver{
MainActivity ma; //a reference to activity's context
public ResponseReceiver(MainActivity maContext){
ma=maContext;
}
#Override
public void onReceive(Context context, Intent intent) {
ma.brCallback("your string"); //calling activity method
}
}
and in your MainActivity
public class MainActivity extends AppCompatActivity {
...
public void onStart(){
...
ResponseReceiver responseReceiver = new ResponseReceiver(this); //passing context
LocalBroadcastManager.getInstance(this).registerReceiver(responseReceiver,null);
...
}
public void brCallback(String param){
Log.d("BroadcastReceiver",param);
}
}
hope it helps
Use lambdas. A Consumer would do.
protected void onCreate(Bundle savedInstanceState) {
...
receiver = new LocationBroadcastReceiver((whatever) -> doSomething(whatever));
registerReceiver(receiver, new IntentFilter("YOUR_MESSAGE"));
}
Where doSomething will be a method in your Activity.
...
class YourBroadcastReceiver extends BroadcastReceiver {
private Consumer<Whatever> callback;
public LocationBroadcastReceiver(Consumer<Whatever> callback) {
this.callback = callback;
}
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
public void onReceive(Context context, Intent intent) {
this.callback.accept(new Whatever());
}
}
Is the alternative to all the other:
declare that method static and call by using only Activity name.
Apart from what you explained, that's a way of coupling.
pass your Activity's context to BroadcastReceiver's contructor.
That wouldn't work because you want to call a method that's not part of AppCompatActivity. And yeah, you could downcast, but then you end up coupled to your activity.
using another Broadcast or a Local Broadcasts instead
Well, you can only pass a bunch of primitives that way. What if you want to pass an object? Also, declaring a new BroadcastReceiver get quite verbose and maybe hard to follow.
Same as Vijju' s answer but using Local Broadcasts instead
public class SampleReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent intentToBroadcast = new Intent("YOUR_ACTION_HERE");
LocalBroadcastManager.getInstance(context).sendBroadcast(intentToBroadcast);
}
}
In your activity add this
public class SampleActivity extends Activity {
#Override
protected void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(this).registerReceiver(mSampleReceiver, new IntentFilter(YOUR_ACTION_HERE));
}
#Override
protected void onPause() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mSampleReceiver);
super.onPause();
}
private SampleReceiver mSampleReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// your code here
}
};
}
Note Move the register/unregister calls to onCreate/onDestroy is you want to be notified even when your activity is in the background.
Related
I have placed the back button in the action bar for navigating between activities
and I want to set on back pressed of the mobile phone from any activity user exits the app.
I can define this explicitly in each activity but I want to write it in one place to avoid writing the same piece of code in each activity.
Is there some way to do so?
You should create BaseActivity extends Activity with your logic about back button and where you need the same behaviour simply extends BaseActivity
You can also add a tag in manifest for all activities like,
<activity
android:name="com.example.shoppingapp.AddNewItems"
android:label=""
android:noHistory="true">
To exit the app from any activity by giving warning to user,
I have implemented BaseActivity class as below:
public class BaseActivity extends AppCompatActivity {
public static String ACTIVITY_FINISH_ACTION = "my.activities.finish.action";
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
registerBroadCastReceiver();
}
private BroadcastReceiver mFinishReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() != null && intent.getAction().equals(ACTIVITY_FINISH_ACTION)) {
new AlertDialog.Builder(BaseActivity.this)
.setTitle("Warning")
.setMessage("Do you really want to exit?")
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.finishAffinity(BaseActivity.this);
finish();
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
}
}
};
private void registerBroadCastReceiver() {
registerReceiver(mFinishReceiver, new IntentFilter(ACTIVITY_FINISH_ACTION));
}
private void unRegisterBroadCastReceiver() {
unregisterReceiver(mFinishReceiver);
}
#Override
protected void onDestroy() {
super.onDestroy();
unRegisterBroadCastReceiver();
}
}
Extend this BaseActivity class to each class and override onBackPressed() method as below:
#Override
public void onBackPressed() {
Intent intent = new Intent();
intent.setAction(BaseActivity.ACTIVITY_FINISH_ACTION);
sendBroadcast(intent);
}
Add below code in your BaseActivity. It will work as expected for each activity that will extend BaseActivity.
#Override
public void onBackPressed() {
finishAffinity();
finish();
}
First Create BaseActivity like below:
public class BaseActivity extends AppCompatActivity {
public static String ACTIVITY_FINISH_ACTION = "my.activities.finish.action";
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
registerBroadCastReceiver();
}
private BroadcastReceiver mFinishReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction() != null && intent.getAction().equals(ACTIVITY_FINISH_ACTION)) {
finish();
}
}
};
private void registerBroadCastReceiver() {
registerReceiver(mFinishReceiver, new IntentFilter(ACTIVITY_FINISH_ACTION));
}
private void unRegisterBroadCastReceiver() {
unregisterReceiver(mFinishReceiver);
}
#Override
public void onBackPressed() {
Intent intent = new Intent();
intent.setAction(BaseActivity.ACTIVITY_FINISH_ACTION);
sendBroadcast(intent);
}
#Override
protected void onDestroy() {
super.onDestroy();
unRegisterBroadCastReceiver();
}
}
Then extend your each activity with BaseActivity and on your back button press, send the broadcast like below:
Intent intent = new Intent();
intent.setAction(BaseActivity.ACTIVITY_FINISH_ACTION);
sendBroadcast(intent);
I have an activity class A for the layout and a non-activity class B for Location Request; the class B triggers some events like onConnectionSuspended and i want to get these back in the classe A. How can i do that ?
Thank you for the previous answers, i worked on it but i add some details.
I want to separate the Activity code from the GoogleApi.Connection code. To do that i made a non-activity class (maybe a service is better ?) with Connection code (see the structure code below).
1) Is it a good idea ?
2) If it is not, what is better to do (maybe put all in the same Activity ?) ?
3) If it is yes, i don't think that i can put some "Toast" in the connections events of my non-activity code so how can i get back the connections events in the Activity to display some messages ?
Thank you for the answers
import android.os.Bundle;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
public class SATlocation implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{
#Override
public void onConnected(Bundle bundle) {
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
}
As an alternative to broadcast receivers, if you have access to your class B instance from your Activity, you can also create an interface for listening to those events.
public interface LocationRequestEventListener {
void onConnectionSuspended();
...
}
public class SomeActivity extends Activity implements LocationRequestEventListener {
private ClassB classB;
#Override
public void onCreate() {
...
classB.setListener(this);
}
...
#Override
void onConnectionSuspended() {
//react to the event here
}
}
public class ClassB {
private LocationRequestListener listener;
....
public void setListener(LocationRequestListener listener) {
this.listener = listener;
}
private void connectionSuspended() {
// suppose this is where your class fire the event of interest
if (listener != null) {
listener.onConnectionSuspended();
}
}
}
use Local broadcast receiver add receiver in your activity as below
private BroadcastReceiver onNotice = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// intent can contain anydata
}
}
inside onresume register receiver as below
protected void onResume() {
super.onResume();
IntentFilter intentFilter = new IntentFilter(MyIntentService.ACTION);
LocalBroadcastManager.getInstance(this).registerReceiver(onNotice, intentFilter);
}
unRegister receiver in onPause
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(onNotice);
}
In your location service add following code to send local broadcast
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);
I have a function in activity I want to run this function with broadcastreceiver. How can I make this?
public class Myclass extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
}
}
This is my broadcastreceiver class I want to run function which is in my activty please tell me with some code how to do this.
If the method you want to execute needs your activity instance, then you can register the broadcast receiver inside your activity, so it can access your activity's state and functions.
In your Activity "onCreate" method:
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("Your Intent action here");
intentFilter.addAction("Another action you want to receive");
final BroadcastReceiver myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
theFunctionYouWantToExecute();
}
};
registerReceiver(myReceiver, intentFilter);
And in your "onDestroy" method:
unregisterReceiver(myReceiver);
Keep in mind that in this case your broadcast receiver has full access to your activity state, BUT it's lifecycle will be conditioned to the activity lifecycle.
Another option you have is to declare your activity method as static, so you can execute it in any part of your application.
You can declare an interface in Myclass and implement it in your MainActivity
public class Myclass extends BroadcastReceiver{
public interface MyClassInterface {
void onMyClassReceive();
}
private MyClassInterface mListener;
public Myclass(MyClassInterface mMyClassInterface) {
mListener = mMyClassInterface;
}
#Override
public void onReceive(Context context, Intent intent) {
mListener.onMyClassReceive();
}
}
Then in your MainActivity:
public class MainActivity implements Myclass.MyClassInterface {
private mMyClass Myclass = new Myclass(this);
#Override
public void onMyClassReceive() {
// Do stuff when Myclass.onMyClassReceive() is called,
// which will be called when Myclass.onReceive() is called.
}
}
You are almost there. Just create your method in the Activity and using Activity's instance call that method. Remember that your method inside your Activity should be not private.
public class Myclass extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
new YourActivity().yourFunction();
}
}
If you want to create a static method inside your Activity then
public class Myclass extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
YourActivity.yourFunction();
}
}
To trigger the Broadcast, you have to pass an Intent. If you want to trigger it from any Activity then
Intent intent = new Intent();
this.sendBroadcast(intent);
If you want to trigger the Broadcast from a Fragment then
Intent intent = new Intent();
getActivity().sendBroadcast(intent);
I know it's quote naif, but you could call a static method in your activity.
In your activity you declare the method like this:
public static <return_type> yourMethod(<input_objs>){
....
Your code
....
}
In the receiver you can use this function just calling:
YourActivityClass.yourMethod(<input_objs>);
I hope it helped.
Store Activity:
public void unlockcup2(){
}
Main Activity:
public void unlock2(){
x = (x-100);
ImageView img5 = (ImageView) findViewById(R.id.bluecake);
img5.setVisibility(View.VISIBLE);
}
Soo, I want to make it so when my button in Store activity(Witch calls unlockcup2()) Call unlock2 in my MainActivity . How do I do this?
localbroadcastmanager can do this job. Send a broadcast in the StoreActivity and receive it in the MainActivity and call unlock2()
MainActivity (Receiver)
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// in this case, there's only one type of action, so no need to check action
unlock2();
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
...
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver,
new IntentFilter("custom-action-name"));
}
#Override
protected void onDestroy() {
...
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
}
StoreActivity (Sender)
public void unlockcup2() {
...
LocalBroadcastManager.getInstance(this)
.sendBroadcast(new Intent("custom-action-name"));
}
In my app, whenever I receive a push notification, I will perform a check if my mainActivity is visible to the user to do something...
I have a static boolean value that is set true inside onResume of mainActivity, and false inside it's onPause.
What should I do inside the onMessage
#Override
protected void onMessage(Context context, Intent intent)
{
if(mainActivity == visible)
//do something inside mainactivity.. change text inside edittext
else
//do something else
}
any insights ?
I'm not a fan of keeping static references to activities. I think they're a can of worms ready to explode on you. So you'll suggest an alternative to #TeRRo answer:
on your global BroadcastReceiver onMessage you'll send a LocalBroadcast that your activity will be listening to. Like this:
private static final String ACTION_PUSH_RECEIVED = "com.myapp.mypackage.action.pushReceived";
public static final IntentFilter BROADCAST_INTENT_FILTER = new IntentFilter(ACTION_PUSH_RECEIVED);
#Override
protected void onMessage(Context context, Intent intent) {
Intent i = new Intent(ACTION_PUSH_RECEIVED);
i.putExtra( ... add any extra data you want... )
LocalBroadcastManager.getInstance(context).sendBroadcast(i);
}
and now we make the activity listen to it:
#Override
protected void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(context)
.registerReceiver(mBroadcastReceiver, BroadcastReceiverClass.BROADCAST_INTENT_FILTER);
}
#Override
protected void onPause() {
LocalBroadcastManager.getInstance(context)
.unregisterReceiver(mBroadcastReceiver);
super.onPause();
}
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent){
// read any data you might need from intent and do your action here
}
}
To avoid this, you should manage activities references. Add the name of the application in the manifest file:
<application
android:name=".MyApp"
....
</application>
Your application class :
public class MyApp extends Application {
public void onCreate() {
super.onCreate();
}
private Activity mCurrentActivity = null;
public Activity getCurrentActivity(){
return mCurrentActivity;
}
public void setCurrentActivity(Activity mCurrentActivity){
this.mCurrentActivity = mCurrentActivity;
}
}
Create a new Activity :
public class MyBaseActivity extends Activity {
protected MyApp mMyApp;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMyApp = (MyApp)this.getApplicationContext();
}
protected void onResume() {
super.onResume();
mMyApp.setCurrentActivity(this);
}
protected void onPause() {
clearReferences();
super.onPause();
}
protected void onDestroy() {
clearReferences();
super.onDestroy();
}
private void clearReferences(){
Activity currActivity = mMyApp.getCurrentActivity();
if (currActivity != null && currActivity.equals(this))
mMyApp.setCurrentActivity(null);
}
}
So, now instead of extending Activity class for your activities, just extend MyBaseActivity. Now, you can get your current activity from application or Activity context like that :
Activity currentActivity = ((MyApp)context.getApplicationContext()).getCurrentActivity();
Or why don't you use the Local broadcasts when you receive the push notification, and receive it in your activity, and do respective changes or actions.
And if they are UI intensive tasks, bind your activity to a service, and receive the push notification and perform the action in this service and use the result in the activity.