Accessing the global value outside function - android

I'm Trying to set a value(global) in a function and access it outside function that is in "On create()" in android
I've tried making the global variable static, and I even tried to write it in a "edit text" and parsing it in "on create()" . but it keeps initializing to 0.0 (the variable is a double type)
when i tried to access in "on create()",
oh and i can't return the value because the function is too nested so all hierarchy is too complex. :(
Can anyone help me with this;
public class TryActivity extends Activity
{
double BAT;\\ global value
public void onCreate(Bundle savedInstanceState)
{
disp(); // calling the function disp to set the value to BAT
String To_string=Double.toString(BAT);
System.out.println("Current Battery level ==="+To_string); \\ prints 0.0 the wrong value
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void disp(){
this.registerReceiver(this.batteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
private BroadcastReceiver batteryInfoReceiver = new BroadcastReceiver(){
public void onReceive(Context context, Intent intent){
double level= intent.getIntExtra(BatteryManager.EXTRA_LEVEL,0);
BAT=level;
Textview1 = (EditText) findViewById(R.id.Textview1);
Textview1.setText(Double.toString(BAT)); // sets the correct value
System.out.println("bbbattererrerey 1 "+Double.toString(BAT)); //prints the correct value
}
};
}

Simply initialize the variable as public static gobally in the class. You will be able to access it from anywhere.

Define as public static your variables:
public class TryActivity extends Activity
{
public static double BAT; //global value.
public void onCreate(Bundle savedInstanceState) {
...
...
...
You are getting BAT with value of 0.0 because when your activity starts execute the method onCreate() and the the method disp() that only register the Intent to get the Battery Level.
If you want to get the battery level at the start of your activity you can do it with a function to get the battery level without receiving updates.
public float getMyBatteryLevel() {
Intent batteryIntent = this.getApplicationContext().registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
return batteryIntent.getIntExtra("level", -1);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
//* Add this method.
getMyBatteryLevel()
disp(); // calling the function disp to set the value to BAT
String To_string = Double.toString(BAT);
System.out.println("Current Battery level ==="+To_string); //prints the right battery level.

The problem is you don't understand the concept of concurrency. The BroadcastReceiver's onReceive() won't be called immediately. Thus, you are just setting up the BroadcastReceiver in disp(), and not directly touching BAT. BAT will only be filled with the correct value when onReceive() is called.

If you will look in to your logs the System.out.println() you have written in onCreate will be called before the System.out.println() written in onReceive of your BroadcastReceiver even it is written after your disp() method.
Reason :
In disp() method you are just registering your BroadcastRecever doesn't mean that your BroadcastReceiver is called. It will be called after sometime when your battery level will be changed.
Solution :
If you want to do something with yout BAT variable define a function in your Activity class and write whole logic inside it like
doThings(double batteryLevele){
//write whatever you want to do with BAT
}
and call this function from onReceive method of your BroadcastReceiver.

Related

Android - Listening to a locale change without static variables

I have a BroadcastReceiver that listens to a locale change. Here's my problem:
I navigate to an Activity and then want to change locale (language setting) which I do by going to the settings app. The BroadcastReceiver then listens in onReceive() once a change is made. I then navigate back to the app and when I do so I'd like to take a user to another Activity.
Also, a locale modification corresponds to a change in configuration which means an Activity will be destroyed and created again.
https://developer.android.com/guide/topics/resources/runtime-changes.html
Here is the BroadcastReceiver:
public class LocaleReceiver extends BroadcastReceiver {
public LocaleReceiver() {}
#Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
if(Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())){
MainActivity.isLocaleChanged = true;
}
}
}
And here is the Activity that uses the static variable set by the BroadcastReceiver.
public class MainActivity extends AppCompatActivity {
public static boolean isLocaleChanged = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(isLocaleChanged){
Intent intent = new Intent(this,SecondActivity.class);
startActivity(intent);
isLocaleChanged = false;
}
}
}
And indeed I am able to navigate to a different Activity !
However, I'd like to do this in a manner that does not use static variables (since they are evil :(). Is there any other way to accomplish this.
I'd also be extra happy if there were no SharedPreferences involved.
Well, you can turn off configuration changes for locale, implement onConfigurationChanged, check if the change is to the locale, and launch the new activity there. I'm not sure if I'd suggest it though, you'll have issues when you return with strings. This is a case where you have to store state non-locally- either in a static, on disk (sharedPreference) or via a state singleton, or some other means. It isn't that statics are evil, its that they can be misused. This is a case where they make sense.
I'd actually recommend static over shared preference here, as shared preferences may stick around if you don't clear it properly and screw up a later execution of your app. A static won't, it will be cleared when your app is killed worst case.

Simple increment counter doesn't work in android app

sounds stupid but a simple increment counter doesn't work in my android app.
I have two activities in the app and one counter in each, which is incremented each time when onCreate method is called. When I'm switching between the activities the first one works well, but the other one just doesn't count.
I'm using the same line to create the variable like this:
private int mCreate;
Then I'm just incrementing it in the same way in each class in the onCreate method:
mCreate++;
This variable is used in two different classes, so it shouldn't be a problem. This is my first android app, so I need some help.
The whole code of the second activity. I'm not showing the first one because the only difference is in the setOnClickListener method.
public class ActivityTwo extends Activity {
private final static String TAG = "Lab-ActivityTwo";
private int mCreate;
private TextView mTvCreate;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_two);
mTvCreate = (TextView) findViewById(R.id.create);
Button closeButton = (Button) findViewById(R.id.bClose);
closeButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
Log.i(TAG, "Entered the onCreate() method"); // to check if the inCreate method was called
mCreate++;
mTvCreate.setText("onCreate() calls: " + mCreate);
Log.i(TAG, "mCreate = " + mCreate); // just to check if I implemented the TextView worng
displayCounts();
}
The reason your second counter doesn't work because after finishing an activity all the variables and objects are destroyed and make free by GC. The next time you call for that activity it is created from scratch and your count remain same everytime.
Like #Opoo said if you want to get count you should define static variable in Application class.

Listener behavior in relation to Activity lifecycle

I have an Activity with a private OnSharedPreferenceChangeListener, the listener's work is defined on the onCreate() method of the Activity. The listener is registered to the sharedPreferences of the application.
The change itself is triggered by a Service in response to an sms received intent.
Will the listener receive the callback when the Activity itself has died? are there cases where it will not?
The listener is defined (roughly):
private OnSharedPreferenceChangeListener _sharedPreferenceListener;
public void onCreate(Bundle bundle){
...
_prefs = PreferenceManager.getDefaultSharedPreferences(this);
_prefs.registerOnSharedPreferenceChangeListener(_sharedPreferenceListener);
...
_sharedPreferenceListener = new SharedPreferences.OnSharedPreferenceChangeListener(){ /*doing some work here*/};
...
}
please igonre the logic here if correct or not, assume that the code works, my main concern is how the listener reacts to changes in the lifecycle of the activity.
Thanks,
actually, since the listener doesn't know anything about the activity (and as such you can use it anywhere , not just in an activity), you will get notified no matter where you use it.
Also, since you can't know for sure what it does with the context , you should use the application context instead in this case (so that you won't have memory leaks, though I doubt it needs a reference to the activity).
Of course, if the listener itself is referenced by weak reference, and the activity doesn't have any reference to itself on any other class, the listener can be GC-ed too. You can see in the code of Android (or at least of API 19) that in the class "android.app.SharedPreferencesImpl" (example link here) , you have a WeakHashMap of listeners, so it might mean that the activity that hosts the listener can be GC-ed and so the listener will stop from being called. Here is the relavant code of Android:
private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners =
new WeakHashMap<OnSharedPreferenceChangeListener, Object>();
...
public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
synchronized(this) {
mListeners.put(listener, mContent);
}
}
So, as I've written, best if you just put the application context in case you wish to keep listening to this event.
Or, in case you do wish to stop listening to this event, just unregister it when the activity is being destroyed.
to prove it, you can simply run your app...
here's my proof app:
MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
preferences.registerOnSharedPreferenceChangeListener(new SharedPreferences.OnSharedPreferenceChangeListener() {
#Override
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
android.util.Log.d("AppLog", "changed!");
}
});
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
startActivity(new Intent(MainActivity.this, Activity2.class));
}
}, 1000);
finish();
}
}
Activity2.java
public class Activity2 extends Activity {
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_activity2);
//if you call here System.gc(); , you have a good chance that the listener won't be called
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//this may or may not cause the listener to write to the log
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(Activity2.this);
preferences.edit().putBoolean("test", true).commit();
}
}, 1000);
}
}
Will the listener receive the callback when the Activity itself has died?
-> No, it won't. Because when your activity dies, the _prefs and _sharedPreferenceListener fields will be destroyed.
You could check this question for more details on OnSharedPreferenceChangeListener :
SharedPreferences.onSharedPreferenceChangeListener not being called consistently
You must un-register the listener in onDestroy() of activity, else Activity object will stay in memory.

