I have a net service in my app, for now it doesn't matter if it's a thread in the Application context or a service, what does matter is i have some trouble getting response properly.
The service is working, and i do get responses, right now i work with the observer design patter which is a bitch in android :-( i have to remove the listener in on destroy and then check the network if it is all ready finished and handle different scenarios.
I want to change my approach, but i'm not sure what's the right android way, it seems like activities are made for polling which is bad for my architecture and error prone :-(.
I thought of the folowing two methods but non seem to give me a real solution:
create a braodcast receiver that
will send a broadcase with a flag if
response or error arrived from the
net, it's apt to the activity to
poll the right data and handle. i do
wonder about this since if i
register for broacast i basically
have to remove the listener in on
pause, so i CAN miss a broadcast,
then it's back to check the net
state in onCreate, same like what
i'm doing now - sucks...
register the activity that whats an event and sent it an intent using startActivity but here if the activity is in on pause or stop i'll bring it to the front, i don't want this kind of behavior, i only want that the activity will get the event no matter what, and starting to wonder if there's a way to do that.
The landscape\portrait event are killing me, any way out of it ?
i discovered the following:
i can decide to handle the
landscape\portrait events myself and
then i eliminate 90% of the problem
i can use Broadcast Receivers but with sticky flag on that will cause the intent to wait for me, i just have to check first if i got the intent once i'll gt it once more if it's sticky (meaning in landscape \ portrait i may get it twice on screen rotation)
if i get new intent that doesn't kill my app (depends on the intent) i get it in onNewIntent() method. i can put some init functions that are dependant on those values in a seperate init function that gathers them all to share them between onCreate and onNewIntnet.
Related
I'm building an app that registers a Broadcast Receiver for Connectivity Changes. When connectivity is available, the app performs a GET request and display the data in a ListView.
I registered the Broadcast Reciver (Connetivity Changes) and it works as expected. But I have a huge dilemma. I want to notify the MainActivity when Connectivity is available.
My first approach was using a class that extends from Observable and implement the Observer interface in the MainACtivity. I stopped that solution because I started using static variables and static methods. My other solution was using a Custom Broadcast registered in the , the idea is sent a broadcast from the Broadcast Receiver and catch it in the MainActivity.
I read several suggestions and a can't get a recommended solution. What is the best approach to this situation?
Do you need to notify the Activity only if it's currently running? Or the next time it's run?
For the first case, you can create a second BroadcastReceiver in the activity, register/unregister it in onResume()/onPause(), then notify it via an intent sent from the Service (all this using a LocalBroadcastManager). However, is that was your intent (heh) then you might as well have a second receiver in the activity for the original broadcast, so I guess it's not likely.
The other way (notify the Activity the next time it's accessed) is even simpler, just use SharedPreferences to record a boolean flag indicating that the task is pending. When the activity is resumed, check for this flag, do the needed work (make sure the connection is still available) and then clear it.
A third possible scenario (which I would think more probable, even though it doesn't match your description of the problem) is that you want to download and store the data at the moment the connection becomes available, then just have the activity load it when it starts. In this case the service would perform the download, then either notify or use the flag trick so that the activity knows new data is available.
Depending on the scenario, you might also want to take a look at Sync Adapters.
Few days ago I read that there is a better mechanism for sending broadcasts within single application - the LocalBroadcastManager.
It works well (just like standard broadcasts..). However, yesterday I've found out that it cannot send broadcasts to receivers, which are defined in the manifest (when I temporarily switched it to use the standard Activity's sendBroadcast method, it worked).
The reason why I want this (and correct me if there is a more preferred way to do it) is:
Lets's say I want to download a file. I will use a service, because that's how Android wants us to do. OK, now I want to display (and periodically update) its progress in my activity. So service will be sending broadcasts to my activity and the activity has to register to receive them. The preferred way to handle broadcasts is to register in onResume() and unregister in onPause(). Now let's imagine that the user is bored with the slowly moving progressbar, so he presses Home and goes to do something else. Later he comes back and wants to see the current status of the download, but how can I tell him, when I unregistered from broadcasts that second he left my application?
That's why I use a receiver defined in the manifest, to be always ready to receive the broadcast and store it permanently (shared preferences, database...), so the activity can reconstruct the latest broadcast when it becomes visible.
However now I'm not sure, whether this routine is not recommended, or why the LocalBroadcastManager is not allowing me to do it.
If you are using SharedPreferences a workaround would be to make your activity implement OnSharedPreferenceChangeListener. So the service writes the pref and the activity listens for the change and updates progress bar. onResume() you also check the preference and update the UI accordingly.
The nice thing with this is you don't really have a leak if you fail to unregister them - see
Android : Where should a OnSharedPreferenceChangeListener be defined/registered - I prefer to unregister to onDestroy() as I want to have my activity updated even if not in the foreground - and the listener will go away even if onDestroy is not called.
As for why it does not work with manifest registered receivers - could you post some code ? Do you actually register the receivers with LBM ?
I've been looking around at many forum discussions, but none of them answers properly how to handle runtime changes that forces the actual activity to restart.
In my case, for example, my activity uses an AsyncTask to show a ProgressBar while fetching data from server. But, if user just rotates the screen, the activity is restarted and repeats the request to server.
If screen rotation is done while the AsyncTask is still in doInBackground(), waiting for server's response, I get a android.view.WindowLeaked error.
I just want to, whenever the screen gets rotated or another interruption occurs, my activity continues doing its job from where it stopped, could that be this hard?
onSaveInsanceState() is recommended? How could I save a partially received JSON in a Bundle? Or maybe I should use onRetainNonConfigurationInstance()...
Will send a bottle of Brazilian's drink "caipirinha" for the good soul that helps me...
You need to use a different architecture.
Move the background operation from the AsyncTask into a Service. A service runs in the background independent of any Activity, and does not get restarted when you change the orientation of the device.
The background Service can communicate with the foreground Activity via broadcasts. Within the service, you can send broadcasts w/ progress info using sendBroadcast(). You can receive the broadcasts in the Activity using a BroadcastReceiver.
EDIT: For less drastic approaches that may be suitable depending on your situation, see:
http://developer.android.com/guide/topics/resources/runtime-changes.html. In particular, if you do not use different resources for landscape and portrait, then the second method (handling the configuration change yourself) may work well.
EDIT2: Some additional info here:
Activity restart on rotation Android
In the app I am working on, I have an AlarmManager that starts a Service at specified times and intervals. The Service uses some data I send in the Intent to read/write the SQLite database, make a Notification and send an SMS. I've had a problem that when the device goes into "deep sleep" and I use the device again, I get a force close with a NullPointerException on the Intent in the Service. As I've done some research, I've had several questions about how a Service works that I haven't been able to answer:
1) I realized that I was using the deprecated onStart method for a Service. I am going to switch to onStartCommand with START_REDELIVER_INTENT flag (think this was the null exception I was getting because the Service was trying to restart with the old onStart and not getting the original Intent). My question is this: Should I put the work the Service does in the onStartCommand or in onCreate? Is there any functional difference?
2) Considering what I am doing in my Service, is this enough work to put in its own Thread?
3) Do I need to specifically call stopSelf? If so, where is the best place to call it?
4) This one is more ambiguous: To my knowledge, I had canceled all of the alarms registered and after deep sleep, I still got the null exception for a Service. Is there any reason the Service would still get run even though I never triggered it with an alarm?
Please ask any clarifying question if necessary. I haven't posted code because most of it is generic for starting and consuming a Service, but if you want to have a peek, let me know. Thanks.
You should use IntentService instead of regular old Service. It does all its work in a background thread and stops itself automatically when it runs out of work.
I have the following framework for my application:
1. a Network thread that runs in the background (a queue) for issuing request and get async responses. The thread is started and stopped in the Application Object so it's leaving through out the whole application.
2. a DataManager which is also a member of Application and has different DataManagers for the data types i retrieve from the network. the data manager itself is the listener for the responses from the network so it's safe until the application itself dies.
3. this is the problematic part. Some of my Adapters and part of my Activities are DataListeners for my DataManagers, that means that the data manager keeps a reference to them.
When a phone call or some other phone event occurs i've noticed that the activity is usually in paused and not destroyed and so receives my events, which is ok. the problem starts when landscape\portrait is changed. since i keep a referenced to the activity in an Application bound object, the activity can't be destroyed on one hand, BUT the event is still getting to the listener, only the wrong one...
Basically i can fix that issue by removing the listener in onDestroy and retaining configuration boolean to tell me that request was allready issues and i just need to put a listener and try to retrieve the data from the data manager.
However :-) i was wondering how android handles this cases usually, if for example this was a Service running. or if the Service is a local Service that used Bound and passed on the Activity as a Listener to the network Event, the same things happen, untill the listener is not removed the Activity is leaked and lives on, but without it, no way to get callbacks from the network...
an Intent requires serilaztion and deserilazation of data which can be heavy (Bitmaps for example?)
And anywa, asuming i send an intent on each respose i get, how do i get the intent to the Activity (i know of getIntent, but if i get another one , not related, do i get it as an 'event' ?)
From what I gather it's customary on Android to remove yourself from listener lists when the activity is destroyed. It's kinda error-prone, but I think it's the generally accepted way to do it.
You could imagine your service accepts only one listener, which may or may not fit your case, and when the activity restarts its registering with the DataManager would overwrite the old activity which would in turn be garbage collected. The drawback is, you don't free the activity memory if it is destroyed but the service lives on, so it's probably better to just remove the activity from listeners.
Android development is rather different from other platforms (e.g. BlackBerry). I'm not able to give you a quick silver bullet solution, however here are my thoughts on this:
Some of my Adapters and part of my
Activities are DataListeners for my
DataManagers, that means that the data
manager keeps a reference to them.
OS kills Activities according to their lifecycle. So you should avoid keeping a handle to an Activity in another object which is supposed to live after the Activity is destroyed by OS. Otherwise you'll get memory leak.
Also keep in mind Application sublass instance does not always live for the whole application session (a session from a user perspective). If your app goes in the background, for example, due to an incoming phone call, then your entire process can be killed. See details here. As soon as you Application sublass contains some state which is not persisted if process is killed you may mistakenly expect your handles to point to some non-null entities. However after going to foreground (and process restore) those may just be nulls because a new instance of Application sublass has been created by OS.
Ok, so let me describe the problem and the solution i found in more details.
The problem:
I have a Service\Network Thread that needs to notify Activities that sent requests through it that either request or Error has arrived in an Async way. Using Listener Pattern requires me to set listener before or when i send a request like so:
mNetService.setRequest(request, this);
where this is Activity that implements my listener Interface.
But doing it this way requires me to remove the listener from the service in onDestroy and returning the listener, if i ever sent a request back in onCreate\onResume, but the response can also arrive exactly when the activity is not listening (landscape\portrait event) which requires me to keep the Error\Response in the service until some1 picks it up and resets it.
The solution i found:
using Broadcasts and BroadcastReciever.
this is only part of the solution but it let you have a listener to broadcasts (that can be specific for a certain class type meaning Activity) and action.
Since all of my Activities inherit a base Activity class i've made they all have a BroadcaseReciever inner class that listens on certain action in it's filter.
is i enable the listening in the C'tor of my Activity the listener will be registered in onResume and deregister in onPause.
If the listener gets onRecieved event it will call a method in the Activity (which i can override in my specific activty) and pass it the Intent i got which can contain all the data from the response.
The only missing part is what happens if the Activity dies for a second and only then the broadcast arrives ? ah, that's a problem, so android intorduces Sticky Broadcasts that stays there untill you remove them with removeStickyBroadcast(Intent), so when is ent broadcast from my service i send Sticky broadcast, when the Activity gets my Broadcast it removes it so it wont stay around and mislead the activity about new response that arrived.
The only problem with it is if i send a request, don't wait for the response and goes to the next Activity right away, in this case when i'll go back to that Activity it will think it got the response. Didn't find a proper solution to that just yet. But it's better then my previous solution.