Android syncronization not working - android

In one of my Android apps I'm using a singleton class to manage InApp billing. Inside this class I'm using a list of interfaces to notify responses from the InApp billing server.
Since my app is multi thread I would like this list to be syncronized, so I've done this:
public class InAppPurchasesManager {
...
private List<InAppPurchasesInterface> requestProductsListeners;
...
public static InAppPurchasesManager getInstance() {
if (mInstance == null) {
mInstance = new InAppPurchasesManager();
}
return mInstance;
}
private InAppPurchasesManager() {}
public void initInAppPurchasesManager(Application app) {
ctxt = app.getApplicationContext();
mInstance.requestProductsListeners = Collections.synchronizedList(new ArrayList());
}
...
public void addRequestProductListener(InAppPurchasesInterface listener)
{
synchronized(requestProductsListeners)
{
if(!requestProductsListeners.contains(listener))
requestProductsListeners.add(listener);
}
}
public void removeRequestProductListener(InAppPurchasesInterface listener)
{
synchronized(requestProductsListeners)
{
requestProductsListeners.remove(listener);
}
}
private void responseOnRequestProductsAndPurchase(boolean success)
{
callingIabHelper = false;
synchronized(requestProductsListeners)
{
for(InAppPurchasesInterface listener : requestProductsListeners)
listener.onRequestProductsAndPurchased(success);
return;
}
}
...
public interface InAppPurchasesInterface {
void onServiceStarted(boolean success);
void onRequestProductsAndPurchased(boolean success);
void onRequestProductPurchased(Purchase purchase, int error);
}
}
But I'm still receiveing a lot of crashes due to concurrent access to requestProductListeners.
This is a crash sample:
Fatal Exception: java.util.ConcurrentModificationException
at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573)
at com.mypackage.managers.InAppPurchasesManager.responseOnRequestProductsAndPurchase(InAppPurchasesManager.java:173)
at com.mypackage.managers.InAppPurchasesManager.access$100(InAppPurchasesManager.java:24)
at com.mypackage.managers.InAppPurchasesManager$2.onQueryInventoryFinished(InAppPurchasesManager.java:145)
at com.mypackage.auxiliary.inappbilling.IabHelper$2$1.run(IabHelper.java:741)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:7329)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
Since I'm not an expert with syncronization and multithreading I'm sure I'm doing something wrong. Should any of the solutions of these questions work? https://stackoverflow.com/a/2120409
Maybe adding "synchronized" to the definition of the methods that use requestProductsListeners?
EDIT:
I finally added synchronized but the crashes due to "java.util.ConcurrentModificationException" keep appearing.
This is my code now:
public class InAppPurchasesManager {
...
private List<InAppPurchasesInterface> requestProductsListeners;
...
public static InAppPurchasesManager getInstance() {
if (mInstance == null) {
mInstance = new InAppPurchasesManager();
}
return mInstance;
}
private InAppPurchasesManager() {}
public void initInAppPurchasesManager(Application app) {
ctxt = app.getApplicationContext();
mInstance.requestProductsListeners = Collections.synchronizedList(new ArrayList());
}
...
public synchronized void addRequestProductListener(InAppPurchasesInterface listener)
{
synchronized(requestProductsListeners)
{
if(!requestProductsListeners.contains(listener))
requestProductsListeners.add(listener);
}
}
public synchronized void removeRequestProductListener(InAppPurchasesInterface listener)
{
synchronized(requestProductsListeners)
{
requestProductsListeners.remove(listener);
}
}
private synchronized void responseOnRequestProductsAndPurchase(boolean success)
{
callingIabHelper = false;
synchronized(requestProductsListeners)
{
for(InAppPurchasesInterface listener : requestProductsListeners)
listener.onRequestProductsAndPurchased(success);
return;
}
}
...
public interface InAppPurchasesInterface {
void onServiceStarted(boolean success);
void onRequestProductsAndPurchased(boolean success);
void onRequestProductPurchased(Purchase purchase, int error);
}
}
What am I missing?
EDIT 2:
To answer the comment of Maxim Blumental I add the following information:
addRequestProductListener method (add a listener to the array) is called in OnResume() method of some fragments which need the products and their prices.
responseOnRequestProductsAndPurchase method (iterate through the array of listeners calling the callback) is called once Google has sent the information about products and their prices.
removeRequestProductListener method (remove the listener from the array) is called once the callback just mentioned has finished.
initInAppPurchasesManager is only called in
public class MyApp extends MultiDexApplication {
#Override
public void onCreate() {
super.onCreate();
InAppPurchasesManager.getInstance().initInAppPurchasesManager(this);
}

Related

Why retrofit returning Null 'LiveData' even after setting return value non-null correctly?

I got the response correctly, set value of LiveData correctly (got confirmed by printing value on console after setting value to live data). But When i tried to print same thing just before "return" it's giving me NullPointerException.
public class ProjectRepository {
private ProjectRepository instance;
Context context;
public ProjectRepository(Context context) {
this.context=context;
}
private MutableLiveData<List<PojoDivision>> data = new MutableLiveData<>();
public LiveData<List<PojoDivision>> getDivisionList() {
((RetrofitConfiguration)context).getDivisionRestApiWithAuthentication().getDivisionList().enqueue(new Callback<List<PojoDivision>>() {
#Override
public void onResponse(Call<List<PojoDivision>> call, Response<List<PojoDivision>> response) {
if (response.isSuccessful()) {
System.out.println(response.body().get(4).getName()); // this is printing
data.setValue(response.body());
System.out.println(data.getValue().get(4).getName()); // this is printing
}
}
#Override
public void onFailure(Call<List<PojoDivision>> call, Throwable t) {
Log.d(TAG, t.getMessage());
}
});
/*
following code is not printing with nullPointerException
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object java.util.List.get(int)' on a null object reference
*/
System.out.println(data.getValue().get(4).getName());
return data;
}
}
Since you're using a LiveData object at the class level for your repository class, your method has no need to return anything. Instead it's responsibility is for updating that LiveData object.
public class ProjectRepository {
private static final String TAG = "ProjectRepository";
private ProjectRepository instance;
Context context;
public ProjectRepository(Context context) {
this.context = context;
}
public MutableLiveData<List<PojoDivision>> data = new MutableLiveData<>();
public void getDivisionList() {
((RetrofitConfiguration) context).getDivisionRestApiWithAuthentication().getDivisionList().enqueue(new Callback<List<PojoDivision>>() {
#Override
public void onResponse(Call<List<PojoDivision>> call, Response<List<PojoDivision>> response) {
if (response.isSuccessful()) {
data.postValue(response.body());
}
}
#Override
public void onFailure(Call<List<PojoDivision>> call, Throwable t) {
Log.d(TAG, t.getMessage());
}
});
}
}
The clients of this class would need to 1) observe the LiveData object, and 2) call the getDivisionList() method to trigger an update:
class MyFragment extends Fragment {
private ProjectRepository repository;
private void setRepository() {
Context context = getContext();
if (context == null) return;
repository = new ProjectRepository(context);
}
public void observeData() {
repository.data.observe(this, new Observer<List<PojoDivision>>() {
#Override
public void onChanged(List<PojoDivision> pojoDivisions) {
// do something with updated data
}
});
}
public void triggerUpdate() {
repository.getDivisionList();
}
}

