-
-
Save parallelcross/b42ddbc65423c6b57c52 to your computer and use it in GitHub Desktop.
package com.mozu.mozuandroidinstoreassistant.app.loaders; | |
import com.mozu.api.MozuApiContext; | |
import com.mozu.api.contracts.productadmin.LocationInventoryCollection; | |
import com.mozu.api.contracts.productruntime.Product; | |
import com.mozu.api.resources.commerce.catalog.admin.products.LocationInventoryResource; | |
import rx.Observable; | |
import rx.Subscriber; | |
import rx.android.schedulers.AndroidSchedulers; | |
import rx.schedulers.Schedulers; | |
public class InventoryRetriever { | |
public Observable<LocationInventoryCollection> getInventoryData(final Product product, int tenantId, int siteId) { | |
final LocationInventoryResource inventoryResource = new LocationInventoryResource(new MozuApiContext(tenantId, siteId)); | |
return Observable | |
.create(new Observable.OnSubscribe<LocationInventoryCollection>() { | |
@Override | |
public void call(Subscriber<? super LocationInventoryCollection> subscriber) { | |
try { | |
subscriber.onNext(inventoryResource.getLocationInventories(product.getProductCode())); | |
subscriber.onCompleted(); | |
} catch (Exception e) { | |
subscriber.onError(e); | |
} | |
} | |
}) | |
.observeOn(AndroidSchedulers.mainThread()) | |
.subscribeOn(Schedulers.io()); | |
} | |
} |
package com.mozu.mozuandroidinstoreassistant.app.fragments; | |
import android.app.Fragment; | |
import android.os.Bundle; | |
import android.view.LayoutInflater; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.view.Window; | |
import android.widget.ImageView; | |
import android.widget.LinearLayout; | |
import android.widget.ListView; | |
import android.widget.ProgressBar; | |
import android.widget.TextView; | |
import com.crashlytics.android.Crashlytics; | |
import com.mozu.api.contracts.productadmin.LocationInventory; | |
import com.mozu.api.contracts.productadmin.LocationInventoryCollection; | |
import com.mozu.api.contracts.productruntime.Product; | |
import com.mozu.mozuandroidinstoreassistant.app.R; | |
import com.mozu.mozuandroidinstoreassistant.app.adapters.ProdDetailLocationInventoryAdapter; | |
import com.mozu.mozuandroidinstoreassistant.app.loaders.InventoryRetriever; | |
import java.util.List; | |
import butterknife.ButterKnife; | |
import butterknife.InjectView; | |
import rx.Observer; | |
import rx.Subscription; | |
import rx.android.observables.AndroidObservable; | |
public class ProductDetailInventoryFragment extends Fragment implements Observer<LocationInventoryCollection> { | |
private Product mProduct; | |
private int mTenantId; | |
private int mSiteId; | |
private List<LocationInventory> mInventory; | |
@InjectView(R.id.inventory_list) ListView mInventoryList; | |
@InjectView(R.id.inventory_progress) ProgressBar mProgress; | |
@InjectView(R.id.dialog_header) LinearLayout mDialogLayout; | |
private Subscription mSubscription; | |
public ProductDetailInventoryFragment() { | |
// Required empty public constructor | |
setRetainInstance(true); | |
} | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
mSubscription = AndroidObservable.bindFragment(this, new InventoryRetriever().getInventoryData(mProduct, mTenantId, mSiteId)).subscribe(this); | |
} | |
@Override | |
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { | |
View view = inflater.inflate(R.layout.product_detail_inventory_fragment, null); | |
ButterKnife.inject(this, view); | |
if (mInventory == null) { | |
mProgress.setVisibility(View.VISIBLE); | |
mInventoryList.setVisibility(View.GONE); | |
} else { | |
onCompleted(); | |
} | |
return view; | |
} | |
@Override | |
public void onDestroyView() { | |
mSubscription.unsubscribe(); | |
super.onDestroyView(); | |
} | |
public void onNext(LocationInventoryCollection inventoryCollection) { | |
mInventory = inventoryCollection.getItems(); | |
} | |
@Override | |
public void onCompleted() { | |
mProgress.setVisibility(View.GONE); | |
mInventoryList.setVisibility(View.VISIBLE); | |
mInventoryList.setAdapter(new ProdDetailLocationInventoryAdapter(getActivity(), mInventory,mTenantId,mSiteId)); | |
} | |
public void onError(Throwable error) { | |
Crashlytics.logException(error); | |
} | |
public void setProduct(Product product) { | |
mProduct = product; | |
} | |
public void setTenantId(int tenantId) { | |
mTenantId = tenantId; | |
} | |
public void setSiteId(int siteId) { | |
mSiteId = siteId; | |
} | |
} |
One minor note. I typically like to let the client set the observeOn
and subscribeOn
.
So your fragment code sets subscribeOn(Schedulers.IO).observeOn(AndroidSchedulers.mainThread)
.
Then later if you ever wish to write tests using Mockito you can use the same InventoryRetriever API and set the threads accordingly. (Typically you don't set any threads so it runs synchronously which simplifies testing)
@dlew im interested to know why you use defer instead of create? Is this something new that was updated recently?
One other thing you might want to change is to make your subscribe/unscubsribe calls in methods such as onResume/onPause... the AndroidObservable.bindFragment
insulates this from you a bit but typically when possible I always like to ensure the points where I subscribe and unsubscribe are in matching lifecycle methods.
This also helps for example when the user might background or resume your app you can suspend or refresh work when needed.
I responded on Twitter, but any Exceptions should just be naturally passed along to onError().
One other thing I might change: I'm personally used to creating my own anonymous inner classes for Subscribers. The reason being that there could be many, many different subscribers in one class.
Actually one more thing i just noticed.
You should change the line
Subscription mSubscription
to something like
Subscription mSubscription = Subscriptions.empty()
This should insulate you from any NPE errors if you decide to change where you subscribe and unsubscribe
Two thoughts:
Usually you don't need to call
Observable.create()
. I understand the problem you're trying to solve here; you can't just useObservable.just()
since your long-running call will happen immediately. Good news: combine it withObservable.defer()
and it'll work great!You should let the subscriber call
subscribeOn()
andobserveOn()
. Instead of calling it before returning the Observable, you should leave it be and call it right beforesubscribe()
.