[英]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.