I'm working with an app that grabs a decent amount of data upon start each time since I need to immediately know things like location and weather fcst in the area.
In my mind I see a loading animation that smoothly moves around for 3 to 7 seconds while everything runs so there isn't just a blank screen or a static title image.
BUT:: I'm running into issues with getting animations or images to load before all of the data is searched for. And I only want the animation to run as long as data is loading. So I have the application switch to a new activity as soon as everything is loaded.
Is there a way to for the animation to run before things are done or do I need to somehow set everything up as an async task. And then how do I pass the async task to the next activity?
So I found an answer to my own question after reading some books. In short, the loading screen that i was looking for uses a splash screen with asynchronous tasks. Either AsyncTask directly or you can implement a service solution.
Extra: I noticed that if you run an async task which starts a GoogleAPIClient, onConnected executes on a pool thread or something, point being you can do UI work on the main thread again without wrapping back to AsyncTask.
Related
Given a one-activity app like this:
public class MyActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
loadingScreen = new RelativeLayout(this);
// add a bitmap to loadingScreen
setContentView(loadingScreen);
Dict dict = new Dict();
dict.init();
// this method takes ~10 seconds
}
}
In theory, it looks like this would display a loading screen while the dictionary initializes. In practice, nothing is displayed until onCreate() returns, so the user sees a blank white screen for 10 seconds. What's the best way to display a please wait while this app loads screen?
I believe I could create a separate thread for dict.init(), but that seems like overkill in this case because I don't want the app to be usable or interactive while dict.init() runs. I'd like it to run on the main thread (and hang the rest of the app while it executes), I just want to display something on the screen first.
PS, I tried moving dict.init() to onStart(), that appeared to have no effect.
edit: Perhaps I should have clarified this to avoid getting "You're doing it wrong" type answers, but the init takes 2 or 3 seconds on modern phones and tables, 10 seconds is a worst-case on old phones. This app is a word game, it can't be used without the dictionary. Moving dict.init() to an async task will not improve the user's experience, and the question I asked is whether it's possible to display a splash screen without doing that. I gather that the answer is "No."
I'd like it to run on the main thread (and hang the rest of the app while it executes)
No, no wouldn't and your users wouldn't like you much either
I believe I could create a separate thread for dict.init(), but that seems like overkill in this case because I don't want the app to be usable or interactive while dict.init() runs.
This is exactly what you should do. You can use a variety of ways including an AsyncTask
and show a ProgressDialog while the work is being done.
so the user sees a blank white screen for 10 seconds.
If it is taking this long then you might want to rethink your flow. Even if you go with a separate Thread and show a ProgressBar, most users aren't going to want to stare at that for 10 seconds. You should load the data in the background and allow them to do something else while it loads, if possible. You could use something like an IntentService depending on how you are getting the data.
Example of AsyncTask
Painless Threading
I've got the following problem. In my app I'm loading data in an AsyncTask. The problem is, when the user now clicks on the icon to open the Navigation Drawer and opens up another fragment the app crashes. When the AsyncTask is finished the app doesn't crash. The problem that is encountering is, that when I switch the fragment (The fragments are always the same, just with another content dependent on the NavigationDrawer Item click) the app crashes.
I guess the problem is, that the async task isn't finished, I'm calling the same fragment again want to display different data.
So what would be my approach to handle this? Use for every different view a different fragment? I thought using the same fragment every time is much easier, since it's just displaying different data but the structure, layout etc. is all the same. Just the data that it gets is different.
I also thought about somehow "blocking" the user from doing any other actions while the asynctask but still show him that the app is processing. But that would be not the definition of an AsyncTask.
How would you approach it? Use different fragments for every different display? Or how? Block somehow? If a user clicks on an item of the navigation drawer the asynctask needs to stop all its actions (if some are done) and then restart doing all the actions. Is there a way to do it?
Please note that the fragment where the async is executed and the activity where the fragments are called are in two different files
You can either block the screen with a loading screen (not that good UX wise...) or you could cancel the asynctask when you change the fragment, in the destroy or detach method.
You didnt show the errors, but I would guess that the app crashes because you are trying to acess something in the asynctask onPostExecute method and it is no longer available...
I guess that it crashes because your AsyncTask is sending data to a class instance that doens't exist.You should change the Class that receives callbacks from asynctask. Anyway i can't give you a better answer till i will see your real code of AsyncTask ( at least onPostExecute() and onProgressUpdate())
use intent service to do that ask task means call ask task in a intent service that one is capable to handle background task without hang UI
As my app (game) is getting larger and larger, I've started to encounter a problem.
I have a menu activity with a 'start game' button - when the user presses this button, it starts the main game activity - now in this activity, I'm creating bitmaps etc in the constructor but there are so many that now when the activity starts, there is a slight delay - about 2 seconds - before the game actually starts.
I'm clearly doing something wrong - please could someone advise how to get around this so the delay (which clearly, has to happen) - isn't noticed by the user.
Load the ones you need immediately right away. Load the rest on a background thread (probably an AsyncTask). If you need one before it may be loaded, either pause or put up a loading screen as needed.
You could start loading the bitmaps in the background of your menu activity, or even when your app is created using a background thread or AsyncTask. You'll still need a loading screen of some sort in case the user navigates to the main game activity before you're done loading all of the bitmaps though.
You can also kick off an IntentService to load the bitmap. When the bitmap is loaded the IntentService can send a broadcast using LocalBroadcastManager. Then each component that cares about a result can register a BroadcastReceiver with LocalBroadcastManager.
I know it sounds crazy that someone is using runOnUiThread inside AsyncTask. Somehow, it is working for me but I wanna know if it is an acceptable and robust approach or not. Here is the scenario:
I have an app in which after successful login, user is rendered to next screen. In this new screen, 3 different methods are loading different types of data from a web server. These methods are:
getMembersForList() : It loads the list of community members and shows it in a listview.
getProfileData() : It loads the profile of logged in user and shows his name , image etc on the screen.
getNotificationCounts : It loads the count of new notifications for the user.
I applied 3 different approaches for it :
(1) Calling all 3 methods simply in onCreate i.e. no exclusive thread is being used for any of the methods . In this case , the transition from login screen to this screen becomes very slow and black screen shows up for some time before this activity shows up.
(2) Calling getMembersForList() on UI thread and the other 2 methods on exclusive threads. In this case transition becomes fast and list shows up quickly but Notification counts and username etc. don't show up because WrongThreadException occurs saying that this thread can't touch other thread's views (TextViews for username, notification count etc. which are declared globally) . The same thing happens when I start these threads from an AsyncTask as well.
(3) Calling getMembersForList() on UI thread and then starting an AsyncTask in which the other 2 methods are being called in "runOnUiThread" inside doInBackground() method. This solves both the above issues. Now the screen transition is faster and the WrongThread exception is also not occuring.
So far the approach-(3) is working good for me but I am not sure if this is the right way to do it because runOnUiThread and AsyncTask are 2 completely opposite things. Can anyone please clear my doubts about this scenario. Thanx in advance.
Yes, use-cases like this are a big reason why the runOnUiThread() method exists in the first place. The idea is you allow your background thread(s)/AsyncTask instance(s) to run your lengthy operations in the background, and then provide a simple hook that they can use to update the interface when they have the result (or at arbitrary intervals, as different pieces of the result become available).
As long as that's what you're doing, then your usage is fine. What you want to avoid doing is performing a lengthy operation on the main thread, either directly or indirectly by passing in some lengthy operation from a background thread.
Of course you don't have to do it that way if you don't want to. You could use postExecute() instead. Or you could store the result somewhere and then use any sort of message-passing API to notify the main thread that the result is ready, and so on.
I would advice to run all the 3 calls in the asyncTask, and update the UI in the postExecute() of the AsyncTask after the background taks is complete, postExecute runs on UIthread so you need not call anything explicit to run them on UIthread.
I've got activity that has to do many things before it is visible. In proccess of loading view I have to load up bitmap/drawable that consume some time and prevents from other actions that could be done in that time. So i decide to move it to another thread. I've used Async Task, but this is not solid way of loading things. There are situations where task starts 1-2 sec after my view is shown! Is there anothe way to load bitmap/drawable that will not consume so much time and will allow to assign it to ImageView?
It is likely that you are still blocking your UI thread before executing the task. Use a logger to verify when your task is being executed.
If the task does take up a lot of time to execute then the bitmaps you are loading may be too large, in which case you should look at the down-sampling the images you are loading using the inSampleSize option with BitmapFactory.
AsyncTask runs tasks from a thread pool which might already be fully in use so it might have to keep the tasks in queue until a thread frees up to run new task. Though I doubt this is the cause of the problem.
You should maybe consider displaying a progress indicator before the actual view you want to show to make sure all tasks are done before the user sees them.
Edit
you could also use task.get(); after running all the other tasks to wait for the bitmap loader to complete before showing anything... but do try to keep the UI responding!