Android MediaPlayer On Stop Event, or similar, exists?

I have several activities which use several audio features. For that, I have a MediaPlayer in a singleton java class, so the activities interact with that class and just exist on the media player.
One of the features is to stop automatically the media player after X minutes. So I created a timer in the singleton class and stops perfectly the radio streaming. the problem is that there is no feedback or callback to the running activity. There is a play/stop button wich has to change the image and I do not know how can I capture that onStop event or whatever....or can be called from a single java class the current activity class running, so I could call a function of the activity in order to change the image?
You probably want to use a broadcast receiver for this.
From your singlton class which does the stopping, when your timer stops the music, call this method:
public void broadcastMusicPaused(View v){
Intent broadcast = new Intent();
broadcast.setAction("MUSIC_STOPPED");
sendBroadcast(broadcast);
}
Then, from your controlling activity, set up your receiver like this:
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "Music Paused", Toast.LENGTH_SHORT).show();
displayMusicStopped(); //switches images
}
};
#Override
protected void onResume() {
IntentFilter filter = new IntentFilter();
filter.addAction("MUSIC_STOPPED");
registerReceiver(receiver, filter);
super.onResume();
}
#Override
protected void onPause() {
unregisterReceiver(receiver);
super.onPause();
}
First of all, thanks jameo for his answer, sounds pretty good, but i do not know if i will have time to try, i promise i will if i can this week or next time i have a similar issue.
Finally i did the trick this way:
1 - Create a Interface with Method onStopMediaPlayer(); //For example call MediaPlayerStopInterface
public interface MediaPlayerStopInterface {
/**
* Called when the player timer ends
*/
public void onStopMediaPlayer();
}
2 - My activities classes implements the interface switching images.
public class PortadaActivity extends Activity implements MediaPlayerStopInterface{
public void onStopMediaPlayer(){
//Switch images or whatever
}
}
3 - My singletton class has an object of the type of the interface MediaPlayerStopInterface
public class AudioControllerClass { //The Singletton Java Class
private MediaPlayerStopInterface currentActivity;
public void setCurrentActivity(MediaPlayerStopInterface mpsi){
currentActivity=mpsi;
}
}
4 - My activities classes in onResume() do a Singlettonclass.setStoppedPlayerInterface(this), so i always have a reference of the running activitie.
public class PortadaActivity extends Activity implements MediaPlayerStopInterface{
public void onResume() {
AudioControllerClass.getInstance(getApplicationContext()).setCurrentActivity(this); //In every resume the singletton class knows who was the last one in being active
}
}
5 - when timer execute, as i have the activitie class reference, i just call object_StoppedPlayerInterface.stoppedPlayer();
public class AudioControllerClass { //The Singletton Java Class
class TimerRadio extends TimerTask {
public void run() {
if(whatever==true){
currentActivity.onStopMediaPlayer();
}
}
}
}
Finally, i didn't code it, but the callback to onStopMediaplayer in activities must be done with a Handler, if you do not want a "Only UI thread can touch his views" exception :P
It works perfectly :). But i don't know if it is a really bad practice or is not so horrible xD
Anyway thanks Jameo. Yours sound much more elegant :P

