3

E/AndroidRuntime: FATAL EXCEPTION: main Process: com.marsad.wallpaperapp, PID: 20425 java.lang.ArithmeticException: divide by zero

Hi, When I click on gif image to apply as live wallpaper mostly everything works good but sometime app crash with the error

Logcat

E/AndroidRuntime: FATAL EXCEPTION: main Process: com.marsad.wallpaperapp, PID: 20425 java.lang.ArithmeticException: divide by zero at com.marsad.wallpaperapp.GIFWallpaperService$GIFWallpaperEngine.draw(GIFWallpaperService.java:139) at com.marsad.wallpaperapp.GIFWallpaperService$GIFWallpaperEngine.access$000(GIFWallpaperService.java:82) at com.marsad.wallpaperapp.GIFWallpaperService$GIFWallpaperEngine$1.run(GIFWallpaperService.java:111) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:224) at android.app.ActivityThread.main(ActivityThread.java:7139) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:536) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:876)

Here is the full code


public class GIFWallpaperService extends WallpaperService {
    Context context;


    @Override
    public WallpaperService.Engine onCreateEngine() {

        Singleton b = Singleton.getInstance();
        String path = b.getPath();


        try {
            InputStream is = new FileInputStream(path);
            Movie movie = Movie.decodeStream(is);

            return new GIFWallpaperEngine(movie);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
            Toast.makeText(context, "Error: " + e.getMessage(), Toast.LENGTH_SHORT).show();
            return null;
        }
        

    }


    private class GIFWallpaperEngine extends WallpaperService.Engine {

        private final int frameDuration = 20;
        private SurfaceHolder holder;
        private Movie movie;
        private boolean visible;
        private Handler handler;

        int width;
        int height;

        public GIFWallpaperEngine(Movie movie) {

            this.movie = movie;
            handler = new Handler();

        }

        @Override
        public void onCreate(SurfaceHolder surfaceHolder) {
            super.onCreate(surfaceHolder);

            this.holder = surfaceHolder;

        }

        private Runnable drawGIF = new Runnable() {
            @Override
            public void run() {
                draw();
            }
        };

        private void draw() {

            WindowManager wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
            Display display = wm.getDefaultDisplay();
            float screenWidth = display.getWidth();
            float screenHeight = display.getHeight();

            width = (int) screenWidth;
            height = (int) screenHeight;


            if (visible) {
                Canvas canvas = holder.lockCanvas();
                canvas.save();


                canvas.scale((float) display.getWidth() / (float) movie.width(),
                        (float) display.getHeight() / (float) movie.height());
                movie.draw(canvas, 0, 0);


                canvas.restore();

                holder.unlockCanvasAndPost(canvas);
                movie.setTime((int) (System.currentTimeMillis() % movie.duration()));

                handler.removeCallbacks(drawGIF);
                handler.postDelayed(drawGIF, frameDuration);

            }

        }

        @Override
        public void onVisibilityChanged(boolean visible) {
            //super.onVisibilityChanged(visible);

            this.visible = visible;

            if (visible) {
                handler.post(drawGIF);
            } else {
                handler.removeCallbacks(drawGIF);
            }


        }

        @Override
        public void onSurfaceDestroyed(SurfaceHolder holder) {
            super.onSurfaceDestroyed(holder);
            this.visible = false;
            handler.removeCallbacks(drawGIF);
        }

        @Override
        public void onSurfaceChanged(SurfaceHolder holder, int format,
                                     int width, int height) {
            this.width = width;
            this.height = height;
            super.onSurfaceChanged(holder, format, width, height);
        }
        

        @Override
        public void onDestroy() {
            super.onDestroy();
            handler.removeCallbacks(drawGIF);

        }


    }

}

Marsad
  • 859
  • 1
  • 14
  • 35
  • Line 139 of `GIFWallpaperService.java` has a statement that is doing `/` division or `%` remainder, and the divisor is zero. Which part of that is confusing? How you need to figure out why the divisor is zero, but only you can do that, because only you have the data in question. – Andreas Jul 02 '20 at 07:57

2 Answers2

4

You may check before draw like this

if(movie.width() > 0 && movie.height() > 0){
        canvas.scale((float) display.getWidth() / (float) movie.width(),
                (float) display.getHeight() / (float) movie.height());
        movie.draw(canvas, 0, 0);
}else{
        //do something default which suit your application
}
Omar
  • 901
  • 11
  • 14
  • Dividing a float value by zero yields positive infinity or negative infinity or NaN (0 / 0) and does not throw an exception. –  Jul 02 '20 at 08:09
  • ```if (movie.duration() == 0){ int i = movie.duration() + 1; movie.setTime((int) (System.currentTimeMillis() % i)); }else { movie.setTime((int) (System.currentTimeMillis() % movie.duration())); }``` – Marsad Jul 02 '20 at 08:12
2

Your exception is coming from these lines:

            canvas.scale((float) display.getWidth() / (float) movie.width(),
                    (float) display.getHeight() / (float) movie.height());
            movie.draw(canvas, 0, 0);

And not the ones you mentioned.

Since these lines are the ones where division by zero might happen.

I would make sure that the movie object has a width/height before doing the calculation.

tomerpacific
  • 4,704
  • 13
  • 34
  • 52
  • @Marsad - what is missing from my answer? Your error is coming from the lines mentioned n my answer. – tomerpacific Jul 02 '20 at 07:49
  • Exception could also come from `movie.setTime((int) (System.currentTimeMillis() % movie.duration()));`. Whichever is line 139. – Andreas Jul 02 '20 at 07:53
  • Thank you for letting me know where the error was. But I posted questions to find a solution – Marsad Jul 02 '20 at 07:54
  • @Marsad To find a solution, you need to figure out why the divisor is zero. We don't have your data, so we cannot determine why `movie.width()`, `movie.height()`, or `movie.duration()` might be zero, or what to do about it. – Andreas Jul 02 '20 at 07:58
  • Dividing a float by zero yields positive infinity or negative infinity and does not throw an exception. –  Jul 02 '20 at 07:59
  • @tomerpacific saka1029 is correct. JLS [15.17.2. Division Operator `/`](https://docs.oracle.com/javase/specs/jls/se14/html/jls-15.html#jls-15.17.2) says *"Division of a zero by a zero results in NaN; Division of a nonzero finite value by a zero results in a signed infinity"* --- Which means that line 139 is probably the `System.currentTimeMillis() % movie.duration()`, and `duration()` is zero. – Andreas Jul 02 '20 at 08:02
  • @Marsad If `movie.duration()` is zero, does that mean only the first frame is present? –  Jul 02 '20 at 08:17
  • Trying to load this image: [https://i.pinimg.com/originals/a3/81/5d/a3815d393a7c6d9e34b2480e8893be1d.gif][] – Marsad Jul 02 '20 at 08:20
  • @saka1029 ```movie.duration()``` is zero sometime. – Marsad Jul 02 '20 at 08:20
  • @Marsad - if my answer helped you, please mark it as such. – tomerpacific Jul 02 '20 at 08:34