我有一个在清单中和一个不同过程中定义的前台服务,当我的活动运行且一切运行正常时,我曾经调用它,但是当我想启动前台服务时,突然我的onStartCommand不再调用,只有onCreate方法!我看不到我的Log on 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);
}
然后在“活动”的onCreate方法中调用startServices()
方法。
这是我的前台服务的代码:
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个小时前,我在使用手机,突然我看到了“前台服务通知”!因此我发现系统不会启动我的前景进程(或立即将其终止)并在需要时启动它(也许是根据管理内存) 那为什么会这样呢?以及如何解决?
答案 0 :(得分:0)
我的蠢坏蛋!
我的服务无法启动并且我的应用大部分时间崩溃的原因是因为updateValues(intent)
内部的方法onStartCommand
!
它有一个while循环,表明条件不正确,并且陷入了无限循环!因此这就是代码无法进一步完成onStartCommand
并启动服务的原因!