Why does my service overload the device?

Asked

Viewed 138 times

0

I am writing an app that has a Service whose role is to take screenshots at 15-second intervals, using an Asynctask. This service, however, overloads my device in such a way that, after a few seconds, makes it so slow that it even makes it impossible to use it. I have no idea why. The definition of an Handler for Imagereader’s Onimageavailable inside a loop in Asynctask bothers me a little bit, I suspect it has something to do with the problem at hand. As I’m entering this area of Android now, I’m very bewildered.

Below is the code of my service.

public class SSService extends Service {

    Handler handler;
    MediaProjection mp;
    MediaProjectionManager mpm;
    Intent mp_data;
    int mp_result_code;

    WindowManager wm;
    Display display;
    DisplayMetrics metrics;
    Point size;
    int mWidth;
    int mHeight;
    int mDensity;

    ImageReader mImageReader;

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        handler = new Handler();
        Bundle bd = intent.getExtras();
        mpm = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
        mp_data = bd.getParcelable("DATA");
        mp_result_code = bd.getInt("RESULT_CODE");

        wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        display = wm.getDefaultDisplay();
        metrics = new DisplayMetrics();
        display.getMetrics(metrics);
        size = new Point();
        display.getRealSize(size);
        mWidth = size.x;
        mHeight = size.y;
        mDensity = metrics.densityDpi;

        mp = mpm.getMediaProjection(mp_result_code, mp_data);

        SCS s = new SCS();
        s.execute();

        return super.onStartCommand(intent, flags, startId);
    }

    private void saveScreenshot(Bitmap bmp) {
        Date now = new Date();
        android.text.format.DateFormat.format("yyyy-MM-dd_hh:mm:ss", now);
        Log.i("DIB", "Salvando print...");
        try {
            // image naming and path  to include sd card  appending name you choose for file
            String mPath = Environment.getExternalStorageDirectory().toString() + "/vagdomScreenshots/" + now + ".jpg";

            File imageFile = new File(mPath);

            FileOutputStream outputStream = new FileOutputStream(imageFile);
            int quality = 100;
            bmp.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
            outputStream.flush();
            outputStream.close();

        } catch (Throwable e) {
            // Several error may come out with file handling or DOM
            e.printStackTrace();
        }
    }

    public class SCS extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... voids) {
            while (true) {
                try {
                    Thread.sleep(15000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                mImageReader = ImageReader.newInstance(mWidth, mHeight, PixelFormat.RGBA_8888, 2);
                mp.createVirtualDisplay("screen-mirror", mWidth, mHeight, mDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, mImageReader.getSurface(), null, null);

                mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
                    @Override
                    public void onImageAvailable(ImageReader reader) {

                        Image.Plane[] plane = reader.acquireLatestImage().getPlanes();
                        ByteBuffer bbuff = plane[0].getBuffer();

                        int pixelStride = plane[0].getPixelStride();
                        int rowStride = plane[0].getRowStride();
                        int rowPadding = rowStride - pixelStride * metrics.widthPixels;

                        Bitmap bmp = Bitmap.createBitmap(metrics.widthPixels + (int) ((float) rowPadding / (float) pixelStride), metrics.heightPixels, Bitmap.Config.ARGB_4444);
                        bmp.copyPixelsFromBuffer(bbuff);

                        reader.close();

                        saveScreenshot(bmp);
                    }
                }, handler);
            }
        }
    }
}
  • 2

    This approach is wrong. Instead of trying to make it "work" use the Workmanager.

1 answer

3

Without being able to test it is not easy to know the true cause.
However, analyzing the code available, I find several problems that may justify this behavior.

The way it is, due to while(true){}, the Asynctask wheel eternally.

A service can be destroyed and later restarted by the system.
Once it is destroyed and the Asynctask is not stopped, it will continue running. Every time the service is restarted, another Asynctask is created and started.

Over time, service crash/restart can happen multiple times, more Asynctask’s keep running making the system slower and slower.

Eventually, some memory leakage may be happening(memory Leak). For example, a try/catch in the use of an Outputstream that is not closed if an error occurs.

For the execution of scheduled tasks, Android provides solutions such as Alarmmanager and Workmanager.
They are managed by the system so as to minimize their impact on overall device performance.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.