RxJava - ReplaySubject only emitting data twice

I am new to ReactiveX and I have a case where I want my observable to emit data to a late subscriber(whenever the observer subscribes, observable should emit the same data that it emitted previously). I made this Observable class that provide ReplaySubject's same instance to all observers (it is singleton class).
public class AccountsObservable {
private static ConnectableObservable<String> hotObservable;
private static AccountsObservable accountsObservable;
public static AccountsObservable getObject() {
if (accountsObservable == null) {
accountsObservable = new AccountsObservable();
}
return accountsObservable;
}
public ConnectableObservable<String> getObservable() {
if (hotObservable == null) {
Observable<String> observable = ReplaySubject.create(new ObservableOnSubscribe<String>() {
#Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
emitter.onNext("XYZ");
emitter.onComplete();
}
});
hotObservable = observable.replay();//publish
}
return hotObservable;
}
}
Similarly, this is the observer class that creates new observer instance.
public class AccountsObserver {
AccountsFetchListener listener;
public AccountsObserver(AccountsFetchListener listener) {
this.listener = listener;
}
public Observer<String> getObserver() {
return new Observer<String>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(String accounts) {
listener.onSuccess(accounts);
}
#Override
public void onError(Throwable e) {
listener.onFailure();
}
#Override
public void onComplete() {
}
};
}
public interface AccountsFetchListener {
void onSuccess(String accounts);
void onFailure();
}
}
Here is the function where I test these observables
private void testObs() {
ConnectableObservable<String> observable = AccountsObservable.getObject().getObservable();
Observer<String> observer = new AccountsObserver(new AccountsObserver.AccountsFetchListener() {
#Override
public void onSuccess(String accounts) {
Log.e("DATA -> ", accounts);
}
#Override
public void onFailure() {
}
}).getObserver();
observable.subscribe(observer);
observable.connect();
}
I called this function "testObs()" 5 times but it emitted data only 2 times. The problem seems to be in AccountsObservable class where I provide ReplaySUbject's instance. Thanks
Your code runs fine as it is, your logs are being suppressed in logcat as per this:
We declared an application as too chatty once it logs more than 5 lines a second. Please file a bug against the application's owner that is producing this developer-verbose-debug-level class logging spam. The logs are 256KB, that means the application is creating a DOS attack and shortening the logs timepan to 6 seconds(!) making it useless for all others.
You can avoid this behaviour by whitelisting your app for logcat:
adb logcat -P '<pid or uid of your app>'

