Android SharedPreferences value not update in BroadcastReceiver - android

I create a SharedPreferences called ALARM with a map called ("alarm",boolean), ("alarm",boolean)'s boolean value changed time to time in MainActivity, and received in a BroadcastReceiver.
The problem is: when I change the value in MainActivity time to time, BroadcastReceiver only change once. What's wrong with my code?
In below code, the start() align to a button, when clicked, change boolean to true. I can see a true value received in the BroadcastReceiver as well. But then I click the stop(), boolean change to false in MainActivity, but still see a true value received in BroadcastReceiver.
If I click stop() first, then I always see false value in BroadcastReceiver.(even I click start() many time)
Thanks.
MainActivity:
public class MainActivity extends AppCompatActivity {
SharedPreferences ALARM;
SharedPreferences.Editor editorALARM;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ALARM = getSharedPreferences("ALARM", MODE_PRIVATE);
editorALARM = ALARM.edit();
}
// start data service
public void start(View view) {
editorALARM.putBoolean("alarm", true).apply();
Log.e("start",""+ALARM.getBoolean("alarm", false));
Intent intent = new Intent();
intent.setAction("xxx.ALARM");
sendBroadcast(intent);
}
// stop data service
public void stop(View view) {
editorALARM.putBoolean("alarm", false).apply();
Log.e("stop",""+ALARM.getBoolean("alarm", true));
Intent intent = new Intent();
intent.setAction("xxx.ALARM");
sendBroadcast(intent);
}
}
BroadcastReceiver:
public class Receiver extends BroadcastReceiver {
SharedPreferences ALARM;
#Override
public void onReceive(Context context, Intent intent) {
ALARM = context.getSharedPreferences("ALARM", Activity.MODE_PRIVATE);
Log.e("actual",""+ALARM.getBoolean("alarm", false));
}
}

It is due to the android: process =":remote" in manifests.xml, after remove it. I got correct boolean.

replace-
editorALARM.putBoolean("alarm", true).apply();
with-
editorALARM.putBoolean("alarm", true).commit();
will work for you

Related

Call a method from other Activity in AlarmReceiver

I'm on a activity with a textview and in the background is AlarmReceiver running with a 10min time trigger.
The activity has a method which I want to call by the trigger. The method sets a new value to the textview. But by calling it from the trigger I can not use "findViewById". I get a NullPointerException at this point. I also tried to setContentView when its called by the trigger but also here I get an NullPointerException
This it the Code:
ValuesActivity:
public void setSyncValue(Context context, boolean fromSyncService, String value){
try {
if(fromSyncService){
setContentView(R.layout.activity_values);
}
...
try{
...
TextView lastSyncTV = (TextView) findViewById(R.id.last_sync_label);
lastSyncTV.setText(value);
...
} catch (Exception ex) {
....
}
} catch (Exception ex) {
....
}
}
AlarmReceiver
#Override
public void onReceive(Context context, Intent intent) {
try {
Intent i = new Intent(context, SyncService.class);
context.startService(i);
}catch (Exception ex){
.....
}
}
SyncService
//runns every 10min
#Override
protected void onHandleIntent(Intent intent) {
try {
...
ValuesActivity valuesActivity = new ValuesActivity();
valuesActivity.setSyncValue(....)
....
}
.....
}
actually you can't create an activity by creating an instance of that, you must run an activity by Intents. in your case if an activity is already in foreground and visible to user you must start activity with a FLAG_ACTIVITY_CLEAR_TOP flag. that send new intent to your current visible activity. to do this you can use this code:
context.startActivity(new Intent(this,ValuesActivity.class).putExtras(bundle).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
in this way if activity already visible to user then android instead of recreating activity just send a new intent to method onNewIntent and you must override this method in your ValuesActivity to receive new intent sent by your service. something like this:
public void onNewIntent(Intent intent){
String value = intent.getStringExtra(/*your key*/);
lastSyncTV.setText(value);
}
if you want to check activity visibility you can add static property in your activity public static boolean isVisible = false; and toggle it true in onResume of your activity and toggle to false in onPause method.
then before startActivity just check if(ValuesActivity.isVisible).
Inside your
#Override
public void onReceive(Context context, Intent intent)
use
Intent intent = new Intent("alaram_received");
context.sendBroadcast(intent);
Inside your mainactivity first register the broadcast
IntentFilter intentFilter = new IntentFilter("alaram_received");
registerReceiver(alarm_receiver,intentFilter);
and then call your method in here:
BroadcastReceiver alarm_receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// your logic here
Log.i("alarm_received","success");
}
};

