There are lots of discussions about data exchange between activities and fragments, but I am still struggeling with a design flaw.
I have an activity that needs to receive some data from an service. When this data has changed, the service sends a local broadcast and the activity needs to get the latest dataset.
public class ActivityChannelConfig extends Activity implements FragmentChannelList.FragmentChanneListInferface, FragmentCustomChannelList.FragmentCustomChannelListInterface {
#Override
protected void onCreate(Bundle savedInstanceState) {
// Bind to Bluetooth Service
bindService(new Intent(this, ServiceBluetoothConnection.class),
mServiceConnection, Context.BIND_AUTO_CREATE);
}
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
ActivityChannelConfig activity = mActivity.get();
if(activity == null)
return;
ServiceBluetoothConnection.BTConnServiceBinder binder = (ServiceBluetoothConnection.BTConnServiceBinder) service;
mService = binder.getService();
mIsBound = true;
// Put current list into channel list fragment
FragmentCustomChannelList customChannelList = (FragmentCustomChannelList)activity.getFragmentManager().findFragmentByTag(activity.TAG_FRAGMENT_CUSTOMIZE);
if(customChannelList != null) {
customChannelList.setChannelList(activity.mServiceConnection.getService().getmDBMeasurement().getSortedMeasChannels(DBMeasurement.MEAS_CHANNEL_FLAG.MEAS_CHANNEL_ENABLED));
}
FragmentChannelList channelList = (FragmentChannelList)activity.getFragmentManager().findFragmentByTag(activity.TAG_FRAGMENT_LIST);
if(channelList != null) {
channelList.setChannelList(activity.mServiceConnection.getService().getmDBMeasurement().getSortedMeasChannels(DBMeasurement.MEAS_CHANNEL_FLAG.MEAS_CHANNEL_ENABLED));
}
}
}
#Override
public void onReceive(Context context, Intent intent) {
final ActivityChannelConfig activity = mActivity.get();
// Bail out if the ActivityMarwisApp is gone.
if (activity == null)
return;
// Channel list has changed
if(intent.getAction().equals(DBMeasurement.INTENT_DB_CHANNEL_LIST_CHANGED)) {
// Put current list into channel list fragment
FragmentCustomChannelList customChannelList = (FragmentCustomChannelList)activity.getFragmentManager().findFragmentByTag(activity.TAG_FRAGMENT_CUSTOMIZE);
if(customChannelList != null) {
customChannelList.setChannelList(activity.mServiceConnection.getService().getmDBMeasurement().getSortedMeasChannels(DBMeasurement.MEAS_CHANNEL_FLAG.MEAS_CHANNEL_ENABLED));
}
FragmentChannelList channelList = (FragmentChannelList)activity.getFragmentManager().findFragmentByTag(activity.TAG_FRAGMENT_LIST);
if(channelList != null) {
channelList.setChannelList(activity.mServiceConnection.getService().getmDBMeasurement().getSortedMeasChannels(DBMeasurement.MEAS_CHANNEL_FLAG.MEAS_CHANNEL_ENABLED));
}
}
}
}
Now my problem is that I don't know, how to pass this data to the fragments inside my activity initial and dynamically. There always is the problem, that the fragment might ne be created when the service is connected or the broadcast is received.
Do I need to implement a two way interaction between the fragment and the activity?
activity.updateList -> fragment
fragment.getCurrentList -> activity
Or should I register a new braodcast receiver in each fragment, which might lead to lots of redundant code?
I know that I could also pass the data using the onCreate Bundle. But I am not a fan of making all that stuff parcable, which I also belive is very slow and inefficient.
You can use local broadcast manager to communicate between multiple fragments and intents
//Send Broadcast
private void sendLocationBroadcast(Intent intent, Context context, String Message){
intent.putExtra("Message", Message);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
}
//In this snippet you point out your fragment or activity by given sample
if(Origin == Enum_Fragments.Task.getInteger())
{
intent = new Intent("Task");
sendLocationBroadcast(intent, context, "Task");
}
// What I have done here is made a enum for fragments and trigger service with related Identity (which was assigned by me to each fragment) after condition identifies the Argument (Origin) it will send data to desired framgment
Here is enum class for ref
public enum Enum_Fragments{
Task(1), Frag Notes(2), Default(0);
Enum_Fragments(int s) {
INTEGER_FOR_MODULE = s;
}
private int INTEGER_FOR_MODULE;
public int getInteger() {
return INTEGER_FOR_MODULE;
}
public void setInteger(int iNTEGER_FOR_MODULE) {
INTEGER_FOR_MODULE = iNTEGER_FOR_MODULE;
}
public static Enum_Fragments value(String i) {
try {
return valueOf(i);
} catch (Exception ex) {
return Default;
}
}
this will send your broadcast for provided intent with some particular data after job done you may receive it at the activity as follows
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
String Message = intent.getStringExtra("Message");
//Todo
Log.d("Local BroadCast", "Recieved " + Message);
}
};
Related
I have activity and two fragments which opened in this activity (for example FragmentFirst, FragmentSecond). In my activity I register BroadcastReceiver. And when i receive any event (inside onReceive) I need to display the received text in the TextView of second fragment.
I could register the BroadcastReceiver in the second fragment, however, the event may come at the moment when my second fragment opens and then I do not have time to register the BroadcastReceiver and I lose the event.
So my code inside the onReceive of activity looks like this:
#Override
public void onReceive(Context context, Intent intent) {
String receivedMessage = intent.getStringExtra(MY_MESSAGE);
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.container);
if (currentFragment instanceof FragmentSecond) {
((FragmentSecond) currentFragment).initMessage(receivedMessage);
}
}
And now I have a question, can there be such a situation that the current fragment is FragmentSecond, but the view of this fragment has not yet been created. In this case, I can get a NPE when calling a initMessage of my FragmentSecond that sets the receivedMessage for the TextView.
If this is really possible, then I will have to add some kind of checks inside the initMessage:
public void initMessage(String receivedMessage) {
if (isViewCreated) { // flag to detect when view was created
tvMessage.setText(receivedMessage);
savedMessage = "";
} else {
savedMessage = receivedMessage; // save message to display it when view will be created
}
}
In practice, I was not able to reproduce such a situation, but it seems to me that this is possible. Please tell me if this is possible?
P.S. I get the feeling that the onReceive controls the life cycle and is called exactly when the fragment view is created. Because I tried to send a broadcast until the moment when the FragmentSecond view was created, but until the onViewCreated of my FragmentSecond was called, onReceive was not called. However, I may be wrong
You can store the message in the Activity and use it the fragment WHEN fragment is ready.
Activity
String message = null;
#Override
public void onReceive(Context context, Intent intent) {
message = intent.getStringExtra(MY_MESSAGE);
}
You can "touch" the Activity in onAttach(context) method of the fragment.
Fragment
private String message = null;
void onAttach(Context: context) {
super.onAttach(context)
if (context instanceof MainActivity) {
MainActivity mainActivity = (MainActivity) context;
message = mainActivity.message;
}
}
That is for grabbing the latest value.
Since you are operating in Java is it a bit more verbose but for updates you can use Observer pattern(create listener interface which the fragments will implement and register themselves to the activity).
interface MessageObserver {
void onMessageChange(String message);
}
Use WeakReference for the Activity so it doesn't leak the context.
Fragment
private WeakReference<MainActivity> mWeakRefActivity;
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
if (context instanceof MainActivity) {
MainActivity mainActivity = (MainActivity) context;
mWeakRefActivity = new WeakReference<MainActivity>(mainActivity);
mainActivity.addObserver(this);
}
}
#Override
public void onDetach() {
// Clean up after yourself
mWeakRefActivity.get().removeObserver(this);
super.onDetach();
}
Activity
ArrayList<MessageObserver> mObservers = new ArrayList<MessageObserver>();
void addObserver(MessageObserver observer) {
mObservers.add(observer);
}
void removeObserver(MessageObserver observer) {
mObservers.remove(observer);
}
public void onReceive(Context context, Intent intent) {
message = intent.getStringExtra(MY_MESSAGE);
for (MessageObserver observer : mObservers) {
observer.onMessageChange(message);
}
}
I have the below stack trace from leak canary with which I am not sure how my Activity is getting leaked
static LGCobtextHelper.mLGContext
references LGContext.mContext
references
ResourcesContextWrapperFactory$WebViewContextWrapper.mBase
references
com.*.*.activity.MyActivity.networkMonitor
references
com.*.*.NetworkMonitor.mPendingResult
references
android.app.LoadedApk$ReceiverDispatcher$Args.this$0
references
LoadedAok$ReceiverDispathcer.mContext
leaks MyActivity instance
MyActivity extends BaseActivity, which registers onResume() and unregisters onPause(), so not sure which leaks the activity
NetworkMonitor.java
public class NetworkMonitor extends BroadcastReceiver {
private final WebSocketClient webSocketClient;
private final ArmingHelper armingHelper;
private final ShutdownManager shutdownManager;
private final CameraThumbnailCache cameraThumbnailCache;
private final CameraAccessManager cameraAccessManager;
private final JoustLogger joustLogger;
private Activity registeredActivity;
private String currentNetworkName;
private List<NetworkStatusChangeListener> networkChangeListeners;
public interface NetworkStatusChangeListener {
void onNetworkUp();
void onNetworkDown();
}
public NetworkMonitor(WebSocketClient webSocketClient, ArmingHelper armingHelper, ShutdownManager shutdownManager, CameraThumbnailCache cameraThumbnailCache, CameraAccessManager cameraAccessManager, JoustLogger joustLogger) {
this.webSocketClient = webSocketClient;
this.armingHelper = armingHelper;
this.shutdownManager = shutdownManager;
this.cameraThumbnailCache = cameraThumbnailCache;
this.cameraAccessManager = cameraAccessManager;
this.joustLogger = joustLogger;
networkChangeListeners = new ArrayList<>();
}
// Activities *must* call this method in onResume() in order for
// the app to watch for network changes
public void startListeningForNetworkChanges(Activity registeringActivity) {
if (!(registeringActivity instanceof NetworkStatusChangeListener)) {
throw new IllegalArgumentException("Registering Activity must implement NetworkStatusChangeListener");
}
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
intentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intentFilter.addAction(GlobalConstants.ANDROID_NET_WIFI_WIFI_STATE_CHANGED);
registeringActivity.registerReceiver(this, intentFilter);
this.registeredActivity = registeringActivity;
registerListenerForNetworkChanges((NetworkStatusChangeListener)registeringActivity);
}
// Activities *must* call this method in onPause() in order to properly
// unregister the receiver that was set in onResume()
public void stopListeningForNetworkChanges(Activity registeringActivity) {
registeringActivity.unregisterReceiver(this);
unregisterListenerForNetworkChanges((NetworkStatusChangeListener)registeringActivity);
registeredActivity = null;
}
// Fragments can use this method to register for Network change updates, call in onResume()
public void registerListenerForNetworkChanges(NetworkStatusChangeListener listener) {
networkChangeListeners.add(listener);
}
// Fragments need to unregister in onPause()
public void unregisterListenerForNetworkChanges(NetworkStatusChangeListener listener) {
networkChangeListeners.remove(listener);
}
#Override
public void onReceive(Context context, Intent intent) {
checkNetworkConnection();
}
public void checkNetworkConnection() {
if (registeredActivity != null) {
final ConnectivityManager connectivityManager = (ConnectivityManager) registeredActivity.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnectedOrConnecting()) {
String newNetworkName = networkInfo.getTypeName();
if (currentNetworkName == null || !currentNetworkName.equals(newNetworkName)) {
Timber.d("Network(%s) Connected", newNetworkName);
// Our network was down, but now it's up. Validate the Websocket
currentNetworkName = newNetworkName;
cameraThumbnailCache.clearInternalURLPreferences();
webSocketClient.reopenWebsocketIfPossible();
cameraAccessManager.onNetworkUp();
if (ActivityBehaviorHelper.needsSecurityCountdown(registeredActivity)) {
armingHelper.startTimerIfReady();
}
for (NetworkStatusChangeListener listener : networkChangeListeners) {
listener.onNetworkUp();
}
joustLogger.onNetworkUp();
}
} else {
Timber.w("Network Down");
currentNetworkName = null;
cameraAccessManager.onNetworkDown();
joustLogger.onNetworkDown();
shutdownManager.onNetworkDown();
for (NetworkStatusChangeListener listener : networkChangeListeners) {
listener.onNetworkDown();
}
}
}
}
}
BaseActivity.java
#Override
protected void onResume() {
super.onResume();
networkMonitor.startListeningForNetworkChanges(this);
}
#Override
protected void onPause() {
networkMonitor.stopListeningForNetworkChanges(this);
super.onPause();
}
It looks like you probably don't need to be holding a reference to the Activity in that NetworkMonitor class. That's probably the source of your memory leak - the Activity reference is likely being held after the Activity is destroyed. Looks like you could just pass the context in as a parameter to the methods that need it.
Also, For a few of the spots where Activity context is being used here, like context.getSystemService(Context.CONNECTIVITY_SERVICE), you could use Application context instead and possibly avoid needing an Activity reference altogether.
I'm trying to create an app that makes HTTP requests through an intentservice. I need the app to wait for the service to finish its run (aka, have the request be returned with some data) before it continues its operations, as its operations involve manipulation of the data I hope to receive from the HTTP requests. I've tried numerous means of doing so - Semaphore, CountDownLatch, but it seems that for all of them, I need some method of passing in the waiting/counting object into the intentservice so that it can tell the main thread where that object is waiting that it is done processing. How do I go about doing that? Basically, I want a synchronous, blocking call to an http server to work conveniently with an Intent Service, since an intent service makes multi threading easy.
Again to reiterate just to make sure i'm not misusing terminology: What I mean by Synchronous and blocking/what I want: I make a call to the http server by sending an intent to my intentservice that makes the request. My UI thread, or thread from which this intent was sent, now waits until the request has been processed and a result has been returned before continuing to run.
If you think that I am going about this process (making http calls in a blocking, synchronous way) all wrong, what is another way you might choose to go about it? Thanks!
I am sorry, but I think your architecture is not right or I may understand it wrong. IntentService is built to do thing serial way on separate thread. Now you say you want it to be synchronous and blocking. You cannot block UI thread!
In order to create notification system from your IntentService to Activity/Fragment/etc. you have few choices: singleton, broadcast message (receiver, resultReceiver), others?
Based on assumption that service and other parts of the application are working in same process. Best option would be to create manager to do this job. Something like this can be built to start service as well as listen for completion event:
public class MyNetworkManager {
static MyNetworkManager sInstance;
Context mContext;
LinkedList<OnCompletionListener> mListeners;
private MyNetworkManager(Context context) {
mContext = context;
mListeners = new LinkedList<>();
}
public static MyNetworkManager getInstance(Context context) {
if (sInstance == null) {
synchronized (MyNetworkManager.class) {
if (sInstance == null) {
sInstance = new MyNetworkManager(context.getApplicationContext());
}
}
}
return sInstance;
}
// add listener to listen for completion event
public void addListener(OnCompletionListener listener) {
synchronized (mListeners) {
mListeners.add(listener);
}
}
// remove listener to stop listening for completion event
public void removeListener(OnCompletionListener listener) {
synchronized (mListeners) {
mListeners.remove(listener);
}
}
// call from UI to start service operation
public void startNetworkOperation() {
Intent service = new Intent();
mContext.startService(service);
}
// call from service to notify UI (still on different thread, can use Handler to make call on main thread)
public void notifyCompletion() {
synchronized (mListeners) {
for (OnCompletionListener listener : mListeners) {
listener.onCompleted(this);
}
}
}
public static interface OnCompletionListener {
void onCompleted(MyNetworkManager manager);
}
}
Use this pattern
public interface SynchronizationListener {
//void onStart(int id); not requered
//void onProgress(int id, long updateTime); not requered
void onFinish(Object data); // replace Object with your data type
}
In your service add end call this
private void startSynchronization() {
SynchronizationManager.getInstance().startSynchronizing();
}
Your Singleton Manager
public class SynchronizationManager {
private static SynchronizationManager instance;
private Object synRoot = new Object();
private boolean synchronizing = false;
private List<SynchronizationListener> synchronizationListeners;
public SynchronizationManager() {
synchronizationListeners = new ArrayList<SynchronizationListener>();
}
static {
instance = new SynchronizationManager();
}
public static SynchronizationManager getInstance() {
return instance;
}
public boolean isSynchronizing() {
synchronized (synRoot) {
return synchronizing;
}
}
public void startSynchronizing() {
synchronized (synRoot) {
if (synchronizing) {
return;
}
synchronizing = true;
}
Object data; // <-- replace Object with your data type
if (ConnectivityReceiver.hasGoodEnoughNetworkConnection()) { // check connection
data = sync();
}
synchronized (synRoot) {
synchronizing = false;
}
onSynchronizationFinish(data); // use listener for send data tu Observer Activity
}
public void stopSynchronizing() {
synchronized (synRoot) {
synchronizing = false;
}
}
public synchronized void registerSynchronizationListener(
SynchronizationListener listener) {
if (!synchronizationListeners.contains(listener)) {
synchronizationListeners.add(listener);
}
}
public synchronized void unregisterSynchronizationListener(
SynchronizationListener listener) {
if (synchronizationListeners.contains(listener)) {
synchronizationListeners.remove(listener);
}
}
public void onSynchronizationStart(int id) {
for (SynchronizationListener listener : synchronizationListeners) {
listener.onStart(id);
}
}
protected void onSynchronizationProgress(int id, long updateTime) {
for (SynchronizationListener listener : synchronizationListeners) {
listener.onProgress(id, updateTime);
}
}
protected void onSynchronizationFinish(Object data) {
for (SynchronizationListener listener : synchronizationListeners) {
listener.onFinish(data);
}
}
protected int sync) {
// code for load your data your HttpRequest
}
}
In your activity
private SynchronizationListener synchronizationListener = new SynchronizationListener() {
/*public void onStart(int id) {
}
public void onProgress(int id, long updateTime) {
}*/
public void onFinish(Object data) {
//elaborate data
}
};
#Override
protected void onResume() {
super.onResume();
SynchronizationManager.getInstance().registerSynchronizationListener(
synchronizationListener);
}
#Override
protected void onPause() {
super.onPause();
SynchronizationManager.getInstance().unregisterSynchronizationListener(
synchronizationListener);
}
See this code for example UnivrApp
A ContentProvider would be a better choice than an IntentService in my thinking. You can trigger each network call with a query and then return a MatrixCursor with details about the results of your background work. Android already has lots of good plumbing around running queries in background tasks and waiting for the results before triggering ui updates.
in ContentProvider query() method :
MatrixCursor cursor = new MatrixCursor(new String[]{"_id","uri", "status", "last_modified", "result"});
String lastModified=null;
int id =1;
// do your work here
// ..
// report your work here
cursor.addRow(new Object[]{id++, uri.toString(), HttpStatus.SC_OK, lastModified, "" });
// set uri for data observers to register
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
What you try to do is just communication between IntentService and Activity/Fragment.
You can try send broadcast at the end of onHandleIntent and catch it in registered receiver or use ResultReceiver - read more how to implement here.
Edit:
Try this:
Handle all background operations at once in onHandleIntent
On every step send new data using ResultReceiver
// operation 1
Bundle b1 = new Bundle();
b1.putParcelable("data", data1);
resultReceiver.send(0, b1);
// operation 2
Bundle b2 = new Bundle();
b2.putParcelable("data", data2);
resultReceiver.send(1, b2);
Handle it in ResultReceiver
public void onReceiveResult(int resultCode, Bundle resultData) {
if (resultCode == 0) { // handle step 1 }
else if (resultCode == 1) { // handle step 2 }
}
I have an activity class (outer class), a static broadcastreceiver class (inner static class) and a service class. The service and the activity communicate with messages and handlers. When an action that the service is monitoring is triggered, the broadcastreceiver is called. After it's done I want to call a method inside the service to remove the element processed from the "items_to_be_processed_queue". To do that I thought to use the method that I have in my MainActivity that sends a message to the service triggering the remove method (I have this method in MainActivity because it's possible to remove manually an item from the "items_to_be_processed_queue" by pressing a button). The thing is I keep getting two kind of errors depending on what I do (I'll show you a bit of code first):
public class MainActivity extends Activity {
Messenger messenger;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
messenger = new Messenger(binder);
}
public void onServiceDisconnected(ComponentName className) {
messenger = null;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
....
}
//Button click implementation
public void removeItem(View view) {
Message msg = Message.obtain(null, MyService.REMOVE_ITEM);
msg.replyTo = new Messenger(new ResponseHandler());
Bundle b = new Bundle();
b.putInt("data", Integer.valueOf(etNumber.getText().toString()));
msg.setData(b);
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void removeItem(int i) {
Message msg = Message.obtain(null, MyService.REMOVE_ITEM);
msg.replyTo = new Messenger(new ResponseHandler());
Bundle b = new Bundle();
b.putInt("data", i);
msg.setData(b);
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
protected static class ResponseHandler extends Handler {
Boolean result;
#Override
public void handleMessage(Message msg) {
int respCode = msg.what;
switch(respCode) {
case MyService.ADD_ITEM: {
result = msg.getData().getBoolean("respData");
}
case MyService.REMOVE_ITEM: {
result = msg.getData().getBoolean("respData");
}
}
}
}
public static class MyBroadcastReceiver extends BroadcastReceiver {
.........
#Override
public void onReceive(Context context, Intent intent) {
........
Case 0: new MainActivity().removeItem(id); //Where id is the position of the item
Case 1: MainActivity.this.removeItem(id);
}
......
So in the case 0 I get no compiling errors but at run time I get a NullPointerException at messenger.send(msg) inside removeItem(int i) method. In case 1 I get the compiling error "No enclosing instance of the type MainActivity is accessible in scope".
What am I doing wrong and what could I do? I even tried to put the removeItem methond inside the broadcastreceiver but I still got run time errores. Thanks in advance for any answer.
Case 0:
You should never create an object of Activity class It will give you a null context. Look at #Raghav Sood's answer here Creating an object of Activity class
Case 1:
You can not call a non-static method from an inner static class. If you want to call removeItem in MyBroadcastReceiver make it static. Since it seems you are not using any instance variables that should not be a problem.
You cannot create activity like that because Android is handling Activity lifeCycle so it won't be anygood..
I can suggest diffrent approach.. Maybe i am missing something because i didn't fully understood your code but this is more architecture problem and less code
Lets say that you hold your DataList In a static way... In that case you can access from Activity and From service as well.. You can't access an activity in the way you want.
class Utils {
private static List<Integer> myList;
static {
myList<Integer> = new Vector<Integer>();//Create new instance of vectore which is thread safe
}
public void getMyList()..;
public List<Integer> setMyList..;
}
In this way you will have direct access to your data structure an you won't have to deal to much with sync between those 2.
EDIT: You can add methods to remove and add or something.. This can be used by
Utils.getMeyList();//Or all other method you need
Hope that make sense..
into my application i use an intent:
private Handler mHandler = new Handler();
.
.
mServiceIntent = new Intent(this, ObdGatewayService.class);
mServiceConnection = new ObdGatewayServiceConnection();
mServiceConnection.setServiceListener(mListener);
// bind service
Log.d(TAG, "Binding service..");
bindService(mServiceIntent, mServiceConnection,
Context.BIND_AUTO_CREATE);
here my activity at onCreate start a new service. this is my onDestroy:
#Override
protected void onDestroy() {
super.onDestroy();
mServiceIntent = null;
mServiceConnection = null;
mListener = null;
mHandler = null;
}
this is mServiceConnection:
public class ObdGatewayServiceConnection implements ServiceConnection{
private static final String TAG = "com.echodrive.io.ObdGatewayServiceConnection";
private IPostMonitor service = null;
private IPostListener listener = null;
public void onServiceConnected(ComponentName name, IBinder binder) {
service = (IPostMonitor) binder;
service.setListener(listener);
}
public void onServiceDisconnected(ComponentName name) {
service = null;
Log.d(TAG, "Service disconnesso.");
}
public boolean isRunning() {
if (service == null) {
return false;
}
return service.isRunning();
}
public void addJobToQueue(ObdCommandJob job) {
if (null != service)
service.addJobToQueue(job);
}
public void setServiceListener(IPostListener listener) {
this.listener = listener;
}
mListener is a listener from interface:
public interface IPostListener {
void fineTest(DatiTest risultati);
void startAcquisizione();
void aquisizioneTerminata();
void aquisizioneInterrotta(String motivo);
void connessioneCorretta();
void gpsStato(boolean stato);
}
my problem is.. how save all this code after rotation? thanks!
The recommended way to save state across rotations is to save them on the outState. This is accomplished by overriding the onSaveInstanceState method. This method gives you a Bundle outState object that you can add Parcelable and Serializable objects to. This should work fine for your Intent object since it implements Parcelable but it may not work for say Handler because it only extends Object.
Another solution is to make these members static. However, be very careful if you decide to do this. Make sure that the value of the static member never holds on to a Context or a view hierarchy, etc, or you could easily introduce memory leaks.
If neither of these is acceptable to you, there is the option suggested by Tushar. However, unless you're careful this will make your life very difficult very fast. A large reason why activities are destroyed and re-created is so that resources can be re-loaded. So if you have layouts, strings, colors, dimens, or basically any resource specifically for landscape, or tablets, or different versions, you'll have to reload the entire UI yourself.