How to test presenter on android (MVP)?

I've never create unit testing before. I'm planning to create UI test & Unit test for my presenter & datasource. I use Retrofit, RxJava, and Dagger in my apps.
Here's what i've tried so far
DataSource (My Datasource is coming from API)
public class DataSource implements DataSourceContract {
private static DataSource dataSource;
#Inject
SharedPreferences sharedPreferences;
#Inject
NewsService newsService;
private DataSource(Context context) {
DaggerAppComponent.builder()
.networkModule(new NetworkModule(API_URL))
.appModule(new AppModule(context.getApplicationContext()))
.preferencesModule(new PreferencesModule())
.build()
.inject(this);
}
public static synchronized DataSource getInstance(Context context) {
if(dataSource == null) {
dataSource = new DataSource(context);
}
return dataSource;
}
public String parseError(Throwable e) {
if(e instanceof SocketTimeoutException) {
return ERROR_TIMEOUT;
}
else if(e instanceof SocketException) {
return ERROR_NO_CONNECTION;
}
else {
return ERROR_SERVER;
}
}
#Override
public DisposableObserver<NewsResponse> getNews(final Callback<NewsResponse> callback) {
return newsService.getNews()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableObserver<NewsResponse>() {
#Override
public void onNext(NewsResponse value) {
callback.onSuccess(value);
}
#Override
public void onError(Throwable e) {
callback.onFailure(e);
}
#Override
public void onComplete() {
}
});
}
}
Presenter
public class MainPresenter implements MainContract.Presenter {
private MainContract.View view;
private DataSource dataSource;
private Disposable dispossable;
public MainPresenter(MainContract.View view, DataSource dataSource) {
this.view = view;
this.dataSource = dataSource;
}
#Override
public void onStart() {
getNews();
}
#Override
public void onStop() {
if(dispossable != null && !dispossable.isDisposed()) {
dispossable.dispose();
}
}
#Override
public void getNews() {
view.setLoading(true);
dispossable = dataSource.getNews(new DataSourceContract.Callback<NewsResponse>() {
#Override
public void onSuccess(NewsResponse responseData) {
try {
switch (responseData.getStatus()) {
case API_SUCCESS:
view.setLoading(false);
view.getNewsSuccess(responseData.getArticles());
break;
default:
view.setLoading(false);
view.getNewsFailed(responseData.getStatus());
break;
}
}
catch (Exception e) {
view.setLoading(false);
view.getNewsFailed(ERROR_SERVER);
}
}
#Override
public void onFailure(Throwable e) {
view.setLoading(false);
view.isNetworkFailed(dataSource.parseError(e), false);
}
});
}
}
And this is the test of my presenter
public class MainPresenterTest {
#Mock
DataSource dataSource;
#Mock
MainContract.View view;
MainContract.Presenter presenter;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
presenter = new MainPresenter(view, dataSource);
}
#Test
public void getNews() throws Exception {
List<Article> articleList = new ArrayList<>();
presenter.getNews();
Mockito.verify(view, Mockito.only()).getNewsSuccess(articleList);
}
}
But there is error when I run the test
Wanted but not invoked:
view.getNewsSuccess([]);
-> at com.java.mvp.view.main.MainPresenterTest.getNews(MainPresenterTest.java:37)
I have no problem running this apps on the device, but I can't make it work on testing
Any idea how to fix this presenter test? Am I doing it right?
And how do I test my datasource? I have no idea how to test this one
Thank you
Keep things simple. You are testing your presenter, not the data source. Add new methods to your presenter for the success and error responses. Then add two tests: one for the success and one for the error.
#Override
public void getNews() {
view.setLoading(true);
dispossable = dataSource.getNews(new DataSourceContract.Callback<NewsResponse>() {
#Override
public void onSuccess(NewsResponse responseData) {
onSuccessNewsResponse(responseData);
}
#Override
public void onFailure(Throwable e) {
onErrorNewsResponse(e);
}
});
}
Add #VisibleForTesting annotation to the new methods.
Success test:
#Test
public void getNewsSuccess() {
presenter.onSuccessNewsResponse(your_response);
Mockito.verify(...);
}
Error test:
#Test
public void getNewsError() {
presenter.onErrorNewsResponse(your_error);
Mockito.verify(...);
}
You have to mock also :
dataSource.getNews() using Mockito when :
e.g.
when(dataSource.getNews()).thenReturn(new SuccessCallback());
So you have to lead your test code into the success callback and check there what methods are called.
The same goes with the eroor case.