How to pass data from BroadcastReceiver to Activity without in onCreate()

I have a serious issue about passing data from BroadcastReceiver to an Activity. Let see my issue carefully. I have a class PhoneStateReceiver extends BroadcastReceiver that used to received an incoming phone.
public class PhoneStateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
System.out.println("Receiver start");
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if(state.equals(TelephonyManager.EXTRA_STATE_RINGING)){
}
}
catch (Exception e){
e.printStackTrace();
}
}
}
The incoming phone will be sent to an Activity, called ReceiverActivity. The ReceiverActivity receives the incoming phone and sends it to a server via a socket connection. The socket connection is initialized in the onCreate function. I googled and found server way to pass the data from BroadcastReceiver to an Activity. The common way is that send data via putExtra function and call startActivity. However, the way will call the onCreate again and then connect the socket, draw the UI again. Thus, it is not helpful in my case.
In my goal, If the phone receives an incoming call, it will send the incoming call to the ReceiverActivity. The ReceiverActivity receives the message and calls the send function. Which is the best way to do it? Thank you
The common way to pass data from a BroadcastReceiver to a ReceiverActivity that I used as follows
In PhoneStateReceiver class :
Intent intent_phonenum = new Intent(context, ReceiverActivity.class);
intent_phonenum.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent_phonenum.putExtra("phone_num", incomingNumber);
context.startActivity(intent_phonenum);
In ReceiverActivity class :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
connect_socket();
Intent intent = getIntent();
phone_num = intent.getStringExtra("phone_num");
send(phone_num);
}
Simple without any third party libs.
Make sure BroadcastReceiver must be registered and also unregistered on OnPause().
You have to do two thing
Register a receiver in you activity like below.
public class MainActivity extends Activity {
Context context;
BroadcastReceiver updateUIReciver;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
IntentFilter filter = new IntentFilter();
filter.addAction("service.to.activity.transfer");
updateUIReciver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//UI update here
if (intent != null)
Toast.makeText(context, intent.getStringExtra("number").toString(), Toast.LENGTH_LONG).show();
}
};
registerReceiver(updateUIReciver, filter);
}
}
Now in you service
public class PhoneStateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
System.out.println("Receiver start");
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
Intent local = new Intent();
local.setAction("service.to.activity.transfer");
local.putExtra("number", incomingNumber);
context.sendBroadcast(local);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
There is a very simple design pattern you can use here to ease communication between your classes and also decouple your code: publisher/subscriber. My favorite library for this is EventBus:
First, add to your build.gradle file:
compile 'org.greenrobot:eventbus:3.0.0'
Then, create a simple POJO - Plain Old Java Object like this:
public class OnReceiverEvent{
private String phoneNumber;
public OnReceiverEvent(String phone){
this.phoneNumber = phone;
}
public String getPhoneNumber(){
return phoneNumber;
}
}
Next, by making your Receiver class a publisher, and your Activity a subscriber, you should be able to easily pass the information to your activity like this:
//inside your PhoneStateReceiver class when you want to pass info
EventBus.getDefault().post(new OnReceiverEvent(phoneNumber));
Next, inside your activity, simply do this:
//onStart
#Override
public void onStart(){
super.onStart();
EventBus.getDefault().register(this);
}
//onStop
#Override
public void onStop(){
super.onStop();
EventBus.getDefault().unregister(this);
}
Finally, handle the posted data i.e phoneNumber value:
#Subscribe
public void onPhoneNumberReceived(OnReceiverEvent event){
//get the phone number value here and do something with it
String phoneNumber = event.getPhoneNumber();
//display or something?
}
UPDATE
If you have another Event that you want this activity to subscribe to, simply create a method like you did in the first one using the #Subscribe annotation.
#Subscribe
public void onSomeOtherEvent(EventClassName event){
//get the variables here as usual;
}
This is the easiest way to pass the data from your receiver to your activity without having to worry about starting the activity over and over!
I hope this helps and good luck!
So I understand you don't want to recreate your Activity everytime.
In your Intent changing this flag will help you :
intent_phonenum.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
In Intent class if you read method summary of FLAG_ACTIVITY_CLEAR_TOP:
If set, and the activity being launched is already running in the
current task, then instead of launching a new instance of that activity,
all of the other activities on top of it will be closed and this Intent
will be delivered to the (now on top) old activity as a new Intent. (you can read more ...)
In this case: If your app is running and you have an Activity instance then Intent will not recreate your Activity. But assume that your app is in closed state and when BroadcastReceiver triggered, the Intent will create new Activity because you don't have instance of that Activity.
#Edit :
You can specify special Intent like that in your BroadcastReceiver:
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
Intent i = new Intent("mycustombroadcast");
i.putExtra("phone_num", incomingNumber);
context.sendBroadcast(i);
}
Then in your Activity inside onCreate() register receiver like that :
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
int incoming_number= bundle.getInt("phone_num");
Log.e("incoming number", "" + incoming_number);
}
};
//then register receiver like that :
registerReceiver(broadcastReceiver, new IntentFilter("mycustombroadcast"));
You can unregister Receiver in onDestroy() : unregisterReceiver(broadcastReceiver);
Also another way is overriding onNewIntent() in your Activity:
#Override
protected void onNewIntent(Intent intent) {
//your intent is here, you can do sth.
super.onNewIntent(intent);
}

