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.
Related
I started an activity with the following code from my service:
Intent cmActivityIntent = new Intent(getApplicationContext(), CallManagementActivity.class);
cmActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(cmActivityIntent);
In the app's manifest the launchMode of the activity is defined as android:launchMode="singleTask".
I've been looking for ways of stopping the activity on the service's onDestroy() but I haven't been able to find any documentation that can help me. And I've only found one way of doing it.
I've seen the aproach of checking on the serviceif the activity is instanced using an activity-class-static-property (public static boolean isInstanced) and sending another intent to the activity with a FINISH_ACTIVITY extra if it is. Then, on the activity's onNewIntent() the flag would be checked and the activity would be finished if the flag was included.
This approach doesn't feel right to me, since intents are supposed to be used start activities and not stopping them.
Does someone know any other way of how to acomplish this?
Many alternatives have been given to solve this issue:
Use an Intent and set an Extra.
Send a broadcast intent from the Service and register a BroadcastReceiver on the Activity.
Use the LocalBroadcastManager (similar to previous alternative)
Bind the Activity to the Service and pass it a Messenger so the Service can use it to communicate with the Activity.
None of them have I found a good solution, in fact, since the service is only accesible from the package, the solution I'm sticking with is the Observer Pattern.
Next you'll find the code I used. The activities implement the Observer interface (my own) and the service the abstract class ObservableService.
ObservableService:
public abstract class ObservableService extends Service {
#Override
public void onCreate() {
super.onCreate();
serviceStarted = true;
observers = new ArrayList<Observer>();
}
#Override
public void onDestroy() {
super.onDestroy();
serviceStarted = false;
}
//---------------------------------------------------------
//
// Singleton methods
//
//---------------------------------------------------------
/**
* Flag set to <code>true</code> if the service is running and
* <code>false</code> if not.
*/
private static boolean serviceStarted;
/**
* Used to check if the service is started.
* #return <code>true</code> if the service is running and <code>false</code>
* if not.
*/
public static boolean isServiceStarted() {
return serviceStarted;
}
//---------------------------------------------------------
//
// Observable methods an constants
//
//---------------------------------------------------------
/**
* Used to notify the observers that the service has been stopped.
*/
public static String UPDATE_TYPE_SERVICE_STOPPED = "service_stopped";
protected static ArrayList<Observer> observers;
public static void addObserver(Observer observer) {
observers.add(observer);
}
public static void removeObserver(Observer observer) {
observers.remove(observer);
}
protected static void notifyObservers(String updateType) {
for (Observer observer : observers) {
observer.onObservableUpdate(updateType);
}
}
}
Observer:
public interface Observer {
public void onObservableUpdate(String updateType);
}
The activities just register themselves as observers at onResume() and unregister at onPause(). The isServiceStarted() is used to finish the activity if the service is already stopped.
#Override
protected void onResume() {
super.onResume();
if (InCallService.isServiceStarted()) {
InCallService.addObserver(this);
} else {
this.finish();
}
}
#Override
protected void onPause() {
super.onPause();
InCallService.removeObserver(this);
}
public void onObservableUpdate(String updateType) {
if (updateType.equals(ObservableService.UPDATE_TYPE_SERVICE_STOPPED)) {
this.finish();
}
}
I chose this because I found it to be a very simple and high-performance alternative.
I would like to preserve the data or string on reload of the activity without using shared prefrences or sqllite databases.
Currently I have tried OnsavedInstancestate or OnRestoreInstancestate method but it will work only if orientation changes not for reloading the activity...
Please suggest me to overcome this.
Regards
priya
You can use singleTon class mechanism here.
Try to create a singleton class in your app.
Get instance of the class in your activity.
set the data to the class in onCreate()
get the data from the class whenever you want say in onRestart().
To learn more about singleTon class see this..
Create singleton class
public class Singleton {
private static Singleton singleton = new Singleton();
/*
* A private Constructor prevents any other class from instantiating.
*/
public String valueToStore;
private Singleton() {
}
/* Static 'instance' method */
public static Singleton getInstance() {
return singleton;
}
public String getValueToStore() {
return valueToStore;
}
public void setValueToStore(String valueToStore) {
this.valueToStore = valueToStore;
}
}
In your activity.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Singleton singleton = Singleton.getInstance();
singleton.setValueToStore("Hai");
}
#Override
protected void onRestart() {
// TODO Auto-generated method stub
super.onRestart();
Singleton singleton = Singleton.getInstance();
Log.d("Value", singleton.getValueToStore());
}
You could try using the application class to store the data in a global singleton that would persist the data, then you could load and store the data from the singleton when you needed it using getter and setter methods.
See this similar question for how to do it: Using the Android Application class to persist data
The easiest way to keep data when an activity is destroyed is to use
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putString("Test", "Test");
super.onSaveInstanceState(outState);
}
Note that this will not get called when the user press the back button only when the system destroys the activity or another activity comes above.
I have an Activity in whose onCreate() method i call a Utility function.
This utility functions requires a callback class instance as a parameter, in which it returns the info that i need. this is:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Utility.functionA(new functionACallBack() {
/**
*
*/
private static final long serialVersionUID = -7896922737679366614L;
#Override
public void onResponse(String error) {
((MyActivity) AppClass.getAppContext()).finish();
}
});
}
Once I have obtained that info, I want to close the activity. so i called finish() from inside the anonymous class that i created for the callback.
But the activity is not getting finished. I thought maybe i need to call finish() from UI thread so i did runOnUiThread(), in inside it also i tried calling finish(). But it just doesn't work.
Could someone please help me with this issue?
UPDATE:
I am storing APP context and then trying to use that but to no avail.
public class AppClass extends Application {
private static Context mContext;
#Override
public void onCreate() {
super.onCreate();
AppClass.mContext = getApplicationContext();
}
public static Context getAppContext(){
return AppClass.mContext;
}
}
Simply call something like this:
#Override
public void onResponse(String error) {
((Activity) context).finish();
}
As this is a static function, you'll have to be able to access your Context in a static way. You can save that as a Class variable, but you'll have to be aware about its handling as it might lead to memory leaks.
To avoid them, you can declare a class that extends Application and save here your context, so this way you won't ever have a memory leak.
Try using this code:
((Activity) ActivityClass.this).finish();
Remember, use the Activity class, not the Application one.
I am trying to figure out the best way to implement Listener to location with the onResume and onPause.
Best I can do not it to turn it off on onPause and reconnect on onResume. But then I keep having disconnect-reconnect when all I want is for the GPS to stay on for the duration of the application. When Home is pressed (or another application is interrupting) then GPS can be downed off for battery saving.
Any ideas?
Thanks.
Your question can be generalized to "How do I tell when my app moves into/out of the foreground?" I have used the following approach successfully in two different apps that needed the ability to discern this.
When you change activities, you should see the following sequence of lifecycle events:
Activity A onPause()
Activity B onCreate()
Activity B onStart()
Activity B onResume()
Activity A onStop()
As long as both of these activities are yours, you can make a singleton class designed to track whether your app is the foreground app or not.
public class ActivityTracker {
private static ActivityTracker instance = new ActivityTracker();
private boolean resumed;
private boolean inForeground;
private ActivityTracker() { /*no instantiation*/ }
public static ActivityTracker getInstance() {
return instance;
}
public void onActivityStarted() {
if (!inForeground) {
/*
* Started activities should be visible (though not always interact-able),
* so you should be in the foreground here.
*
* Register your location listener here.
*/
inForeground = true;
}
}
public void onActivityResumed() {
resumed = true;
}
public void onActivityPaused() {
resumed = false;
}
public void onActivityStopped() {
if (!resumed) {
/* If another one of your activities had taken the foreground, it would
* have tripped this flag in onActivityResumed(). Since that is not the
* case, your app is in the background.
*
* Unregister your location listener here.
*/
inForeground = false;
}
}
}
Now make a base activity that interacts with this tracker. If all of your activities extend this base activity, your tracker will be able to tell you when you move to the foreground or the background.
public class BaseActivity extends Activity {
private ActivityTracker activityTracker;
public void onCreate(Bundle saved) {
super.onCreate(saved);
/* ... */
activityTracker = ActivityTracker.getInstance();
}
public void onStart() {
super.onStart();
activityTracker.onActivityStarted();
}
public void onResume() {
super.onResume();
activityTracker.onActivityResumed();
}
public void onPause() {
super.onPause();
activityTracker.onActivityPaused();
}
public void onStop() {
super.onStop();
activityTracker.onActivityStopped();
}
}
I simply have not found a solution to share a real-time data between the activitys. My first activity receives real-time object (type double, a random numbers). And i want to pas this numbers to second activity. It all works, only the second Activity shows only one time the data. I have to refresh the activity by going back to first activity and only then the second activity show the latest data. I implemented a Singelton pattern:
public class FirstActivity extends Activity{
public double xAxis;
public double yAxis;
public static FirstView instance;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.device_view);
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
int data1 = msg.arg1;
xAxis = (double) data1;
dataX.setText(String.valueOf(xAxis));
int data2 = msg.arg2;
yAxis = (double) data2;
dataY.setText(String.valueOf(yAxis));
}
};
secondview.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent nextScreen = new Intent(getApplicationContext(),
SecondActivity.class);
startActivity(nextScreen);
}
});
}
public static void initInstance(){
if(instance == null)
{
instance = new FirstActivity();
}
}
public static FirstActivity getInstance(){
return instance;
}
}
SecondView class
public class SecondActivity extends Activity{
private double valueX;
private double valueY;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.linegraph);
valueX = FirstActivity.getInstance().xAxis;
valueY = FirstActivity.getInstance().yAxis;
}
}
Application class
package com.bluetoothcomm;
import android.app.Application;
public class MyApplication extends Application {
#Override
public void onCreate(){
super.onCreate();
initSingeltons();
}
public void initSingeltons(){
FirstActivity.initInstance();
}
}
You may implement a background service capable of providing the real time data to Activity1 and also to Activity2. I am guessing that your problem ocurrs if you are passing data from Activity1 to Activity2 through an Intent with putExtras, on this way it will only do this at the moment you start Activity2.
I have found my problem and the solution is to use Application. Only this dose not solves my problem. The problem is that the static variable instance public static FirstView instance is bound to the class loader, the first class that initilize that. So when the static variable inside any class has been initilized by an Activity and when the second Activity is started the first Activity is destroyed, so this means the static variable is also uninitilized. Thats why the SecondActivity dose not gets the up to date data or real time data, it catches only static constant data.
I changed my code a littele bit with the combination of Singelton and Application, couse this way the static variable should never be uninitilized when SecondActivity is activated. But i still get the same results, the static variable instance is uninitilized when i swtich to Second Activity. I am doing somethink wrong, does any one sees it. I added my code.
#Max Rasguido, #Orabig
You should use the intent process. docs
How is your data supposed to change when activity2 is shown, if you say that it's received by activity1 ?
However, I would use a preference, or an attribute of your application class (which is a singleton itself), but you give too little informations to fully understand your needs...