Proper usage of Observable.create() in RxJava 2 (Best Practices) - java

I'm currently building a small Social Media style App which leverages RxJava 2 and Firebase. I'm using MVP style architecture, and I've abstracted out my AuthService with an interface called AuthSource.
For simplicity's sake, I'll work with a Single method in my Service:
public class FirebaseAuthService implements AuthSource {
private FirebaseAuth auth;
private FirebaseAuth.AuthStateListener listener;
//initialization code
#Override
public Maybe<User> getUser() {
return Maybe.create(new MaybeOnSubscribe<User>() {
#Override
public void subscribe(final MaybeEmitter<User> e) throws Exception {
if (auth == null) {
auth = FirebaseAuth.getInstance();
}
if (listener != null) {
auth.removeAuthStateListener(listener);
}
listener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
auth.removeAuthStateListener(listener);
if (firebaseUser != null) {
User user = new User(
firebaseUser.getDisplayName(),
firebaseUser.getEmail());
user.setUserId(firebaseUser.getUid());
Uri photoUrl = firebaseUser.getPhotoUrl();
if (photoUrl != null){
user.setProfilePhotoUrl(photoUrl.toString());
}
e.onSuccess(user);
} else {
e.onComplete();
}
}
};
auth.addAuthStateListener(listener);
}
}
);
}
}
interface AuthSource {
Maybe<User> getUser();
//Other methods etc.
}
Finally, I'll show my Presenter method which handles the call:
//from with a Presenter:
#Override
private void getUserData() {
disposableSubscriptions.add(
auth.getUser().subscribeOn(schedulerProvider.io())
.observeOn(schedulerProvider.ui())
.subscribeWith(
new DisposableMaybeObserver<User>() {
#Override
public void onError(Throwable e) {
view.makeToast(R.string.error_retrieving_data);
view.startDispatchActivity();
}
#Override
public void onComplete() {
}
#Override
public void onSuccess(User user) {
ProfilePagePresenter.this.currentUser = user;
view.setName(user.getName());
view.setEmail(user.getEmail());
if (user.getProfilePhotoUrl().equals("")) {
view.setDefaultProfilePhoto();
} else {
view.setProfilePhotoURI(user.getProfilePhotoUrl());
}
getUserProfileFromDatabase();
}
}
)
);
}
I realize the topic of the question is a bit general, so I'll try to narrow things down from here. The code I've posted above works insofar as I'm succesfully getting Data from Firebase's API using Create(). The problem is, I'm quite new to using RxJava 2, and I'm not certain what's going on under the hood here for garbage collection and memory leaks. I chose to use Observable.create() as per the RxJava 2 Docs:
"Provides an API (via a cold Observable) that bridges the reactive world with the callback-style world."
RxJava 2 Docs
Finally, the only proactive thing I'm doing at the moment to dispose of these Observables, is to call CompositeDisposable.clear() in my Presenter when events take the user to a new Activity.
Questions:
-Is it safe to assume that simply calling CompositeDisposable.clear() when the Presenter finishes, will handle my Garbage collection? (assuming I haven't created memory leaks in the rest of the code).
-If my understanding is correct, create() is a better option to use than fromCallable() in this case, as fromCallable() should be used for Synchronous events (i.e. not something like Firebase API callbacks)?
-Is it really as simple as just throwing my Asynchronous callbacks in Observable.create()? I'm terrified at how easy that is to do...

Is it safe to assume that simply calling CompositeDisposable.clear()
when the Presenter finishes, will handle my Garbage collection?
(assuming I haven't created memory leaks in the rest of the code).
It's a little trickier than this. Non-disposed Observable won't create memory leak if everything referenced by the Observable belong to the Activity scope. Both the producer and the consumer will be garbage collected alongside Activity. Memory leak may occur if you referenced resources that will survive the Activity, a provider instantiated at Application level for example. So if you want to use CompositeDisposable.clear() make sure to implement emitter.setCancellable() inside Observable.create() to dispose those leaky resources.
If my understanding is correct, create() is a better option to use
than fromCallable() in this case, as fromCallable() should be used for
Synchronous events (i.e. not something like Firebase API callbacks)?
create() use to be named fromAsync(). Use fromCallable() to wrap a synchronous method call, create() when wrapping callback code.
Is it really as simple as just throwing my Asynchronous callbacks in
Observable.create()? I'm terrified at how easy that is to do...
It is as easy ... if you take care of those pesky references outside of scope as mentioned at the first point.
Usually on Android, a memory leak involve the Context, which is big. Be sure to test your code. leakcanary is a great help for this matter.
Last, you could avoid doing the wrapping yourself by using an existing Firebase RxJava binding. Or take inspiration from them:
https://github.com/kunny/RxFirebase
https://github.com/ashdavies/rx-firebase
https://github.com/DariusL/RxFirebaseAndroid
https://github.com/ezhome/Android-RxFirebase
https://github.com/nmoskalenko/RxFirebase
https://github.com/VictorAlbertos/RxFcm

Calling clear will detach the subscriber - the code that reacts to the emitted events, from the Observable, and as a result the subscriber which is enclosed by the presenter/activity and has hard reference to it, will no longer be held by the observer and lived longer than the presenter/activity lifecycle.
But, beware, you still can cause leaks if your Observable itself contains references to your presenter/activity.
In either cases, leak will occur when you reference your activity/presenter by static or other object that lives in longer (for instance Application) context than your activity/presenter.
Indeed, create() method is the correct way to create Observable from async method (BTW, in RxJava1, there was a different obsolete way that called also create, but it was changed in RxJava2, so there will be no way of creating Observable wrongly, but that's a different story)
Well, you still need to make sure you obey to the Observable contract,
make sure that there will be terminal event (either onComplete/onError),
there will be no onNext after terminal event (onCompleted/onError), and backpressure (which is enforced with Flowable Observable)

Related

Best way to return data to MainActivity from AsyncTask

I'm using an ASyncTask in my app to get some data (a short URL) via a REST API from a web service (Bitly).
When the ASyncTask completes I want to pass the result back to my MainActivity.
Getting the data back to the MainActivity is acheievd by using the onPostExecute method of the AsyncTask.
I've read and read and read about how to do this and there seem to be two general approaches.
Originally I was using a 'WeakReference' approach whereby at the start of the AsyncTask class you create a weak reference to your MainActivity as follows:
private class getShortURL extends AsyncTask<String, Void, String> {
private WeakReference<MainActivity> mainActivityWeakReference;
myASyncTask(MainActivity activity) {
mainActivityWeakReference = new WeakReference<>(activity);
}
{etc etc}
With this approach your AsyncTask class sits outside of your MainActivity class and so a lot of things need to be referenced via the weak reference.
This worked fine (except I suspected - possibly incorrectly - that this weak reference may have been the cause of occassional NPEs), but I then found another way of doing things.
This second approach involved moving the ASyncTask class inside of the MainActivity class.
This way I was able to access everything that was accessible in the MainActivity class directly, inlcuding UI elements and methods defined in the MainActivity. It also means that I can access resources such as strings etc and can generate toasts to advise the user what is happening.
In this case the whole of the WeakReference code above can be removed and the AsyncTask class can be made private.
I am also then able to do things like this directly in onPostExecute or to keep this in a method within the MainActivity that I can call directly from onPostExecute:
shorten_progress_bar.setIndeterminate(false);
shorten_progress_bar.setVisibility(View.INVISIBLE);
if (!shortURL.equals("")) {
// Set the link URL to the new short URL
short_link_url.setText(shortURL);
} else {
CommonFuncs.showMessage(getApplicationContext(), getString(R.string.unable_to_shorten_link));
short_link_url.setHint(R.string.unable_to_shorten_link);
}
(note that CommonFuncs.showMessage() is my own wrapper around the toast function to make it easier to call).
BUT, Android Studio then gives a warning that "the AsyncTask class should be static or leaks might occur".
If I make the method static I then get a warning that the method from the MainActivity that I want to call from onPostExecute cannot be called as it is non-static.
If I make that method from MainActivity a static method, then it cannot access string resources and any other methods that are non static - and down the rabbit hole I go!
The same is true, as you would expect, if I just move the code from the method in the MainActivity into the onPostExecute method.
So...
Is having an AsyncTask as a non-static method really a bad thing? (My
app seems to work fine with this warning in AS, but I obviously don't
want to be creating a memory leak in my app.
Is the WeakReference appraoch actually a more correct and safer approach?
If I use the WeakReference approach, how can I create things like toasts which need to be run on the UI thread and access string
resources etc from the MainActivity?
I read somewhere about creating an interface but got a bit lost and couldn't find that again. Also would this not have the same kind of reliance on the MainActivity that a WeakReference does and is that a bad thing?
I'm really looking for best practice guidance on how to get some data back to the MainActivity and the UI thread from an AsyncTask that is safe and doesn't risk memory leaks.
Is having an AsyncTask as a non-static method really a bad thing? (My app seems to work fine with this warning in AS, but I obviously don't want to be creating a memory leak in my app.
Yes, your Views and your Context will leak.
Enough rotations and your app will crash.
Is the WeakReference approach actually a more correct and safer approach?
It's lipstick on a dead pig, WeakReference in this scenario is more-so a hack than a solution, definitely not the correct solution.
What you're looking for is a form of event bus from something that outlives the Activity.
You can use either retained fragments* or Android Architecture Component ViewModel for that.
And you'll probably need to introduce Observer pattern (but not necessarily LiveData).
If I use the WeakReference approach, how can I create things like toasts which need to be run on the UI thread and access string resources etc from the MainActivity?
Don't run that sort of thing in doInBackground().
I'm really looking for best practice guidance on how to get some data back to the MainActivity and the UI thread from an AsyncTask that is safe and doesn't risk memory leaks.
The simplest way to do that would be to use this library (or write something that does the same thing yourself, up to you), put the EventEmitter into a ViewModel, then subscribe/unsubscribe to this EventEmitter inside your Activity.
public class MyViewModel: ViewModel() {
private final EventEmitter<String> testFullUrlReachableEmitter = new EventEmitter<>();
public final EventSource<String> getTestFullUrlReachable() {
return testFullUrlReachableEmitter;
}
public void checkReachable() {
new testFullURLreachable().execute()
}
private class testFullURLreachable extends AsyncTask<Void, Void, String> {
...
#Override
public void onPostExecute(String result) {
testFullUrlReachableEmitter.emit(result);
}
}
}
And in your Activity/Fragment
private MyViewModel viewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
// ...
}
private EventSource.NotificationToken subscription;
#Override
protected void onStart() {
super.onStart();
subscription = viewModel.getTestFullUrlReachable().startListening((result) -> {
// do `onPostExecute` things here
});
}
#Override
protected void onStop() {
super.onStop();
if(subscription != null) {
subscription.stopListening();
subscription = null;
}
}

RxJava and long running listener

Okay, so I am new to RxJava2 (well, I don't know RxJava either) and am trying to develop an Android app using RxJava2 and MVP structure.
In that app, I am making async calls to a library that uses listeners.
I set the listener using a "standard" setListener / registerListener method.
One of the method is returning values "realtime" -> I call the start() method of my library, and then will be notified on my listener at each modification of the list (when there is an add/remove of the items).
I don't really grasp how I can achieve this behavior using RxJava, as the listener is subscribed in the definition of the emitter / subscriber?
Where should I declare the listener ? Where should I unsubscribe ? What object should I be using?
I started the dev using Nucleus, but can switch to another boilerplate or do one myself.
Here is some pseudo-code illustrating my question:
Before
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
mMyLib.setListener(this);
mMyLib.startDiscovery();
}
#Override
public void itemListChanged(List<Dummy> items) {
// update the UI with the list items
}
#Override
protected void onDestroy() {
super.onDestroy();
mMyLib.setListener(null);
}
Using Nucleus, in my presenter
Where should I unsubscribe if I want to receive modifications of the list as long as my activity / presenter are alive? Am I even using the right syntax/ objects?
private static final int REQUEST_ITEMS = 1;
private PublishSubject<Integer> pageRequests = PublishSubject.create();
...
#Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
restartableReplay(REQUEST_ITEMS,
() -> Observable.create(e ->
{
mMyLib.setListener(new MyLib.Listener() {
#Override
public void itemListChanged(List<Dummy> items) {
Log.d(TAG, "meh itemListChanged");
e.onNext(items);
e.onComplete();
}
});
mMyLib.startDiscovery();
}
)
,
MainFragment::onItems,
MainFragment::onNetworkError);
}
void request() {
start(REQUEST_ITEMS);
}
You're in the right direction, this is a valid way to wrap the async callbacks with RxJava, few comments:
Your'e calling e.onComplete() on itemListChanged, this is wrong, as it will end your Observable sequence, you might not need to call onComplete() at all, as it is never ending notifications from outer source, or call it once upon real end of notifications (outer source finish to produce items), do not confuse it with unsubscribing from source.
For unsubscription logic to do something you should define it in your create(), call e.setCancellable() with your cancellation logic (mMyLib.setListener(null) or any additional clean up resources code)
it's seems in this case that you have only 1 subscriber, but otherwise consider to use share(), to have a 'hot' Observable that can multicast to several subscribers.
as for Nucleus library, as far as I remember restartableReplay, will cache your'e Observable and replay emitted items, this is might be wrong with this kind of 'hot' stream of events (unless you need to replay maybe last emission or something), additionally, cache will be problematic as you will lose unsubscription ability, so just be sure to use Nucleus right here.
Where should I unsubscribe if I want to receive modifications of the list as long as my activity / presenter are alive? Am I even using the right syntax/ objects?
You simply need to unsubscribe wherever you want to stop getting notifications, whether it is at onStop() or onDestory() depends is up to you.

Mongodb async java driver find()

I have a webapp in which I have to return the results from a mongodb find() to the front-end from my java back-end.
I am using the Async Java driver, and the only way I think I have to return the results from mongo is something like this:
public String getDocuments(){
...
collection.find(query).map(Document::toJson)
.into(new HashSet<String>(), new SingleResultCallback<HashSet<String>>() {
#Override
public void onResult(HashSet<String> strings, Throwable throwable) {
// here I have to get all the Json Documents in the set,
// make a whole json string and wake the main thread
}
});
// here I have to put the main thread to wait until I get the data in
// the onResult() method so I can return the string back to the front-end
...
return jsonString;
}
Is this assumption right or thereĀ“s another way to do it?
Asynchronous APIs (any API based on callbacks, not necessarily MongoDB) can be a true blessing for multithreaded applications. But to really benefit from them, you need to design your whole application architecture in an asynchronous fashion. This is not always feasible, especially when it is supposed to fit into a given framework which isn't built on callbacks.
So sometimes (like in your case) you just want to use an asynchronous API in a synchronous fashion. In that case, you can use the class CompletableFuture.
This class provides (among others) two methods <T> get() and complete(<T> value). The method get will block until complete is called to provide the return value (should complete get called before get, get returns immediately with the provided value).
public String getDocuments(){
...
CompletableFuture<String> result = new CompletableFuture<>(); // <-- create an empty, uncompleted Future
collection.find(query).map(Document::toJson)
.into(new HashSet<String>(), new SingleResultCallback<HashSet<String>>() {
#Override
public void onResult(HashSet<String> strings, Throwable throwable) {
// here I have to get all the Json Documents in the set and
// make a whole json string
result.complete(wholeJsonString); // <--resolves the future
}
});
return result.get(); // <-- blocks until result.complete is called
}
The the get()-method of CompletableFuture also has an alternative overload with a timeout parameter. I recommend using this to prevent your program from accumulating hanging threads when the callback is not called for whatever reason. It will also be a good idea to implement your whole callback in a try { block and do the result.complete in the finally { block to make sure the result always gets resolved, even when there is an unexpected error during your callback.
Yes, you're right.
That's the correct behaviour of Mongo async driver (see MongoIterable.into).
However, Why don't you use sync driver in this situation? Is there any reason to use async method?

Best way to sequence a pair of external service calls in Akka

I need to geocode an Address object, and then store the updated Address in a search engine. This can be simplified to taking an object, performing one long-running operation on the object, and then persisting the object. This means there is an order of operations requirement that the first operation be complete before persistence occurs.
I would like to use Akka to move this off the main thread of execution.
My initial thought was to use a pair of Futures to accomplish this, but the Futures documentation is not entirely clear on which behavior (fold, map, etc) guarantees one Future to be executed before another.
I started out by creating two functions, defferedGeocode and deferredWriteToSearchEngine which return Futures for the respective operations. I chain them together using Future<>.andThen(new OnComplete...), but this gets clunky very quickly:
Future<Address> geocodeFuture = defferedGeocode(ec, address);
geocodeFuture.andThen(new OnComplete<Address>() {
public void onComplete(Throwable failure, Address geocodedAddress) {
if (geocodedAddress != null) {
Future<Address> searchEngineFuture = deferredWriteToSearchEngine(ec, addressSearchService, geocodedAddress);
searchEngineFuture.andThen(new OnComplete<Address>() {
public void onComplete(Throwable failure, Address savedAddress) {
// process search engine results
}
});
}
}
}, ec);
And then deferredGeocode is implemented like this:
private Future<Address> defferedGeocode(
final ExecutionContext ec,
final Address address) {
return Futures.future(new Callable<Address>() {
public Address call() throws Exception {
log.debug("Geocoding Address...");
return address;
}
}, ec);
};
deferredWriteToSearchEngine is pretty similar to deferredGeocode, except it takes the search engine service as an additional final parameter.
My understand is that Futures are supposed to be used to perform calculations and should not have side effects. In this case, geocoding the address is calculation, so I think using a Future is reasonable, but writing to the search engine is definitely a side effect.
What is the best practice here for Akka? How can I avoid all the nested calls, but ensure that both the geocoding and the search engine write are done off the main thread?
Is there a more appropriate tool?
Update:
Based on Viktor's comments below, I am trying this code out now:
ExecutionContext ec;
private Future<Address> addressBackgroundProcess(Address address) {
Future<Address> geocodeFuture = addressGeocodeFutureFactory.defferedGeocode(address);
return geocodeFuture.flatMap(new Mapper<Address, Future<Address>>() {
#Override
public Future<Address> apply(Address geoAddress) {
return addressSearchEngineFutureFactory.deferredWriteToSearchEngine(geoAddress);
}
}, ec);
}
This seems to work ok except for one issue which I'm not thrilled with. We are working in a Spring IOC code base, and so I would like to inject the ExecutionContext into the FutureFactory objects, but it seems wrong for this function (in our DAO) to need to be aware of the ExecutionContext.
It seems odd to me that the flatMap() function needs an EC at all, since both futures provide one.
Is there a way to maintain the separation of concerns? Am I structuring the code badly, or is this just the way it needs to be?
I thought about creating an interface in the FutureFactory's that would allow chaining of FutureFactory's, so the flatMap() call would be encapsulated in a FutureFactory base class, but this seems like it would be deliberately subverting an intentional Akka design decision.
Warning: Pseudocode ahead.
Future<Address> myFutureResult = deferredGeocode(ec, address).flatMap(
new Mapper<Address, Future<Address>>() {
public Future<Address> apply(Address geocodedAddress) {
return deferredWriteToSearchEngine(ec, addressSearchService, geocodedAddress);
}
}, ec).map(
new Mapper<Address, SomeResult>() {
public SomeResult apply(Address savedAddress) {
// Create SomeResult after deferredWriteToSearchEngine is done
}
}, ec);
See how it is not nested. flatMap and map is used for sequencing the operations. "andThen" is useful for when you want a side-effecting-only operation to run to full completion before passing the result on. Of course, if you map twice on the SAME future-instance then there is no ordering guaranteed, but since we are flatMapping and mapping on the returned futures (new ones according to the docs), there is a clear data-flow in our program.

In android, how can I separate the data loading into its own thread?

So I'm working on my "hello world" application in android/java, and elected to do a sports app (which is strange...I don't like sports...but whatever). So I set up my layout, allow users to 'drill down', so they can see the layout for Baseball, or MLB, or the Indians. Say a user selects 'Indians' from the MLB view. I update the tabs, potentially the color scheme, background, etc, and load the data for the 'news' and 'players' tabs (the latter of which is unique to team layouts). Unfortunately, api calls can sometimes take relatively long to complete, especially when the free API from ESPN is capped at 1 call per second. I do some significant caching already, but there's no way I can guarantee that I won't be loading both 'news' and 'players' for 'Indians' at the same time, so one of the requests will have to wait a full second to return.
So my solution is to have a data loading thread - the UI says 'get me this data', and does the UI work not contingent on the data being there. The question though is - once the data is returned from the data loader (as each piece comes back), how should it update or notify the UI appropriately? My current thought is:
UI thread:
OnSelectIndians()
{
DataLoadThread.GetIndiansPlayers();
DataLoadThread.GetIndiansNews();
// UI stuff
}
OnPlayersLoaded(Array Players)
{
if (layout == INDIANS_LAYOUT) // Make sure we haven't changed layouts
{
foreach player in Players
tab[PLAYERS].textview.text += player
}
}
But this isn't a problem I've had to deal with before. Is this the right way to go about it? Or is there a better/easier design I can use? I don't particularly like requiring the UI thread to have a 'on data returned' method for every type of data I can request. My other loosely-formed idea is to create a lambda function in the UI code, which is passed to the data loader and executed in the data loading thread, so:
DataLoadThread.Queue(
foreach player in GetIndiansPlayers()
myView.tab[PLAYERS].textview.text += player;
);
But I think this is probably the worse route, as now we have 2 threads interacting with the UI. Any advice?
Edit: Okay I got it working using AsyncTask. Out of the box, it still has the problem listed above that I would have to create a new derived class for every type if data I load (so PlayerLoadTask, NewsLoadTask, StandingsLoadTask, etc etc). I also wanted was to have most of the logic visible during the call, so if I'm looking at the event code I know what its doing. Below is the working implementation - would appreciate any feedback on it, but I'll accept the first answer below just the same.
abstract public class LoadDataHelper {
public LoadDataHelper(DataLoader dl, Object param) {
mDataLoader = dl;
mParam = param;
}
abstract public LinkedList<String> LoadData();
protected DataLoader mDataLoader;
protected Object mParam;
}
abstract public class UpdateUIHelper {
public UpdateUIHelper(MyActivity context) {
mContext = context;
}
abstract public void UpdateUI(LinkedList<String> results);
protected MyActivity mContext;
}
private class LoadDataTask extends AsyncTask<Void, Void, LinkedList<String> > {
private LoadDataHelper mLdh;
private UpdateUIHelper mUih;
LoadDataTask(LoadDataHelper ldh, UpdateUIHelper uih) {
mLdh = ldh;
mUih = uih;
}
#Override
protected LinkedList<String> doInBackground(Void... params) {
return mLdh.LoadData();
}
#Override
protected void onPostExecute(LinkedList<String> results) {
mUih.UpdateUI(results);
}
}
//
// .....
//
LoadDataTask task = new LoadDataTask(new LoadDataHelper(mDataLoader, "football") {
public LinkedList<String> LoadData() {
return mDataLoader.LoadLeaguesFromSport((String)mParam);
}
},
new UpdateUIHelper(this) {
public void UpdateUI(LinkedList<String> results) {
TextView tv = (TextView)findViewById(R.id.tv1);
tv.setText("");
for (String res : results) {
tv.append(res + "\n");
}
}
});
task.execute();
Take a look at:
1) AsyncTask
http://developer.android.com/reference/android/os/AsyncTask.html
The AsyncTask.onPostExecute will be executed in the UI thread.
I think this is the most common technique to do background processing.
2) runOnUIThread: If you are managing your own worker thread, you can use this in a worker thread to make sure code is run on the UI thread.
Its always better to have UI work in UI thread, and Non-UI work in Non-UI thread, But this became a Law from the arrival of HoneyComb in Android.
2 ways to do it in Android.
1. Use Java thread with Handler..
Create a thread to do the process heavy background task, and then display the data using
Handler...
2. Use AsyncTask<>, which is specially designed for Android, to sync the UI work and Non-UI
work. AsyncTask is also known as painless threading.
This is what AsyncTask was designed to do ,
Here is the tutorial that I learned from.
Here is what you do
Create a class that extends AsyncTask
Implement doInBackground and onPostUpdate methods
In the onPostUpdate method update the ui , you can use runOnUiThread to avoid any issues during ui update
The advantage of this using Async tasks is that you can even update the progress and display a visual indicator to the user , You can as easily cancel the task to stop the loading if required
AsyncTask is essentially a helper that simplifies the use of threads
Your best bet is to use the AsyncTask. I created a similar app that made 25+ calls to a server to download images. Using the AsyncTask will cut that time greatly, and still provide a great user experience. Here is a great tutorial on how to use/setup an AsyncTask:
http://www.peachpit.com/articles/article.aspx?p=1823692&seqNum=3
async task is the solution for you
here is a tutorial

Categories

Resources