Service and Activity accessing shared data

I have an Activity that starts a service. I would like the service to have access 1 of the Activity's member variables(a boolean). I have implemented a getBoolean() method in the Activity, but how do I instantiate the Activity in the service for it to access?
Use SharedPreferences to save data in activity and yu can access it in service
in OnStartCommand method when you start a service
SharedPreferences sharedPref = getSharedPreferences("MYPREF", Context.MODE_PRIVATE);
sharedPref.getBoolean("flag",false);
You don't. Instead, use a broadcast receiver or shared preferences.
Example using broadcast receiver -
public class MyService extends Service {
boolean mActivityBoolean;
BooleanReceiver mReceiver;
#Override
public void onCreate() {
super.onCreate();
mReceiver = new BooleanReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(
mReceiver, new IntentFilter("activityBooleanIntent")
);
}
#Override
public void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
super.onDestroy();
}
public class BooleanReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
mActivityBoolean = intent.getBooleanExtra("activityBoolean", false);
}
}
}
public class MyActivity extends Activity {
void someMethodThatSendsABooloean(boolean trueOrFalse) {
.....
Intent intent = new Intent();
intent.setAction("activityBooleanIntent");
intent.putExtra("activityBoolean", trueOrFalse);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}

How to start activity as its first created

How to start same activity again as its created first time. I used INTET to start activity again . but If user press home button at mobile this intent not works . is there anyother way to startactivity as its first created when its in background. Pls help this I shall be very thankful to you for this.
private void sendNextMessage(){
Log.i("Is there are sms sendNextMessage", thereAreSmsToSend()+"");
if(thereAreSmsToSend()){
Log.i("sendNextMessage mMessageSentParts", mMessageSentParts+"");
Log.i("sendNextMessage mMessageSentTotalParts", mMessageSentTotalParts+"");
Log.i("sendNextMessage mMessageSentCount", mMessageSentCount+"");
Log.i("sendNextMessage Phone list", list_phone.get(mMessageSentCount)+"");
sendSMS(list_phone.get(mMessageSentCount),list_MESSAGE_BODY.get(mMessageSentCount));
}else{
Toast.makeText(getBaseContext(), "All SMS have been sent",
Toast.LENGTH_SHORT).show();
new AddNewCategory().execute();
h.removeCallbacks(r);
h.postDelayed(new Runnable() {
public void run() {
// I used this code to start activity again but if user press home button this intent not works .
Intent i = new Intent();
i.setClass(MainActivity.this, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
startActivity(i);
Log.e("Time", "60000 intent");
h.removeCallbacks(r);
}
}, 30000);
h.removeCallbacks(r);
h.removeCallbacks(r);
}
}
How about using the SharedPreferences with a boolean value;
Make a class for this:
private Context context;
public boolean saveFirsTime(boolean firstime)
{
SharedPreferences sharedPreferences = getSharedPreferences();
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean("FirstTime", firstime);
return editor.commit();
}
public boolean loadFirsTime() {
SharedPreferences sharedPreferences = getSharedPreferences();
boolean firstimeMap = sharedPreferences.getBoolean("FirstTime", true);
return firstimeMap;
}
public boolean clearFirsTime() {
SharedPreferences sharedPreferences = getSharedPreferences();
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.remove("FirstTime");
return editor.commit();
}
private SharedPreferences getSharedPreferences() {
return context.getSharedPreferences("SharedPrefereneces",Context.MODE_PRIVATE);
}
And then implement saveFirstTime(false) in your Activity onCreate();
Write a service and broadcast receiver something like below :
This Activity start activity on reboot similarly u can write ur event on which activity is called :
public class BootStartUpReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// Start Service On Boot Start Up
Intent service = new Intent(context, TestService.class);
context.startService(service);
//Start App On Boot Start Up
Intent App = new Intent(context, MainActivity.class);
App.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(App);
}
}