How to notify Activity about changes in global variable in Application?

I have a IntentService that updates a global variabel in a extended Application class. In several of mine Activities I need to know when the variable is changed.
Do I have to implement a BroadcastReceiver in all my Activities(and send a intent from my service) or is there a simpler way to notify my activities?
Thank you!
I have also faced this type of problem. Broadcast receiver in one of the Solution. But i am not satisfied with that.So, I tried with another metod.You can find more details in object observer pattern in andrdoid,refer this link.
public class TestActivity extends Activity implements Observer {
BaseApp myBase;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myBase = (BaseApp) getApplication();
myBase.getObserver().addObserver(this);
myBase.getObserver().setValue(10);
}
#Override
public void update(Observable observable, Object data) {
// This method is notified after data changes.
Toast.makeText(this, "I am notified" + myBase.getObserver().getValue(),
0).show();
}
}
public class Test extends Observable
{
private int value=2;
/**
* #return the value
*/
public int getValue()
{
return value;
}
/**
* #param value
* the value to set
*/
public void setValue(int value)
{
this.value = value;
setChanged();
notifyObservers();
}
}
package app.tabsample;
import android.app.Application;
public class BaseApp extends Application {
Test mTest;
#Override
public void onCreate() {
super.onCreate();
mTest = new Test();
}
public Test getObserver() {
return mTest;
}
}
Yes, BroadcastReceivers were designed for just this. That said, why not just make a single parent class which has a BroadcastReceiver and all the associated logic? Then the only thing your other activities have to do is simply inherit from that parent class.
Note that you should also set some sort of global variable in persistent storage (like a shared preference) every time you send our a Broadcast. That way, if one of your activities isn't in the foreground when the Broadcast is sent, it can check the variable in persistent storage when it comes back in the onResume() method and act accordingly.

Categories

Resources