Configuring RxJava to Send Data to activity from GCMListenerService

I am trying to send an update to my Activity from my GCMServiceListener so, I am using RxJava/RxAndroid And created a BusClass for handling sending and Observers
public class ClientBus {
//private final PublishSubject<Object> _bus = PublishSubject.create();
// If multiple threads are going to emit events to this
// then it must be made thread-safe like this instead
private final Subject<Object, Object> _bus = new SerializedSubject<>(PublishSubject.create());
public void send(Object o) {
_bus.onNext(o);
}
public Observable<Object> toObserverable() {
return _bus;
}
public boolean hasObservers() {
return _bus.hasObservers();
}
}
And in my Application Class I did this to initialize the BusClass
private ClientBus clientBus;
public ClientBus getRxBusSingleton() {
if (clientBus == null) {
clientBus = new ClientBus();
}
return clientBus;
}
In the activity I want to receive the message, I registered a CompositeSubscription and get a reference to my ClientBus class from the Application Class
clientBus = ((MyApplication) getApplicationContext()).getRxBusSingleton();
#Override
protected void onStart() {
super.onStart();
initSubscriptions();
}
#Override
protected void onStop() {
super.onStop();
_subscriptions.unsubscribe();
}
void initSubscriptions() {
_subscriptions = new CompositeSubscription();
_subscriptions.add(clientBus.toObserverable().subscribe(new Action1<Object>() {
#Override
public void call(Object event) {
Log.e("New Event", "Event Received");
if (event instanceof MyGcmListenerService.Message) {
String msg = ((MyGcmListenerService.Message) event).getMessage();
if (msg.equals("Update Available")) {
scheduleArrayList = getSchedules();
scheduleAdapter = new ScheduleAdapter(getApplicationContext(), scheduleArrayList, ScheduledUberActivity.this);
scheduledList.setAdapter(scheduleAdapter);
scheduleAdapter.notifyDataSetChanged();
} else if (msg.equals("Refresh")) {
fetchTrips();
}
}
}
}));
}
And from the MyGcmListenerService class I did this when I get a new notification
private void sendRefreshNotif() {
if (clientBus.hasObservers()) {<--It enters the if cause the Log prints. But, the activity doesn't get the message
Log.e("Obervers", "Observers aren't null");
clientBus.send(new Message("Refresh"));
}
}
What I don't understand is why isn't it working here? I use it to interact between activities and fragments. I closed my application to check if the notification comes in, It'll enter this block if (clientBus.hasObservers()) { but it didn't and starting the app and testing the Observer, it notices there's an active Observer. Any help? Thanks.
It seems like you used different instances of the ClientBus class in CompositeSubscription and MyApplication.
Try to make a singleton from ClientBus class, it works fine for me.
public class ClientBus {
public ClientBus(SingletonAccessor accessor) {}
private static ClientBus instance;
private static class SingletonAccessor{}
public static ClientBus getInstance() {
if (instance == null) instance = new ClientBus(new SingletonAccessor());
return instance;
}
private final Subject<Object, Object> mBus = new SerializedSubject<>(PublishSubject.create());
public void send(Object o) {
mBus.onNext(o);
}
public Observable<Object> toObserverable() {
return mBus;
}
public boolean hasObservers() {
return mBus.hasObservers();
}
}

