简体   繁体   English

Android Foreground Service onStartCommand不会调用,只有onCreate调用

[英]Android Foreground Service onStartCommand doesn't invoke, only onCreate invokes

I have a Foreground service which is defined in manifest and in a different process and I used to call it when my activity runs and everything was working good but suddenly when I want to start the foreground Service the onStartCommand doesn't invoke anymore, only the onCreate method! 我有一个前台服务,它在清单和不同的进程中定义,我曾经在我的活动运行时调用它,一切都运行良好但突然间,当我想启动前台服务onStartCommand不再调用,只有onCreate方法! and I cant see my Log in onStartCommand method... 我无法看到我的登录onStartCommand方法...

This is My Service declared in Manifest: 这是在Manifest中声明的My Service:

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

here is my code, for starting the service : 这是我的代码,用于启动服务:

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);
    }

and I call startServices() method in my onCreate method of my Activity... 我在我的Activity的onCreate方法中调用startServices()方法...

and here is the code of my Foreground service: 这是我的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));
    }

and I simply can't understand why is this happening cause I was working for maybe 4 hours ago! 而且我简直无法理解为什么会发生这种情况因为我工作了大概4小时前! but it doesn't work for now... 但它现在不起作用......

Update: for about 9 hours earlier I was using my phone and suddenly I saw the Notification of my Foreground Service started! 更新:大约9个小时前,我正在使用我的手机突然看到我的前台服务通知开始了! so I figured it out that the system doesn't start my Foreground process (or kill it immediately) and start it whenever it wants!(according to managing the memories perhaps) So why is that so? 所以我发现系统没有启动我的前台进程(或立即杀死它)并随时启动它!(根据管理的记忆或许) 所以为什么会这样呢? and how can be resolved? 怎么解决?

My Stupid Bad! 我的愚蠢不好! the reason that my service didn't start and most of the time my app crashed was because of the method updateValues(intent) inside of onStartCommand ! 我的服务没有启动,大部分我的应用程序崩溃时的原因是因为该方法的updateValues(intent)的内部onStartCommand It has a while Loop that the condition wasn't right and it got stuck in an infinite loop! 它有一个循环,条件不对,它陷入无限循环! so that was the reason code did't go further to complete the onStartCommand and start the Service! 所以这就是代码没有进一步完成onStartCommand并启动服务的原因!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM