Tasks and Back Stack is the definitive resource for understanding the mechanism involving tasks and their interaction with the Back button. In an early paragraph:
A task is a collection of activities
that users interact with when
performing a certain job. The
activities are arranged in a stack
(the "back stack"), in the order in
which each activity is opened.
Tasks are then explained in terms of the home screen and how it launches processes. This makes sense. I'm curious, however: What should determine the use of multiple tasks in "user" applications?
I'm interested in a intuitive understanding or heuristic guiding task usage rather than simply trying to achieve specific orderings of activities on the back stack.
A task is a group of components that work coherently together to fulfill a purpose for the user (not necessarily a very specific purpose, but a purpose nonetheless). It's what the user sees as an application.
A music player exists to allow the user to manage and play songs. It may include various activities that display album/artist/song metadata, control playback, organize playlists, etc. It may also include services that implement the playback and that watch for new songs. The user doesn't know what an activity and a service are; he or she only knows that this series of screens lets him or her manage and play songs.
The activities in a task don't need to belong to the same 'application' from a development standpoint. If the music player task allows users to link an image to a song, then it might launch an image gallery activity or the camera activity. Since the new activity is still working toward the purpose of managing songs, it's still part of the same task.
On the other hand, if the user completely breaks out of the task's purpose, it might be time to start a different task. For example, if you launch a web browser to view the artist's website, the user is now doing something different. The user probably doesn't associate web browsing with managing and playing songs, so this should probably be a different task.
I think a task in that given context is sort of a workflow. Take email. Writing a new email may consist of
first filling in recipients and then in the next activity selecting recipients and clicking on send finally sends the email off.
Another task could be selecting multiple emails and then deleting all in one go.
In practice what you often find is an AsyncTask which is basically doing work in background which otherwise would block the UI thread and make the app non-responsive.
Related
I have a use case where I want to download some files from the server and store them locally before starting another activity that is dependent on this file. This kind of design can be found on karaoke kind of applications where clicking on one song would
Load the required files from the server
Once the download is finished, open the required activity.
Let us assume that my app is a karaoke app. My question is how to design this flow. Basically, on clicking on one song, I want to show progress on the screen and when the download is finished, I want to move to the activity. Another requirement is that once I am inside the karaoke activity screen and playing a song, I have an option which leads to loading of another lesson. If a user uses that option, I want to again download the required files. Based on this requirement, should I:
Have the file loading thing as a separate activity?
OR
It can be used as Fragmentinside the activity where I choose a particular song. In this case, once entering the karaoke screen, if I choose an option which leads to downloading some files and reloading of this activity, is this the best design?
I would recommend two different approaches depending on how long you plan on keeping the data that you've downloaded. If it is single use than a bound service would be ideal. However, if you are planning on keeping the downloaded content for more than a single use, I would recommend you use a content provider and possibly a sync adapter(Depending on how frequent/predictable content downloading is). This combo would help guide you into not having to think about the 'design' as much(Since it is pretty standard at this point), plus it would provide a lot of features that you may/may not find useful: you can make your internal data 'public' via the content provider/authority(s), you can make an 'account' on the phone associated with your app so that the user can manage its syncing via the sync manager(actually via widgets/apps using the sync manager, but still), and most importantly a set of clean(ish)/standard means to interact with it/propagate UI, etc.
My simple version would be an Activity that spawns either a async-AIDL service with callback (which is in my opinion the only way to use a bound service) that would allow you to asynchronously design your 'starter' activity, its "currently downloading" spinner (which can get progress updates via the callback if you design it that way). Then once the download is complete then send the results (via a parcel file descriptor in the Intent's bundle) to the new activity that makes use of it.
However, if you are planning on using the data more than once, I'd recommend downloading the content like you did above, but then also store it in a content provider for easy access later. Providers also have a lot of nice associated functionality related to cursor loaders, etc. that will help keep a list of the content currently being stored nice and clean/up-to-date/dynamic/etc. However, this is a lot more work to setup once, then later it would save you time in reduced.
A sync adapter is best when the data to be downloaded is predictable, either based on user's account or temporally (such as someone having an account to download data from (email account, etc.) or when the target is fairly constant, but the data should be updated every hour or so(such as the current weather)). So this will depend a lot on your application's exact specifics.
Here is an assignment for an Android App Development course I wrote that is an even more simplified version of the first option (it has intent service + broadcast receiver for returning download results back to the Activity). Obviously since this is an assignment it has sections cut out to make skeleton code, but the documentation is ABSURDLY detailed and should be fairly easily implemented.
https://gitlab.com/vandy-aad-3/aad-3-assg-2/tree/master
Here is the extension of that assignment for that same course that focuses on implementing a simple content provider's 4 main methods (Create, Read, Update, & Delete). Everything else about the provider is given to you.
https://gitlab.com/vandy-aad-3/aad-3-assg-3/tree/master
Obviously the content being downloaded in both applications is probably not what you intended, but that is a simple swap to replace in what you do want.
Not to shill to hard, but here is the (free) Specialization that this course is a part of: https://www.coursera.org/learn/androidapps
Point one : Don't download video file within the Activity level. You can start a Service to handle it. Once the download function is finished you can start the second Activity. While download function is in progress you can show a ProgressBar
Point Two : Best Design is show a ProgressBar with percentage to user. Or disable the function. After download complete enable or start the second activity.
I already know that using Services/Intent services we download multiple files in background. But this problem have one more complexity to solve.
I have to download multiple videos/images in different activities in parallel like whats app. I have seen in whats app that we can start download and then we can moves on different screens or press home button etc. But when we move back on that screen again the downloading is still continue with and showing the updated progress.
Like above there is 4 activities and user started downloading of ABC.mp4 on activity and A and then moves on to Activity B. Then moves on to C and started downloading of video/image. If user moves back on to the A and I want to show the progress of that ABC.mp4 file that how much downloaded and same case for the other activities.
Please let me know to you Services or any other way to do, so I can update the UI as well with the updated value of the downloading file. Any help is appreciated.
Well here's my piece of advice:
I did the same thing but with Pdf files a while a ago. First you need to choose a good Http client library to perform the downloads and forget about all the issues related to the downloads that you'll have if you perform this operations by yourself. I recommend you use the Ion librabry has a lot of useful features like cancel the downloads, attach callbacks to have an eye in the download progress, known if the download succeded, failed, etc.
Second, you obviously need a Service running in background, always, you can do this by making your own service, and It's very important that the Service process name in the android manifest is like android:name="com.company.app.services.MyService" and not like android:name=":MyRemoteService" doing so you'll make sure that the service will be running in background all the time (keep in mind that the OS can and will kill the service if It's neccesary, but the service will be restarted when the resources will made available again).
Third, to keep all the views, custom views, activities, fragments, etc. that display those files updated, you need trigger BroadcastReceivers from your Service. Keep in mind that doing so you can't use the LocalBroadcastReceiver, because your Service has its own process indipendent from your application.
Keep in mind that:
1) Theres no need to explicitly use an Activity, you can register your broadcasts anywhere where you see It fit. A RecyclerAdapter (most likely), a Fragment, or an Activity.
2) The communication App/Service is done through Intents so all data that you send to and from the Service must be Serializable.
3) You can use several different types of broadcast each one for differents situations (error, fail, success, progress, etc.) or you can use only one an send a enum that describe this kind of status through the Bundle of the Intent when you fire the broadcasts from your service
Hope this helps you, If you have any doubt, let me know.
I am trying to understand the need for task affinity in Android. I searched other SO answers as well.
I am particularly interested in the combination of a singleTask launch mode and task affinity.
For singleTask launch mode (OR Intent with NEW_TASK flag), system takes one of 3 actions:
If activity exists, it will resume it
If activity doesn't exist, it will look for a task with matching affinity to add the activity
Without finding a matching task, system will create a new task with this activity as root
I kind of understand the need to the first case from this answer. It talks about having same activity in multiple states, and how it can create inconsistency problems in user experience.
What I am more puzzled about is the second case - why does the system need to find an existing task with the same affinity ? What kind of use case does this fulfill and would break if this feature is disallowed ? Why is it necessary ?
From this link:
... if the intent passed to startActivity() contains the
FLAG_ACTIVITY_NEW_TASK flag, the system looks for a different task to
house the new activity. Often, it's a new task. However, it doesn't have to be.
If there's already an existing task with the same affinity as the new activity, the
activity is launched into that task. If not, it begins a new task.
The same link also talks about task reparenting. This is another feature
I cannot understand. The link does give an example of a weather/travel app:
... suppose that an activity that reports weather conditions in selected cities
is defined as part of a travel application. It has the same affinity as other
activities in the same application (the default application affinity) and it allows
re-parenting with this attribute. When one of your activities starts the weather
reporter activity, it initially belongs to the same task as your activity.
However, when the travel application's task comes to the foreground, the weather
reporter activity is reassigned to that task and displayed within it.
My question for this feature is similar. I'm not able to tell whether this feature is to fulfill some necessary user experience requirement OR is just a fancy add-on to tasks ? Why do activities need to be re-parented across tasks ?
Can someone please help me answer the above two questions ?
I'll take a stab at this!
I believe Android/Google's intentions were to have a seamless interaction for the user.
So when I read about affinity what came to mind were URLs, emails, documents and such. Does it make sense to ask the user what application to open especially if they already have one of the applications open that can handle the intent.
Same goes for re-parenting. The task opens another application but what happens when the user is finished with that task and wants to go back to the original application? In the user's perspective it is one experience regardless of how many applications are needed to meet that experience.
(I swear I read about this in a Material Design doc from Android....)
Application Flow Image (Cannot post directly - not enough reputation yet)
Introduction
We are creating an application that manages our products. We have several types of a products (1) and each type of product has dozens of those type (2) (ex. Videos).
We have an xml files on our website that holds all the information for each product. When a user selects the type of product (1) it reaches out to our website to download the xml file which populates the product list (2). The user then selects the product from the list which then passes the information to the product single activity (3).
Oh philosophy was when creating the application to create a place where the user can download the product and materials connected to it, but have the application manage which products you have downloaded. You download everything you need so when you don't have internet connection you are still able to use the application and view the products you have downloaded.
Problem
Some of the products in our app are fairly large and require an extended amount of time to download. When a user is on the product single activity (3) they can download the products and when a configuration change happens we understand we need to use fragments to maintain the progress bar and text on the button.
! The problem comes in when the user hits the back button.
We don't want to just cancel the download for the user.
It takes quite a while for the download to finish
We want the user to have the ability to download multiple products at once.
Not canceling the ASyncTask actually lets it continue running when the user hits the back button and even allows us to send Toast messages to show that it is still running. The problem comes in when the user navigates back to the activity the UI doesn't show the file is still downloading because we lost the reference to the ASyncTask that is running.
Solution
We are trying to come up with a solution so that the user can back out of the product single activity (3) and come back to it later and see the status of an ASyncTask if it was started earlier. The problem is if the activity is destroyed how do we hold on to a reference to the ASyncTask or Fragment.
The solution to your problem would be to use services. Services in Android are designed to be long running background tasks. Although you can't directly hook into the UI thread from services, you can use Handlers to post to the UI. Your service will stay around as long as they are needed (Android kills them only under low memory conditions and even then tries to stay away from the running ones).
AsyncTask is designed to be used only for short operations. It is possible to use it with some changes to run longer processes but Android prefers to not do it that way. Android specifically tries to steer you to use background threads and processes.
The problems that you are seeing are because AsyncTask (generally being defined from within the activity class) are tied to the Activity itself and maintains a reference to it. But when an activity goes to the background and has remained in the background for some time, the activity may be destroyed and GC'd at which point, the AsyncTask loses its reference to the parent. With services, it will not matter whether your activity is still available or not. You can connect to the service anytime you want and then query the service to find the status of the download.
first of all there are services that do background work even if your app is displayed on the screen or dead.. second of all there are threads that work and work and work..
thirdly there is a methon called onBind that binds an activity to a service..
your SOLUTION??
use threads in services and whenver your activity is called or app is opened
bind it to the service to get what you want...
NOTE: if your file takes some time to download, well then asynctask is not a recommended approach..that is if it takes a hell of a timee..
Hope im helpful...thnks
I am trying to understand conceptually what a task is in Android. So is it correct that a task can have multiple activities and can run one activity at a time? But is a task like a unix process? And each activity can be thought of as a thread within the process? Looking to clarify my somewhat weak understanding.
A task, unlike a Unix process, is basically an UI concept.
From the documentation - Tasks and Back Stacks
A task is a collection of activities that users interact with when
performing a certain job. The activities are arranged in a stack (the
"back stack"), in the order in which each activity is opened.
The activities that make up a task can belong to different applications (and hence, to different processes). That's why inter-activity communication in Android is done via Intents (basically, messaging objects than can be serialized) and not via direct method calls -- even when the called activity is part of the same application as the caller.
A user can switch freely between tasks (with the "Recents" button) but cannot move arbitrarily between the activities that make up a task. Normally they can only go one step back, via the "Back" button.
You should take a look at the documentation -- it's quite well explained there.
An Android application maps to a Unix process (more or less, since an app can run more than one process if it so desires) . But there is not a one-to-one mapping with tasks -- a task can contain activities from multiple applications, and a single application can have activities in multiple tasks.