Android BroadCastReceiver refresh all activities

I have an issue using BroadCastreceiver to refresh activities in my application. I'm using a service which is doing some calculations and in onDestroy() method I'm doing this :
#Override
public void onDestroy(){
super.onDestroy();
Intent intent = new Intent("finish");
this.sendBroadcast(intent);
}
and in my activities I'm doing this :
receiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("finish")) {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
TabGroupActivity parentActivity = (TabGroupActivity)getParent();
Intent previewMessage = new Intent(Tutorial.this, Tutorial.class);
parentActivity.startChildActivity("Tutorial", previewMessage);
progressBar.setVisibility(View.GONE);
sync.setImageResource(R.drawable.sync_icon2);
final SharedPreferences isLogged = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
SharedPreferences.Editor editor = isLogged.edit();
editor.putBoolean("getProgBar", false);
editor.commit();
}
}
};
registerReceiver(receiver, new IntentFilter("finish"));
I have that function in all my activities and the problem is that if I change 2-3 of them before my service stop, after that I can see in my LogCat logs from other activities which has that function too, but I'm not currently on these activities. They are just somewhere in activity stack. But the thing that I can't understand is it reloading them (even if I can't see it visually) and how to prevent this kind of issues. I need to refresh only activity which I'm in.
Thanks!
Just add these to your activities. You have to unregister your broadcastreceiver and register it again in your onResume() like this :
#Override
public void onPause(){
super.onPause();
YourActivity.this.unregisterReceiver(receiver);
}
#Override
public void onResume(){
super.onResume();
IntentFilter intentFilter = new IntentFilter("com.example.MyService");
YourActivity.this.registerReceiver(receiver, intentFilter);
}

Categories

Resources