Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Magnet used in Service crashes after second removing of magnet isntance #22

Open
r0boto opened this issue Oct 24, 2017 · 1 comment
Open

Comments

@r0boto
Copy link

r0boto commented Oct 24, 2017

Hello,

I found the following exception when I trying to destroy second magnet instance used as a preloader.

The exception is following:

10-24 09:18:47.395 12745-12906 A: java_vm_ext.cc:504] JNI DETECTED ERROR IN APPLICATION: JNI CallStaticVoidMethodV called with pending exception android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
10-24 09:18:47.395 12745-12906 A: java_vm_ext.cc:504] at void android.view.ViewRootImpl.checkThread() (ViewRootImpl.java:7286)
10-24 09:18:47.395 12745-12906 A: java_vm_ext.cc:504] at android.view.ViewParent android.view.ViewRootImpl.invalidateChildInParent(int[], android.graphics.Rect) (ViewRootImpl.java:1198)
10-24 09:18:47.395 12745-12906 A: java_vm_ext.cc:504] at void android.view.ViewRootImpl.invalidateChild(android.view.View, android.graphics.Rect) (ViewRootImpl.java:1193)
10-24 09:18:47.395 12745-12906 A: java_vm_ext.cc:504] at void android.view.View.invalidateInternal(int, int, int, int, boolean, boolean) (View.java:15470)
10-24 09:18:47.395 12745-12906 A: java_vm_ext.cc:504] at void android.view.View.invalidate(int, int, int, int) (View.java:15405)
10-24 09:18:47.395 12745-12906 A: java_vm_ext.cc:504] at void android.widget.ProgressBar.invalidateDrawable(android.graphics.drawable.Drawable) (ProgressBar.java:1709)
10-24 09:18:47.395 12745-12906 A: java_vm_ext.cc:504] at void android.graphics.drawable.DrawableContainer.invalidateDrawable(android.graphics.drawable.Drawable) (DrawableContainer.java:400)
10-24 09:18:47.395 12745-12906 A: java_vm_ext.cc:504] at void android.graphics.drawable.Drawable.invalidateSelf() (Drawable.java:450)
10-24 09:18:47.395 12745-12906 A: java_vm_ext.cc:504] at void android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT.invalidateOwningView() (AnimatedVectorDrawable.java:1589)
10-24 09:18:47.395 12745-12906 A: java_vm_ext.cc:504] at void android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT.onAnimationEnd(int) (AnimatedVectorDrawable.java:1764)
10-24 09:18:47.395 12745-12906 A: java_vm_ext.cc:504] at void android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT.callOnFinished(android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT, int) (AnimatedVectorDrawable.java:1772)

Exception Occurrences:
Each time when I trying to remove preloader which is displayed second time in magnet instance. Preloader is displayed after click on the bubble icon. In other words, the workflow is following:

  • Show bubble
  • Click (Event)
  • Show preloader bubble
  • Remove preloader bubble (Event)
  • Show bubble
  • Click (Event)
  • Show preloader bubble
  • Remove preloader bubble**(Crash)**

What I tried
I tried to resolve this problem using running removal code on the main thread. I tried to use the different instances, finalize instance variables. Could You please confirm this issue or is problem elsewhere?

Handler mainHandler = new Handler(mContext.getMainLooper());
                Runnable myRunnable = new Runnable() {
                    @Override
                    public void run() {
                        magnet.destroy();
                        stopService(intent);
                    } 
                };
                myRunnable.run();

**Class code to reproduce **

public class BubbleService extends Service {

    private Context mContext;
    private Handler mHandler;
    private Runnable mRunnable;
    private String textToTranslate;
    private Magnet magnet, magnetLoading;
    private Integer iconCoordsX, iconCoordsY;
    private ImageView iconViewBubble;
    private ProgressBar progressBar;
    private Intent intent;


