Служба Android Foreground onStartCommand не запускается, вызывается только onCreate - PullRequest
0 голосов
/ 28 мая 2019

У меня есть служба Foreground, которая определена в манифесте и в другом процессе, и я обычно вызываю ее, когда моя деятельность выполняется и все работает хорошо, но внезапно, когда я хочу запустить службу Foreground, onStartCommand больше не вызывается , только метод onCreate! и я не могу увидеть мой метод входа в систему onStartCommand ...

Это Мое служение, заявленное в Манифесте:

<service
            android:name=".services.ForegroundService"
            android:enabled="true"
            android:exported="false"
            android:process=":ForegroundService" />

вот мой код для запуска услуги:

private void startServices() {
        new Handler().postDelayed(() -> {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                startForegroundService(new Intent(MapBoxActivity.this,ForegroundService.class));
            } else {
                startService(new Intent(MapBoxActivity.this,ForegroundService.class));
                Timber.i("service Started!");
            }
            TaskScheduler.schedule(MapBoxActivity.this);
        }, 10*1000);
    }

и я вызываю startServices() метод в моем методе onCreate моей Деятельности ...

и вот код моей службы Foreground:

public class ForegroundService extends Service implements
        SensorEventListener, StepListener , MapboxActivityLocationCallback.MapboxLocationListener {

    private static final String ACTION_STOP_SERVICE = "stop_service";
    public static final String URL_SAVE_PROFILE = "https://www.mohregroup.com/db-mapapa/saveName.php";

    private int countedSteps = 0;
    private Location originLocation;
    private LocationEngine locationEngine;
    private long DEFAULT_INTERVAL_IN_MILLISECONDS = 10 * 60 * 1000L;
    private long DEFAULT_MAX_WAIT_TIME = DEFAULT_INTERVAL_IN_MILLISECONDS * 3;
    private MapboxActivityLocationCallback locationCallback = new MapboxActivityLocationCallback();

    private final SparseArray<MarkerItem> treasuresList = new SparseArray<>();
    private SparseArray<MarkerItem> sawTreasuresList = new SparseArray<>();

    private String JSON_locations = null, JSON_locations_tmp = null, geocodeAddress = null, address;

    //Session Manager
    private SessionManager sessionManager;
    private HashMap<String, Object> user;

    //locationChecker
    private String zone, currentZone;
    private boolean onConnectedFlag = false;

    private MyDbAdapter dbAdapter;

    private int coins , dailySteps;
    private float bagCapacity;

    private SteepDetector steepDetector;

    private BagBroadcastReceiver receiver;

    private PowerManager.WakeLock wakeLock;

    public ForegroundService() {
    }

    @SuppressLint("MissingPermission")
    @Override
    public void onCreate() {
        super.onCreate();
        activateLocationEngine();

        //###########SEND TO SERVER
        registerReceiver(new NetworkStateChecker(), new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
        //for updated UI!
        BroadcastReceiver sendToServerReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                //TODO : for updated UI!
            }
        };
        registerReceiver(sendToServerReceiver, new IntentFilter(DATA_SAVED_BROADCAST));

        syncProfile();

        //###########SEND TO SERVER

        //TODO : works even screen is off
        PowerManager powerManager = (PowerManager)this.getSystemService(Context.POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,":ForegroundService");
        wakeLock.acquire(5000);

        sessionManager = new SessionManager(getApplicationContext());
        user = sessionManager.getUserDetails();
        coins = (int) user.get(SessionManager.getKeyCoin());
        bagCapacity = (float) user.get(SessionManager.getKEY_BagCapacity());
        dailySteps  = (int) user.get(SessionManager.getKEY_Steps());
        Timber.i("foreground_userDetails \n coins: %s \n bagCapacity: %s \n dailySteps: %s" ,
                coins , bagCapacity , dailySteps);

        dbAdapter = new MyDbAdapter(getApplicationContext());

        steepDetector = new SteepDetector();
        steepDetector.registerListener(this);

        SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        if (sensorManager != null) {
            //TODO : make sensors great again!
//            Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);
            Sensor sensor2 = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
//            if (sensor != null) {
//                sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_UI);
//            } else
                if (sensor2 != null) {
                //we don't have step counter sensor! so we use accelerometer
                sensorManager.registerListener(this, sensor2, SensorManager.SENSOR_DELAY_NORMAL);
            }
        }

        locationAdder();
        receiver = new BagBroadcastReceiver();
        registerReceiver(receiver, new IntentFilter("bag_state"));

        new Handler().postDelayed(this::getAdd, 10 * 1000);

        locationCallback.registerMapboxLocationListener(this);

        updateServer();
    }

    private void getAdd() {
        if (originLocation != null) {
            try {
                address = new GetAddress(originLocation).execute().get();
//                Timber.tag("geocodeR").d("%s \n", address);
            } catch (ExecutionException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void syncProfile() {
        Handler handler = new Handler();
        handler.post(() -> {
            StringRequest stringRequest = new StringRequest(Request.Method.POST, URL_SAVE_PROFILE,
                    response -> {
                        try {
                            JSONObject obj = new JSONObject(response);
                            if (!obj.getBoolean("error")) {
                                //if there is a success
                                //storing the name to sqlite with status synced
                                dbAdapter.addProfile(countedSteps, PROFILE_SYNCED_WITH_SERVER);
                                Timber.tag("OnResponse").d("synced successfully!");
                            } else {
                                //if there is some error
                                //saving the name to sqlite with status unsynced
                                Timber.tag("OnResponse").d("not synced ");
                                dbAdapter.addProfile(countedSteps, PROFILE_NOT_SYNCED_WITH_SERVER);
                            }
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    },
                    error -> {
                        //on error storing the name to sqlite with status unsynced
                        Timber.tag("OnErrorResponse").d("not synced ");
                        dbAdapter.addProfile(countedSteps, PROFILE_NOT_SYNCED_WITH_SERVER);
                    }) {
                @Override
                protected Map<String, String> getParams() {
                    Map<String, String> params = new HashMap<>();
                    params.put("step", String.valueOf(countedSteps));
                    return params;
                }
            };

            VolleySingleton.getInstance(ForegroundService.this).addToRequestQueue(stringRequest);

        });
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        //Step Counter with StepDetector Sensor
        if (event.sensor.getType() == Sensor.TYPE_STEP_DETECTOR
                && event.values[0] == 1.0) {
            countedSteps++;
            int steps;
            int prev_odometer_steps = (int) user.get(SessionManager.getKEY_Steps());
            if (countedSteps > prev_odometer_steps) {
                steps = countedSteps - prev_odometer_steps;
                if ((int) user.get(SessionManager.getKeyCoin()) < (float) user.get(SessionManager.getKEY_BagCapacity())) {
                    BagBroadcastReceiver.isNotified = false;
                    coins += steps;
                }
            }
            if (coins >= ((float) user.get(SessionManager.getKEY_BagCapacity()))) {
                sendBroadcast(new Intent("bag_state"));
                Timber.tag("bag_coins").d("%s", coins);
            }
        } else {
            steepDetector.updateAccel(
                    event.timestamp, event.values[0], event.values[1], event.values[2]);
        }
    }

    private void updateContentProvider() {
        ContentValues contentValues = new ContentValues();
        contentValues.put(MyContentProvider.COINS , coins);
        contentValues.put(MyContentProvider.STEPS , countedSteps);
        getContentResolver().update(MyContentProvider.CONTENT_URI , contentValues , null , null);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {

    }

    @Override
    public void step(long timeNs) {
        countedSteps++;
        if ((int) user.get(SessionManager.getKeyCoin()) < (float) user.get(SessionManager.getKEY_BagCapacity())) {
            BagBroadcastReceiver.isNotified = false;
            coins += 1;
            Timber.i("foreground_updatedCoin: coins: %s \n countedSteps: %s \n steps: %s \n bagC: %s",
                    coins , countedSteps , 1 , bagCapacity);
        }
        //use content provider
        updateContentProvider();
        if (coins >= ((float) user.get(SessionManager.getKEY_BagCapacity()))) {
            sendBroadcast(new Intent("bag_state"));
            Timber.tag("bag_coins").d("%s", coins);
        }
    }

    @Override
    public void onLocationUpdate(Location lastLocation) {
        if (lastLocation != null) {
            originLocation = lastLocation;
            try {
                if (JSON_locations != null && address != null) {
                    JSON_locations = dbAdapter.LocationGetAllData().toString();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @SuppressLint("MissingPermission")
    private void activateLocationEngine() {
        locationEngine = LocationEngineProvider.getBestLocationEngine(this);
        LocationEngineRequest request = new LocationEngineRequest.Builder(DEFAULT_INTERVAL_IN_MILLISECONDS)
                .setFastestInterval(DEFAULT_INTERVAL_IN_MILLISECONDS / 5)
                .setMaxWaitTime(DEFAULT_MAX_WAIT_TIME)
                .setPriority(LocationEngineRequest.PRIORITY_BALANCED_POWER_ACCURACY)
                .build();

        locationEngine.requestLocationUpdates(request, locationCallback, Looper.getMainLooper());
        locationEngine.getLastLocation(locationCallback);

        if (!onConnectedFlag) {
            locationChecker();
            onConnectedFlag = true;
        }
    }


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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null &&
                ACTION_STOP_SERVICE.equals(intent.getAction())) {
            stopSelf();
            if (locationEngine != null) {
                locationEngine.removeLocationUpdates(locationCallback);
            }
        } else {
            activateLocationEngine();
            displaySawTreasures();
            updateTreasures();
            updateValues(intent);
        }
        startForegroundService();
        Timber.i("onStartCommand Started!");
        return START_STICKY;
    }

    private void updateValues(Intent intent) {
        if (intent != null){
            coins = intent.getIntExtra(COIN_MAP_FOREGROUND , 0);
            bagCapacity = intent.getFloatExtra(BAG_CAPACITY_MAP_FOREGROUND , 0f);
            Cursor cursor = getContentResolver().query(MyContentProvider.CONTENT_URI ,
                    null , null , null , null);
            if (cursor != null){
                if (cursor.moveToFirst()){
                    while (!cursor.isAfterLast()){
                        dailySteps = cursor.getInt(cursor.getColumnIndex(MyContentProvider.STEPS));
                    }
                }
                cursor.close();
            }
            Timber.i("foreground_userUpdated \n coins: %s \n bagCapacity: %s \n dailySteps: %s" ,
                    coins , bagCapacity , dailySteps);
        }
    }

    private void startForegroundService() {
        /*
         * Notification for foreground Service
         * */
        int notification_id = (int) System.currentTimeMillis();
        RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.notification_custom);

        Intent button_intent = new Intent(this, ForegroundService.class);
        button_intent.setAction(ACTION_STOP_SERVICE);
        PendingIntent button_pending = PendingIntent.getService(
                this,
                0,
                button_intent,
                PendingIntent.FLAG_CANCEL_CURRENT);
        remoteViews.setTextViewText(R.id.notif_txt, String.valueOf(dailySteps));
        remoteViews.setOnClickPendingIntent(R.id.notif_btn, button_pending);

        //action intent
        Intent actionIntent = new Intent(this, MapBoxActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(
                this,
                0,
                actionIntent,
                PendingIntent.FLAG_UPDATE_CURRENT
        );


        NotificationCompat.Builder builder =
                new NotificationCompat.Builder(this, CHANNEL_ID)
                        .setSmallIcon(R.drawable.ic_stat_notification_small)
                        .setContentTitle(getResources().getString(R.string.notification_title))
                        .setCustomBigContentView(remoteViews)
                        .setPriority(NotificationCompat.PRIORITY_LOW)
                        .addAction(R.id.notif_btn, "Stop", pendingIntent)
                        .setAutoCancel(false);
        if (dailySteps < 2000) {
            builder.setContentText("ماجراجویی بیشتر، گنج بیشتر!!");
        } else if (dailySteps > 2000 && dailySteps < 4000) {
            builder.setContentText("خوبه! امروز خوب فعالیت داشتی!");
        } else if (dailySteps >= 4000 && dailySteps < 6000) {
            builder.setContentText("ایول! امروز خوب تلاش کردی!");
        } else if (dailySteps >= 6000 && dailySteps < 8000) {
            builder.setContentText("رفیق امروز میخوای بترکونی؟!");
        } else if (dailySteps >= 8000 && dailySteps < 10000) {
            builder.setContentText("میبینم کههه خیلی عالی پیش رفتی امروز!");
        } else if (dailySteps >= 10000) {
            builder.setContentText("رفیق ترکوندی! تو فوق العاده ای!");
        }
        builder.setContentIntent(pendingIntent);

        Notification notification = builder.build();

        startForeground(notification_id, notification);

        Timber.i("foreground Started!");

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        locationEngine.removeLocationUpdates(locationCallback);
        unregisterReceiver(receiver);
        if (originLocation != null) originLocation = null;
        if (JSON_locations != null) JSON_locations = null;
        if (JSON_locations_tmp != null) JSON_locations_tmp = null;
        if (geocodeAddress != null) geocodeAddress = null;
        if (address != null) address = null;
        if (dbAdapter != null) dbAdapter = null;
        wakeLock.release();
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        locationEngine.removeLocationUpdates(locationCallback);
        stopSelf();
    }

    private void sendTreasureNotification(MarkerItem markerItem, SparseArray<MarkerItem> updatedList) {

        NotificationCompat.Builder builder =
                new NotificationCompat.Builder(this, CHANNEL_ID)
                        .setSmallIcon(R.drawable.ic_stat_notification_small)
                        .setContentTitle(getResources().getString(R.string.notification_text))
                        .setPriority(NotificationCompat.PRIORITY_HIGH)
                        .setVibrate(new long[]{0, 250, 250, 250, 250})
                        .setLights(Color.BLUE, 1000, 2000)
                        .setAutoCancel(true);
        if (!sessionManager.isLoggedIn())
            builder.setContentText("برای بدست آوردنش وارد حسابت شو!");

        //creating an action Intent and passing the values to the GoogleMapActivity from Service
        Intent actionIntent = new Intent(this, MapBoxActivity.class);
        actionIntent.setAction("newTreasureList");
        actionIntent.putExtra("list", (Parcelable) updatedList);

        PendingIntent actionPendingIntent = PendingIntent.getActivity(this,
                0,
                actionIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentIntent(actionPendingIntent);
        //issue the notification
        NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        if (notificationManager != null && sawTreasuresList.get(markerItem.getId()) == null) {
            //Log.d("markerIds",markerItem.getOwnerId()+"-"+(Integer)user.get(SessionManager.getKeyId()));
            if (markerItem.getOwnerId() != (int) user.get(SessionManager.getKeyId())) {
                notificationManager.notify(1, builder.build());
            }
            sawTreasuresList.put(markerItem.getId(), markerItem);
            Timber.tag("notification_sent").d(updatedList.toString());
        }
    }

    private void displaySawTreasures() {
        final Handler handler = new Handler(Looper.getMainLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                if (originLocation != null) {
                    for (int i = 0; i < treasuresList.size(); i++) {
                        MarkerItem markerItem = treasuresList.valueAt(i);
                        sendTreasureNotification(markerItem, sawTreasuresList);
                        treasuresList.delete(markerItem.getId());
                    }
                }
                handler.postDelayed(this, 12 * 60 * 1000);
            }
        });

    }

    private ArrayList<JSONObject> getJsonTreasures(String json) {

        ArrayList<JSONObject> jsonObjectArrayList = new ArrayList<>();
        if (json != null) {
            try {
jsonObject.get("server_response");
                JSONArray jsonArray = new JSONArray(json);

                for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject object = (JSONObject) jsonArray.get(i);
                    jsonObjectArrayList.add(object);

                    MarkerItem markerItem = new MarkerItem(object.getInt("locationId"),
                            object.getInt("ownerId"), object.getString("owner"),
                            object.getDouble("latitude"), object.getDouble("longitude"),
                            object.getInt("value"), object.getInt("shovelId"), object.getInt("shovel"),
                            object.getString("charmLink"),
                            object.getInt("depth"));
                    treasuresList.put(markerItem.getId(), markerItem);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return jsonObjectArrayList;
    }

    private void locationAdder() {
        final Handler handler = new Handler(Looper.getMainLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {
//                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                if (NetworkUtil.hasNetworkAccess())
                    if (JSON_locations != null)
                        if (!JSON_locations.equals(JSON_locations_tmp)) {
//                            Log.d("LocationsStatus",JSON_locations.equals(JSON_locations_tmp)+"");
                            JSON_locations_tmp = JSON_locations;
                            //adding json information to the array list of JSONObject
                            ArrayList<JSONObject> jsonObjectArrayList = getJsonTreasures(JSON_locations);
                            treasuresList.clear();
                            if (jsonObjectArrayList != null) {
                                for (JSONObject jsonObject : jsonObjectArrayList) {
                                    try {
                                        String latitude = jsonObject.getString("latitude");
                                        String longitude = jsonObject.getString("longitude");
                                        if (!latitude.equals("") && !longitude.equals("")) {
                                            MarkerItem markerItem = new MarkerItem(jsonObject.getInt("locationId"),
                                                    jsonObject.getInt("ownerId"), jsonObject.getString("owner"),
                                                    jsonObject.getDouble("latitude"), jsonObject.getDouble("longitude"),
                                                    jsonObject.getInt("value"), jsonObject.getInt("shovelId"), jsonObject.getInt("shovel"),
                                                    jsonObject.getString("charmLink"),
                                                    jsonObject.getInt("depth"));
                                            treasuresList.put(markerItem.getId(), markerItem);
                                        }
                                    } catch (JSONException e) {
                                        e.printStackTrace();
                                    }
                                }
                                SparseArray<MarkerItem> tmp = new SparseArray<>();
                                for (int i = 0; i < treasuresList.size(); i++) {
                                    MarkerItem m = treasuresList.valueAt(i);
                                    if (sawTreasuresList.get(m.getId()) != null) {
                                        tmp.put(m.getId(), m);
                                    }
                                }
                                sawTreasuresList = tmp;
                            }
                        }
                handler.postDelayed(this, 11 * 60 * 1000);
            }
        });
    }

    private void updateServer() {
        Handler handler = new Handler();
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (NetworkUtil.hasNetworkAccess()){
                    if (originLocation != null){
                        try {
                            address = new GetAddress(originLocation).execute().get();
                        } catch (InterruptedException | ExecutionException e) {
                            e.printStackTrace();
                        }
                        if (address != null) {
                            new LocationTask(ForegroundService.this).execute("updatePoint",
                                    String.valueOf(coins), String.valueOf(1),
                                    String.valueOf(originLocation.getLatitude()), String.valueOf(originLocation.getLongitude()),
                                    address, address);
                        } else {
                            new LocationTask(ForegroundService.this).execute("updatePoint", String.valueOf(coins), String.valueOf(1),
                                    String.valueOf(originLocation.getLatitude()), String.valueOf(originLocation.getLongitude()),
                                    "not titled", "not titled");
                        }
                        Timber.d("update_server: COINS: %s \n originLocation: %s \n address: %s " ,
                                coins , originLocation.toString(),address);
                    }
                }

                //TODO update server data every 1 hour
                handler.postDelayed(this , 30 * 1000);
            }
        });
    }

    private void updateTreasures() {
        final Handler handler = new Handler(Looper.getMainLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (NetworkUtil.hasNetworkAccess()) {
//                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    try {
                        address = new GetAddress(originLocation).execute().get();
                        if (address != null) {
                            new LocationTask(ForegroundService.this).execute("getLocations", address);
                            JSON_locations = dbAdapter.LocationGetAllData().toString();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                //set up to 17 mins
                handler.postDelayed(this, 17 * 60 * 1000);
            }
        });
    }

    private void locationChecker() {
        final Handler handler = new Handler(Looper.getMainLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                if (originLocation != null && onConnectedFlag && NetworkUtil.hasNetworkAccess()) {
                    try {
                        address = new GetAddress(originLocation).execute().get();

                        if (address != null) {
                            zone = address;
                        }

                        if (zone != null && !zone.equals(currentZone)) {
                            currentZone = zone;
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                //set up to 19 mins
                handler.postDelayed(this, 19 * 60 * 1000);
            }
        });
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(CalligraphyContextWrapper.wrap(base));
    }

и я просто не могу понять, почему это происходит, потому что я работал, может быть, 4 часа назад! но пока это не работает ...

Обновление: около 9 часов назад, когда я использовал свой телефон, и внезапно я увидел, что началось Уведомление о моей службе Foreground! поэтому я понял, что система не запускает мой процесс Foreground (или немедленно его убивает) и запускает его, когда захочет! (возможно, в соответствии с управлением воспоминаниями) Так почему это так? и как можно решить?

1 Ответ

0 голосов
/ 28 мая 2019

Мой Глупый Плохой! причина, по которой моя служба не запускалась и в большинстве случаев мое приложение зависало, была вызвана методом updateValues(intent) внутри onStartCommand! У него есть некоторое время Loop, что условие было неправильным, и он застрял в бесконечном цикле! так что по этой причине код не пошел дальше, чтобы завершить onStartCommand и запустить Сервис!

...