Perform requests with Retrofit inside custom Runnable

I am migrating from Volley to a custom implementation using Retrofit, but I'm trying to add to my implementation some of the Volley features that I liked, for example
RequestQueue.cancel(String tag)
If the Request has the requested tag, then it's canceled by setting a boolean value, mCanceled, to true. The run method checks this value and returns if it's true.
To be able to reproduce this with Retrofit I should be able to use my custom class implementing Runnable instead of the default one, where I have a mTag and a mCanceled field.
Moreover, Volley was also able to set such flag inside the active Threads and immediately stop them. My cancelAll method, that I've already implemented, just drains the queue to another queue, but isn't able to access the active threads.
Is it possible to achieve the same results with Retrofit and ThreadPoolExecutor?
I think I've found a nicer solution: instead of blocking the Runnable of the requests, I am blocking the Callback execution.
I have extended the Callback interface:
public interface CustomCallbackInterface<T> extends Callback<T> {
public String getTag();
public String setTag(String tag);
public void cancel();
public boolean isCanceled();
}
so that each Callback has a tag and a cancel flag. Then the success method starts with:
public class CustomCallback<ConvertedData> implements CustomCallbackInterface<ConvertedData>{
//failure...
#Override
public void success(ConvertedData cd, Response response) {
if(isCanceled()) return;
// ....
}
}
Every time I make a new request, I store the created CustomCallback inside a List cancel just iterates the list and calls cancel() on the items with the same tag.
I've implemented an easy to use class based on Vektor88 answer
public abstract class CancelableCallback<T> implements Callback<T> {
private static List<CancelableCallback> mList = new ArrayList<>();
private boolean isCanceled = false;
private Object mTag = null;
public static void cancelAll() {
Iterator<CancelableCallback> iterator = mList.iterator();
while (iterator.hasNext()){
iterator.next().isCanceled = true;
iterator.remove();
}
}
public static void cancel(Object tag) {
if (tag != null) {
Iterator<CancelableCallback> iterator = mList.iterator();
CancelableCallback item;
while (iterator.hasNext()) {
item = iterator.next();
if (tag.equals(item.mTag)) {
item.isCanceled = true;
iterator.remove();
}
}
}
}
public CancelableCallback() {
mList.add(this);
}
public CancelableCallback(Object tag) {
mTag = tag;
mList.add(this);
}
public void cancel() {
isCanceled = true;
mList.remove(this);
}
#Override
public final void success(T t, Response response) {
if (!isCanceled)
onSuccess(t, response);
mList.remove(this);
}
#Override
public final void failure(RetrofitError error) {
if (!isCanceled)
onFailure(error);
mList.remove(this);
}
public abstract void onSuccess(T t, Response response);
public abstract void onFailure(RetrofitError error);
}
Usage example
rest.request(..., new CancelableCallback<MyResponse>(TAG) {
#Override
public void onSuccess(MyResponse myResponse, Response response) {
...
}
#Override
public void onFailure(RetrofitError error) {
...
}
});
// if u need to cancel all
CancelableCallback.cancelAll();
// or cancel by tag
CancelableCallback.cancel(TAG);

Categories

Resources