'continuous processes in background on android

I need to take pictures every 3 sec and upload them to server continuously in the background unless user opens the app and stops it.

In my current implementation I am using foreground service, in that service I am creating a new thread that takes a picture and saves it storage then if there is internet connection uploads it to server. All of it is done in a while loop.

1=> Application is not running properly on some devices. On my Oneplus it is working fine even more than 12 hours. but on different devices it is behaving differently like on xiaomi it works as long device is being used, as soon as device locks it works for a few minutes then stops. it starts working again when devices receives any notification or user turns the device's screen on.

2=> Someone told me that instead of using services I should use broadcasts. Will that be better in my case? If it is how can I do this using broadcasts?

I have been stuck on this for sometime any help will be appreciated! my code is below.

my service code


    public class CameraForeground extends Service implements Info {
        public static final int MEDIA_TYPE_IMAGE = 1;
        int camId;
        int fieldId;
        String apiKey;

        private PowerManager.WakeLock wakeLock = null;
        private static final String tag = CameraForeground.class.getSimpleName();

        boolean running;

        private Camera mCamera;
        static File dir;


        @RequiresApi(api = Build.VERSION_CODES.O)
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            if (intent != null) {
                running = intent.getBooleanExtra("camService", false);
                Log.i(TAG, "run: " + running);
                if (running) {
                    startServices();
                } else {
                    stopServices();
                }
            } else {
                Log.i(TAG, "onStartCommand: null intent probably by the system");
            }
            return START_STICKY;
        }

        private void startServices() {
            final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
            wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, tag);
            wakeLock.acquire(10*60*1000L /*10 minutes*/);

            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (running) {
//                    if (dir != null) {
//                        Log.e(TAG, "run: " + dir.getPath());
//                        makeLogFile();
//                    }
                        if (wakeLock != null) {
                            Log.i(TAG, "run: wake" + wakeLock);
                        }
                        if (isCameraFree()) {
                            Log.i(TAG, "run: yes Camera is free");
                            pictureTakingThread();
                        } else {
                            Log.e(TAG, "run: camera is not free");
                        }
                        uploadingThread();
                        try {
                            Thread.sleep(3000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
            Log.i(TAG, "startServices: End of the service loop");
        }

        private void stopServices() {
            Log.i(TAG, "stopServices: service ending ...");
            try {
                if (wakeLock.isHeld()) {
                    wakeLock.release();
                }
                stopForeground(true);
                stopSelf();
            } catch (Exception e) {
                Log.i(TAG, "stopServices: Service stopped with null wakelock:" + e.getMessage());
            }
            running = false;
        }

        private void pictureTakingThread() {
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
            Log.i(TAG, "run: in picture taking thread");
            mCamera = Util.getCameraInstance();
            String device = getDeviceName();
            Camera.Parameters params = mCamera.getParameters();
            List<Camera.Size> sizes = params.getSupportedPictureSizes();
            Camera.Size size = sizes.get(sizes.size() - 5);
            for (int i = 0; i < sizes.size(); i++) {
                if (sizes.get(i).width >= 800 && sizes.get(i).width <= 1200) {
                    size = sizes.get(i);
                }
            }
//                    Log.i(TAG, "run: size: width:" + size.width + " height:" + size.height);
            params.setPictureSize(size.width, size.height);
            mCamera.setParameters(params);

            Camera.CameraInfo info = new Camera.CameraInfo();
            Camera.getCameraInfo(0, info);
            if (info.canDisableShutterSound) {
                mCamera.enableShutterSound(false);
            }
            if (mCamera != null) {
                try {
                    mCamera.setPreviewTexture(new SurfaceTexture(0));
                    mCamera.startPreview();
                    mCamera.takePicture(null, null, new Camera.PictureCallback() {

                        @Override
                        public void onPictureTaken(byte[] data, Camera camera) {
                            File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
                            if (pictureFile == null) {
                                Log.e(TAG, "onPictureTaken: cannot create media files check Permissions");
                                return;
                            }
                            try {
                                if (device.equals("cubot")) {
                                    Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
                                    Bitmap bitmap = Bitmap.createBitmap(900, 700, bmp.getConfig());
                                    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
                                    bmp.compress(Bitmap.CompressFormat.JPEG, 10, bytes);

                                    FileOutputStream fos = new FileOutputStream(pictureFile);
                                    fos.write(bytes.toByteArray());
                                    fos.close();
                                } else {
                                    FileOutputStream fos = new FileOutputStream(pictureFile);
                                    fos.write(data);
                                    fos.close();
                                    Log.i(TAG, "onPictureTaken: picture taken");
                                }
                            } catch (FileNotFoundException e) {
                                Log.e(TAG, "onPictureTaken: File not found" + e.getMessage());
                            } catch (IOException e) {
                                Log.e(TAG, "onPictureTaken: Error Accessing File " + e.getMessage());
                            }
//                                        }
                            releaseCamera();
                        }
                    });

//                        Thread.sleep(2000);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
//            }
//        }).start();
        }

        private void uploadingThread() {
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
            SharedPreferences pref =  this.getSharedPreferences("FLYNN.PES",Context.MODE_PRIVATE);
            camId = pref.getInt("camId", 0);
            fieldId = pref.getInt("fieldId", 0);
            apiKey = pref.getString("apiKey", "");
            Log.i(TAG, "uploadingThread: in uploading thread");
            if (isOnline()) {
//                        Log.e(TAG, "run: second thread");
                if (dir != null) {
                    if (dir.exists()) {
                        File[] flies = dir.listFiles();
                        if (flies != null) {
                            for (int i = 0; i < flies.length; i++) {
                                File file = flies[i];
                                if (file.isDirectory()) {
//                                            Log.e(TAG, "run: not usable here");
                                } else {
//                                            Log.e(TAG, "run: files " + isOnline() + file);
                                    Methods methods = RetrofitClient.getRetrofitInstance().create(Methods.class);
                                    Map<String, String> headers = new HashMap<>();
                                    headers.put("apiKey", apiKey);
                                    headers.put("camId", Integer.toString(camId));
                                    headers.put("fiId", Integer.toString(fieldId));
                                    MultipartBody.Part files = MultipartBody.Part.createFormData(
                                            "files",
                                            file.getName(),
                                            RequestBody.create(MediaType.parse("image/*"), file));
                                    Call<ResponseBody> call = methods.uploadImage(headers, files);

                                    try {
                                        Response<ResponseBody> result = call.execute();
                                        if (result.isSuccessful()) {
                                            Log.i(TAG, "run: successful: " + result);
                                            file.delete();
                                            if (file.exists()) {
                                                file.getCanonicalFile().delete();
                                                if (file.exists()) {
                                                    getApplicationContext().deleteFile(file.getName());
                                                }
                                            }
                                        }
                                        if (!result.isSuccessful()) {
                                            Log.i(TAG, "run: " + result);
                                        }
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        }
                    }
                }
            }
//            }
//        }).start();
        }

        @RequiresApi(api = Build.VERSION_CODES.O)
        @Override
        public void onCreate() {
            super.onCreate();
            Log.i(TAG, "onCreate: Service created");
            final String CHANNELID = "Foreground Service ID";
            NotificationChannel channel = new NotificationChannel(CHANNELID, CHANNELID, NotificationManager.IMPORTANCE_LOW);
            getSystemService(NotificationManager.class).createNotificationChannel(channel);
            Notification.Builder notification = new Notification.Builder(this, CHANNELID)
                    .setContentText("I am Running")
                    .setContentTitle("Everyone is not running");

            startForeground(1001, notification.build());
        }

        @RequiresApi(api = Build.VERSION_CODES.O)
        @Override
        public void onDestroy() {
            Log.i(TAG, "onDestroy: cam service destroyed");
            super.onDestroy();
        }

//    @Override
//    public void onTaskRemoved(Intent rootIntent) {
//        Intent restartServiceIntent = new Intent(getApplicationContext(), CameraForeground.class);
//        restartServiceIntent.putExtra("camService", running);
//
//        PendingIntent restartServicePendingIntent = PendingIntent.getService(this, 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
//        getApplicationContext().getSystemService(Context.ALARM_SERVICE);
//        AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
//        alarmService.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 2000, restartServicePendingIntent);
//        super.onTaskRemoved(rootIntent);
//    }

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

        private static Uri getOutputMediaFileUri(int type) {
            return Uri.fromFile(getOutputMediaFile(type));
        }

        private static File getOutputMediaFile(int type) {
            File storageDir = new File(Environment.getExternalStoragePublicDirectory(
                    Environment.DIRECTORY_PICTURES), "Aham kam");
            if (!storageDir.exists()) {
                if (!storageDir.mkdirs()) {
//                Log.e(TAG, "getOutputMediaFile: Failed to create directory");
                    return null;
                }
            }
            dir = storageDir;

            @SuppressLint("SimpleDateFormat")
            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
            File mediaFile;
            if (type == MEDIA_TYPE_IMAGE) {
                mediaFile = new File(storageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
            } else {
//            Log.i(TAG, "getOutputMediaFile: returning null");
                return null;
            }

//        Log.i(TAG, "getOutputMediaFile: properly returning");
            return mediaFile;
        }


        private void releaseCamera() {
            if (mCamera != null) {
                mCamera.release();        // release the camera for other applications
                mCamera = null;
            }
        }

        public boolean isOnline() {
            ConnectivityManager cm =
                    (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo netInfo = cm.getActiveNetworkInfo();
            return netInfo != null && netInfo.isConnected();
        }

        public String getDeviceName() {
            String manufacturer = Build.MANUFACTURER;
            String model = Build.MODEL;
            return manufacturer.toLowerCase();
        }

        public boolean isCameraFree() {
            Camera camera = null;
            try {
                camera = Camera.open();
            } catch (RuntimeException e) {
                return false;
            } finally {
                if (camera != null) camera.release();
            }
            return true;
        }
    }

my manifest file

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="...">

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <uses-permission android:name="android.permission.ACTION_MANAGE_OVERLAY_PERMISSION"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher_flynn_new"
        android:label="PES"
        android:roundIcon="@mipmap/ic_launcher_flynn_new_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Pictures_taking_service"
        android:usesCleartextTraffic="true"
        android:requestLegacyExternalStorage="true"
        tools:targetApi="m">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:foregroundServiceType="camera"
            android:stopWithTask="false"
            android:enabled="true"
            android:exported="false"
            android:name=".CameraForeground" />

    </application>

</manifest>


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source