I have a main Activity that's happily been working with a Service I created for a while now. Recently I've had to add a DialogFragment to my app and although its working nicely as well, I now need to make a call to my Service and pass along more than the usual Intent type strings. Basically I need to pass an array of Bitmaps to the Service, and I don't think it's reasonable to try and stuff them into an Intent.
So I was hoping, without luck so far, that I could bind to the service while the DialogFragement is open so I can make a direct method call to the Service.
Is there any way to do this? So I have to copy the entire ServiceConnection class and bind to it from onStart()? I figured there must be a less messy way to do this.
Thanks in advance.
As there is no code, I assume that your DialogFragment serves to capture some kind of input from the user (Yes/No or something similar), as most dialogs do. If this is the case, then you can simply return the input back to the calling Activity and make a call to the Service based on this input. Another question is where to the Bitmaps come from? Passing an array of Bitmaps from an Activity to a Service doesn't seem a good decision for me, you should probably consider moving the Bitmap retrieving logic to the Service itself, whether the Bitmaps come from the network or from resources.
Most part of my answer is based on assumptions about the design of your application, so if those assumptions go wrong you can post some code or add a broader description of your app and I'll be glad to review my answer.
Related
First of all: I am rather new to Android App programming and I have a rather basic question:
Already with the sandbox app I am currently working on, the code in the Activity class get quite huge because all the callback methods / listeners (click listener, callbacks from GoogleApiClient) are in there (either by implementing the respective interface or by creating a private class). But I would rather put those into separate classes.
But the question that I ask myself is this: how would I then be able to access the class attributes of the activity class? Sure, I would then probably create setter/getter, but still I first need a reference to the Activity object. How would I get this?
Thanks and regards!
It's a really wide question, since the answer depends by your project and by your programming style. The first suggestion is: move what you can move in one or more fragment. All stuffs related to google play services can be nicely handled in a fragment for example. Listener and callback are UI related components, so they need a Context of an Activity to work, but you can split your UI (again) with Fragment and keep a piece of logic in a Fragment and another piece somewhere else. If you have some logic that runs in background, then you should consider using Service. I tend to have empty Activities, but this is not a rule.
I try to get the foreground activity for a long time, and i didn't managed to get it until now.
I don't know if it even possible, but i am dont intersted in my app activity only.
There is no data transfer between my service and the activity which i want to get.
I saw lot of questions of this kind but i got nothing suitable for my needs.
I just need to get an instance, not a ComponentName, not decription of the current foreground activity.
I've tried through ActivityThread, ActivityManager, ActivityManagerService (even though i couldnt get his instance too), and so on.
Field activitiesField = activityThreadClass.getDeclaredField("mActivities");// won't help
activityManager.getRunningTasks(rnd);// won't help either
If there is any refelection way, listener or something like that, but not a static field.
Without knowing why you want an instance of the Activity, or other background info. I'd suggest the following.
If you're inside a Fragment, then you can do getActivity() - which will give a reference to the Activity, and you can then cast this as your own Activity.
Otherwise, you might want to consider having a BroadcastReceiver, which can start an Activity for you.
You shouldn't be accessing an Activity directly. If you have methods/logic you need to access, you might consider refactoring them into a helper class.
Edit:
"Your application runs in a secure sandbox environment, so other processes on the system cannot access your code or private data." Take from the official Android docs
I have my MainActivity which gives the user a selection of pages to open, all of which involve downloading some data from the internet and displaying it. To save the user waiting when they choose their page I've made an AsyncTask as a subclass of MainActivity which produces an object DATAwhen the download is complete.
How would I pass DATA on to the SecondActivity in the following circumstances:
The user chooses the SecondActivity before the AsyncTask download has completed.
The download completes before the user chooses the SecondActivity.
the AsyncTask doesn't have to be a sub-class of MainActivity its just been tidy to do it that way so far,
thanks for the help!
Here's one way to do this:
Create a reference to your data in your Application. The Android Application is a good place to store global data. Next, populate the data via your AsyncTask (Watch out for the pitfalls of using an AsyncTask). You can now access your data via a call similar to this: ((MyApplication)getApplication).mydata
As you mentioned, two scenarios can come up. Either the data has been populated, or not. To handle this, use an observer that observes changes to the data. Have SecondActivity register as an observer when the data is null. When the data is available your SecondActivity's update method will get called and you can do whatever you please with it. Finally, make sure to unregister from being an observer.
Hope this helps.
Passing information directly between activities works only if it is Parcellable (via Intent). Almost anything could be made Parcellable but it is not always a good idea especially when the amount of data is large.
The next problem is that your AsyncTask most likely keeps the Context of your first activity alive when it is running longer than the activity lasts. Activity instances are quite often recreated when you rotate the device and naive implementations tend to start another asynctask in the new instance and end up with multiple tasks that download the same data. You would need to pass the reference of a running task between instances of the same Activity.
The simplest solution is probably to create a singleton (or a Service) accessible from both activities that hosts the AsyncTask & loads the data. If it requires a Context use getApplicationContext() since that's safe to use outside the lifetime of Activites.
Activities could register themselves as listeners for "data loaded" events while they are active.
I've recently struggled with AsyncTask and had difficulty having the UI behave while the task was running in the background. While there are comments around that services aren't really appropriate for the sort of thing you're describing, I've found them much easier to work with. You might check intentService as a middle ground. Good tut's can be found here and, specifically concerning intentService, here.
Im trying to use the pattern of Activity-Service-Messenger to comunicate my Activity and Service. (like explained here http://viktorbresan.blogspot.mx/2012/09/intentservice-and-inter-process.html) Basically it says that i should create a Handler inside my Activity, and then create a Messenger and send that via putExtra() to my Service. The Service would then post messages to the activity ussing the Messenger.
My problem is that if i rotate the emulator, the Handler associated with the Messenger holds a reference to a destroyed activity. This causes not to refresh the interface of the new activity. I tried to put Messenger in onSaveInstanceState(). Eventought i can save the Messenger, the Handler is still referencing my past activity and i cant find a way to retrieve my Handler from the Messenger to set the new activity.
Edit:
Im avoiding to using:
android:configChanges="orientation|keyboardHidden"
onRetainNonConfigurationInstance()
Edit:
I used HalR idea of using a singleton and keep the handler there. It works really good, althought i can see that this pattern implies a careful cleaning of the references on the singleton.
Finally im also testing on the idea of using Activity-Service that was commented by Hoan Nguyen
I'm not sure that its appropriate for this case, but there are many people who have been frustrated by losing their activity when it rotates, or having to set complex stuff up every time they get a new activity.
Some people will create singletons that they use for referencing, then keep the Handler in there.
Others will extend the application class and put stuff in there. If you have a lot of complex things you are wanting to set up once, those are techniques you can use.
Keeping your app fluid and your making your activities independent of one another is a better overall philosophy, so its best to avoid anything global, but sometimes you gotta do what you gotta do.
Rotating the device at least pauses and resumes your activity according to the lifecycle. I think you are aware of the consequences.
Maybe stopping and starting a new service is the only right solution here. i worked as well with global states, but it will just always be easier when, you make every activity independent like a "single application".
edit: ok it's a messenger service... so stopping and starting is not a solution. so maybe you can register and unregister your messengers.
I want to better understand how to structure an Android app where an activity fires off an API call (for example).
I'd currently implement it by putting the API call into an AsyncTask subclass, passing it a reference to the activity so it can update the UI in onPostExecute. But my gut-feel is that this is creating overly-coupled code.
I'm wondering whether instead I should put an API call like that into a service, and use a BroadcastReceiver to update the activity.
What say you, AsyncTask, or BroadcastReceiver?
I usually follow the Local Service pattern. I have a strong suspicion that this is how the official Twitter app works and that this is the pattern most of the Google apps use. This also solves the issue of your app going away (getting killed or going into the background) before the task finishes, or if the phone switches configuration during a background task.
BroadcastReceiver and service is an overhead here. A request to web-service should not go to long. Service is appropriate in case of downloading files or something similar.
AsyncTask way is the right one here. But I would suggest you showing a progress dialog to let user know that your application isn't freezed, but doing some useful work.
See the example here.
AsyncTask is just fine. Only thing you should worry about is referencing you Activity using WeakReference to avoid whole Activity be memory leaked. It isn't overly-coupled code imo if you using observer or events patterns.
I would go with a service only if the call is going to take long, so that the user can leave the app while it's completing.
I'd use the AsyncTask if the task is short enough that it almost wouldn't go ANR if done in UI thread.
(disclaimer: I consider myself a beginner, and I'm expecting comments from more experienced people)