    @Override
    public void onCreate() {
        super.onCreate();
        mContext = this;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Logger.d("onStartCommand");
        if(intent != null) {
            Bundle b = intent.getExtras();
            textToTranslate = b.getString(Constants.Global.TRANSLATION);
            this.showBubble();
        }
            return Service.START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    private void removeCallback() {
        if(mRunnable != null && mHandler != null)
            mHandler.removeCallbacks(mRunnable);
    }

    private void removeExistingBubble() {
        try {
            Logger.d("removeExistingBubble");
            mHandler = new Handler();
            if(magnet != null) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Logger.d("magnet destroy");
                        magnet.destroy();
                        magnet = null;
                    }
                });
            }
            if(magnetLoading != null) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Logger.d("magnetLoading destroy");
                        magnetLoading.destroy();
                        magnetLoading = null;
                    }
                });

            }
        } catch (Exception e) {
            Logger.e(e.getMessage());
        }
    }

    private void showBubble() {
        try {
            Logger.d("Show bubble");
            //this.removeExistingBubble();
            iconViewBubble = new ImageView(this);
                iconViewBubble.setImageResource(R.drawable.ic_launcher);
            magnet = Magnet.newBuilder(this)
                    // a view is required
                    .setIconView(iconViewBubble)
                    // all the parameters below are optional
                    .setIconCallback(mIconCallback)
                    .setHideFactor(0.2f)
                    .setShouldShowRemoveView(true)
                    .setRemoveIconShouldBeResponsive(true)
                    .setRemoveIconResId(R.drawable.ic_close)
                    .setRemoveIconShadow(R.drawable.bottom_shadow)
                    //.setShouldStickToWall(true)
                    .setRemoveIconShouldBeResponsive(true)
                    .setInitialPosition(300, 400)
                    .build();
            magnet.show();
            //setTimerForInactiveBubble();
        } catch (Exception e) {
            Logger.e(e.getMessage());
        }
    }

    private void showLoadingBubble() {
        Logger.d("showLoadingBubble");
        magnet.destroy();
        //removeCallback();
        progressBar = new ProgressBar(mContext);
        magnet = Magnet.newBuilder(this)
                // a view is required
                .setIconView(progressBar)
                // all the parameters below are optional
                .setIconCallback(mLoadingIconCallback)
                .setHideFactor(0.2f)
                .setShouldShowRemoveView(true)
                .setRemoveIconShouldBeResponsive(true)
                .setRemoveIconResId(R.drawable.ic_close)
                .setRemoveIconShadow(R.drawable.bottom_shadow)
                .setShouldStickToWall(true)
                .setInitialPosition(iconCoordsX, iconCoordsY)
                .build();
        magnet.show();
    }

    private void setTimerForInactiveBubble() {
        try {
            Logger.d("setTimerForInactiveBubble");
            mHandler = new Handler();
            mRunnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        Logger.d("Remove bubble from inactivity");
                        magnet.destroy();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            };
            mHandler.postDelayed(mRunnable,
                    Constants.Global.BUBBLE_DISMISS_DURATION);
        } catch (Exception e) {
            Logger.e(e.getMessage());
        }
    }

    private void bubbleClickCallback() {
        try {
            Logger.d("Clicked on the bubble");
            if (CommonHelper.isDeviceOnline(mContext)) {
                showLoadingBubble();
                //callTranslationService();
            }
            else {
                ToastHelper.showToastMessage(mContext, //TODO: ADD THE OFFLINE TRANSACTION //TODO: MOVE TOAST TO HELPER?
                        mContext.getResources().getString(R.string.no_internet_connectivity),
                        Constants.Global.DEBUG_ENABLED);
            }
        } catch (Exception e) {
            Logger.d(e.getMessage());
        }
    }

    private IconCallback mIconCallback = new IconCallback() {
        @Override
        public void onFlingAway() {
            Logger.d("onFlingAway");
            mHandler = new Handler();
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    Logger.d("destroy");
                    magnet.destroy();
                }
            });

        }

        @Override
        public void onMove(float v, float v1) {
            //Logger.d("onMove");
            iconCoordsX = (int) v;
            iconCoordsY = (int) v1;
        }

        @Override
        public void onIconClick(View view, float v, float v1) {
            Logger.d("onIconClick");
            bubbleClickCallback();
        }

        @Override
        public void onIconDestroyed() {
            Logger.d("onIconDestroyed");
            removeCallback();
            //magnet = null;
        }
    };

    private IconCallback mLoadingIconCallback = new IconCallback() {
        @Override
        public void onFlingAway() {
            try {
                Logger.d("onFlingAway");
                Handler mainHandler = new Handler(mContext.getMainLooper());
                Runnable myRunnable = new Runnable() {
                    @Override
                    public void run() {
                        magnet.destroy();
                        stopService(intent);
                    } // This is your code
                };
                myRunnable.run();

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onMove(float v, float v1) {
            iconCoordsX = (int) v;
            iconCoordsY = (int) v1;
        }

        @Override
        public void onIconClick(View view, float v, float v1) {
            Logger.d("onIconClick");
        }

        @Override
        public void onIconDestroyed() {
            try {
                Logger.d("onIconDestroyed");
                //removeCallback();
                //stopService(intent);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

    private void callTranslationService() throws Exception {
        Logger.d("callTranslationService");
        //Intent myIntent = new Intent(mContext, TranslateService.class);
        //Intent myIntent = new Intent(mContext, ResultService.class);
        Intent myIntent = new Intent(mContext, ResultServiceCard.class);
        myIntent.putExtra(Constants.Global.TRANSLATION, textToTranslate);
        mContext.startService(myIntent);
    }

}
@r0boto
Copy link
Author

r0boto commented Dec 19, 2017

I found that this issue is happening only in case if .setIconView() takes as params ProgressBar instead of the ImageView.

Strange is that after the first occurrence of the icon removal is everything is working fine, app crashes after the second removal. When I replaced ProgressBar by ImageView, the crashing stopped.

I solved using progressBar.setVisibility(View.GONE);

private void removeExistingBubble() {
        try {
            if(magnetLoading != null) {
                progressBar.setVisibility(View.GONE);
                magnetLoading.destroy();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant