Android - library module's interface method is not called in app module - android

I am using Android Image Slider library for showing images on a slider. However, some images are not loading because backend requires authentication. So I need a listener for not loading images.
This is library: inside abstract BaseSliderView class, there is ImageLoadListener interface. I am setting listener using setOnImageLoadListener method.
public abstract class BaseSliderView {
.....
private ImageLoadListener mLoadListener;
.....
protected void bindEventAndShow(final View v, ImageView targetImageView){
....
rq.into(targetImageView,new Callback() {
#Override
public void onSuccess() {
if(v.findViewById(R.id.loading_bar) != null){
v.findViewById(R.id.loading_bar).setVisibility(View.INVISIBLE);
}
}
#Override
public void onError() {
if(mLoadListener != null){
mLoadListener.onEnd(false,me);
}
if(v.findViewById(R.id.loading_bar) != null){
v.findViewById(R.id.loading_bar).setVisibility(View.INVISIBLE);
}
}
});
}
/**
* set a listener to get a message , if load error.
* #param l
*/
public void setOnImageLoadListener(ImageLoadListener l){
mLoadListener = l;
}
.....
public interface ImageLoadListener{
void onStart(BaseSliderView target);
void onEnd(boolean result,BaseSliderView target);
}
.....
}
I checked, when image is not loaded, interface onEnd method is called in library module.
But on app module, onEnd method is not called even in library module it is called.
Why is this happening? Should not onEnd method be called in app module? How to solve this problem?

I could solve this problem using greenrobot's EventBus library. First of all, I have added library dependency to library build.gradle file:
compile 'org.greenrobot:eventbus:3.0.0'
Created class for event:
public class ImageLoadErrorEvent {
String url;
ImageView imageView;
public ImageLoadErrorEvent(String url, ImageView imageView) {
this.url = url;
this.imageView = imageView;
}
public String getUrl() {
return url;
}
public ImageView getImageView() {
return imageView;
}
}
Posted on BaseSliderView class:
#Override
public void onError() {
if(mLoadListener != null){
mLoadListener.onEnd(false,me);
EventBus.getDefault().post(new ImageLoadErrorEvent(mUrl, targetImageView));
}
if(v.findViewById(R.id.loading_bar) != null){
v.findViewById(R.id.loading_bar).setVisibility(View.INVISIBLE);
}
}
In Activity, inside onCreate method, registered EventBus:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user);
EventBus.getDefault().register(this);
Then created onMessageEvent:
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(ImageLoadErrorEvent event) {
MyToast.show("Error");
}
Yay, now it is working!

Related

Android syncronization not working

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);
}

is there a way to create condition listener

is there a way to create a listener that activates an event under a certain condition(boolean)?
i tried reading about creating custom listeners using interfaces but i dont think it's the answer for my question.
right now in my app i write an if statement everywhere so if i could just create a listener for it, it would be much easier.
set_A==B_Listener(????? {//listener takes place if a==b
#Override
public boolean event(View v, MotionEvent e)
{
//do something
}
});
Create a class variable for your statement, than you can attach an OnChangeListener to your statement in the onCreate method of your Activity
public class DummyActivity extends Activity {
interface OnStateChangeListener{
public void onAttach(Activity activity);
public void onStateChange(boolean state);
}
private boolean state;
private OnStateChangeListener listener;
private YourClass stateChangedCallback;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
listener = new OnStateChangeListener() {
private Activity currentActivity;
#Override
public void onAttach(Activity activity) {
currentActivity = activity;
}
#Override
public void onStateChange(boolean state) {
if (((DummyActivity) this.currentActivity).state != state) {
stateChangedCallback.doSomething();
((DummyActivity) this.currentActivity).state = state;
}
}
};
}
private void yourFunction() {
boolean state = true;
listener.onStateChange(state);
}
}

How to test if an image is fully loaded with Picasso

Picasso is asynchronous, so i was wondering if there is any way i can test if an image is fully loaded, before executing any additional code?
Picasso.with(context).load(imageURI).into(ImageView);
// image fully loaded? do something else ..
If the image is fully loaded it will be set on the ImageView synchronously.
You can use the callback to assert this.
final AtomicBoolean loaded = new AtomicBoolean();
Picasso.with(context).load(imageURI).into(imageView, new Callback.EmptyCallback() {
#Override public void onSuccess() {
loaded.set(true);
}
});
if (loaded.get()) {
// The image was immediately available.
}
Using overloaded method .into(ImageView target, Callback callback) is appropriate for your case. You can use the base implementation or extend your own like
Base:
Picasso.with(context).load(url).into(target, new Callback(){
#Override
public void onSuccess() {
}
#Override
public void onError() {
}
});
Extended version:
package main.java.app.picasso.test;
/**
* Created by nikola on 9/9/14.
*/
public abstract class TargetCallback implements Callback {
private ImageView mTarget;
public abstract void onSuccess(ImageView target);
public abstract void onError(ImageView target);
public TargetCallback(ImageView imageView){
mTarget = imageView;
}
#Override
public void onSuccess() {
onSuccess(mTarget);
}
#Override
public void onError() {
onError(mTarget);
}
}
Usage:
Picasso.with(context).load(url).into(target, new TargetCallback(target) {
#Override
public void onSuccess(ImageView target) {
}
#Override
public void onError(ImageView target) {
}
});

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);

android how to make listener to a custom variable?

i've seen this thread : How to implement a listener about implement listeners.
its actually pretty simple but i don't get how exactly its done and how to implement in my own code.
i have this static variable variable: AppLoader.isInternetOn.
i want to build a listener which will listen to this variable changes and update a TextView.
should i do this: ?
build an interface:
public interface InternetStateListener {
public void onStateChange();
}
run it in my activity:
public class MyActivity extends Activity {
private InternetStateListener mListener;
setTheListener(this);
public void setTheListener(InternetStateListener listen) {
mListener = listen;
}
private void onStateChange() {
if (mListener != null) {
if (AppLoader.isInternetOn)
text.setText("on")
else
text.setText("off")
}
}
}
Your Activity does nothing special, just register itself (since the interface is implemented directly in the class) with the Other class that provides the listener.
public class MyActivity extends Activity implements InternetManager.Listener {
private TextView mText;
private InternetManager mInetMgr;
/* called just like onCreate at some point in time */
public void onStateChange(boolean state) {
if (state) {
mText.setText("on");
} else {
mText.setText("off");
}
}
public void onCreate() {
mInetMgr = new InternetManager();
mInetMgr.registerListener(this);
mInetMgr.doYourWork();
}
}
The other class has to do pretty much all the work. Besides that it has to handle the registration of listeners it has to call the onStateChange method once something happend.
public class InternetManager {
// all the listener stuff below
public interface Listener {
public void onStateChange(boolean state);
}
private Listener mListener = null;
public void registerListener (Listener listener) {
mListener = listener;
}
// -----------------------------
// the part that this class does
private boolean isInternetOn = false;
public void doYourWork() {
// do things here
// at some point
isInternetOn = true;
// now notify if someone is interested.
if (mListener != null)
mListener.onStateChange(isInternetOn);
}
}
The part that you're missing it the class that actually notifies the listener. So you would need a class (most likely a service) that runs and pings the state of the network. Then when it detects a change it should call onStateChange() in any registered listeners. Then you would call setTheListener on that service, not on your activity.
Here's a link that thoroughly describes this design pattern: http://en.wikipedia.org/wiki/Observer_pattern

Categories

Resources