我正在尝试制作计算出租车/汽车票价的应用程序。该应用程序将作为后台服务运行,即使在用户退出应用程序后,仍会在后台更新乘坐数据,如位置,票价,距离等。当用户按下停止按钮时,该服务将停止。现在我的问题是,每次激活恢复/重新启动时,它都会重置为初始状态 - 就像服务停止一样。如何持续更新UI以使活动保持更新,以便每当用户访问页面时都会显示更新的数据。我正在跑一个STICKY服务。
这是我的服务
public class LocationManager extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private static final String TAG = LocationManager.class.getSimpleName();
double last_lat = -1000.0f;
double last_lon = -1000.0f;
double dist_total = 0.0f;
double fare_total = 0.0f;
long start_time = -1;
private GoogleApiClient mGoogleApiClient;
private Context mContext;
private LocationRequest mLocationRequest;
private boolean mToStartUpdates = false;
private boolean isInited = false;
private long mLastLocationMillis = 0;
private SharedPreferences settings;
String rideTime = "00h:00m:00s";
private IBinder mBinder = new TukTukMeterBinder();
private Timer timer = new Timer();
public LocationManager(){}
public void init(boolean startUpdates) {
mToStartUpdates = startUpdates;
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
}
}
public class TukTukMeterBinder extends Binder{
LocationManager getBinder(){
return LocationManager.this;
}
}
public double getDistanceTraveled(){
return dist_total;
}
public double getFare_total(){
return fare_total;
}
public double getLast_lat(){
return last_lat;
}
public double getLast_lon(){
return last_lon;
}
public String getRideTime(){
return rideTime;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onCreate() {
super.onCreate();
mContext = this;
init(true);
}
@Override
public void onConnected(Bundle bundle) {
LogUtil.i("GoogleApiClient connection has Connected");
isInited = true;
if (mToStartUpdates && RequirementHelper.isLocationEnabled(mContext)) {
createLocationRequest();
} else {
createLocationRequestDialog();
}
}
@Override
public void onConnectionSuspended(int i) {
LogUtil.i("Could not connect to googleApiClient" + i);
if (mGoogleApiClient != null) {
mGoogleApiClient.reconnect();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction().equals(AppConstants.ACTION.STARTFOREGROUND_ACTION)) {
LogUtil.i("Received Start Foreground Intent ");
buildNotification();
start_time = System.currentTimeMillis();
mHandler.postDelayed(mUpdateTimeTask,1000);
} else if (intent.getAction().equals(AppConstants.ACTION.STOPFOREGROUND_ACTION)) {
stopForeground(true);
stopSelf();
mHandler.removeCallbacks(mUpdateTimeTask);
}
return START_STICKY;
}
private void buildNotification() {
Intent notificationIntent = new Intent(this, TukTukHomeActivity.class);
notificationIntent.setAction(AppConstants.ACTION.MAIN_ACTION);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
Bitmap icon = BitmapFactory.decodeResource(getResources(),
R.mipmap.ic_launcher);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("TukTuk Meter")
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(
Bitmap.createScaledBitmap(icon, 128, 128, false))
.setContentIntent(pendingIntent)
.setOngoing(true)
.build();
startForeground(AppConstants.NOTIFICATION_ID.FOREGROUND_SERVICE,
notification);
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
isInited = false;
}
/**
* This method will automatically creates a dialog for automatically turning on GPS without navigating to settings activity.
*/
public void createLocationRequestDialog() {
mLocationRequest = LocationRequest.create();
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
builder.setAlwaysShow(true);
PendingResult<LocationSettingsResult> result =
LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
@Override
public void onResult(LocationSettingsResult result) {
final Status status = result.getStatus();
final LocationSettingsStates state = result.getLocationSettingsStates();
LogUtil.d("onResult state:[" + state + "]");
LogUtil.d("onResult status:[" + status + "]");
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS://Already have a location.
if (RequirementHelper.isLocationEnabled(mContext)) {
createLocationRequest();
break;
} else {
}//$fallthrough without break
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
LogUtil.d("showing request loccation dialog");
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
status.startResolutionForResult(((Activity) mContext), TukTukHomeActivity.REQUEST_ENABLE_GPS);
} catch (IntentSender.SendIntentException e) {
// Ignore the error.
}
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
// Location settings are not satisfied. However, we have no way to fix the
// settings so we won't show the diaLogUtil.
break;
}
}
});
}
/**
* The dialog to be shown to turn on location is currently disabled.
*/
public void createLocationRequest() {
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(10 * 1000);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
builder.setAlwaysShow(true);
requestLocationUpdates();
}
public void requestLocationUpdates() {
if (mGoogleApiClient.isConnected() && RequirementHelper.hasAnyLocationPermission(mContext)) {
LogUtil.d("requestLocationUpdates");
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, LocationManager.this);
}
}
@Override
public void onLocationChanged(Location location) {
LogUtil.d("Fetched AdsLocation" + location);
if (location != null) {
// DataStorePrefManager.getInstance(mContext).saveLastKnownLocation(location);
mLastLocationMillis = SystemClock.elapsedRealtime();
settings = PreferenceManager.getDefaultSharedPreferences(mContext);
double min_fare = settings.getFloat(DataStorePrefManager.KEY_BASE_FARE, 0.0f);
double min_dist = settings.getFloat(DataStorePrefManager.KEY_MIN_DISTANCE, 0.00f);
double rate_per_km = settings.getFloat(DataStorePrefManager.KEY_KM_FARE, 0.00f);
Log.i(TAG, location.getLatitude() + " , " + location.getLongitude());
if (last_lat < -90 || last_lon < -180) {
last_lat = location.getLatitude();
last_lon = location.getLongitude();
} else {
double lat1 = Math.toRadians(last_lat);
double lon1 = Math.toRadians(last_lon);
double lat2 = Math.toRadians(location.getLatitude());
double lon2 = Math.toRadians(location.getLongitude());
double R = 6371.0f;
double dLat = (lat2 - lat1);
double dLon = (lon2 - lon1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1) * Math.cos(lat2) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double d = R * c;
if (d > 0.05 && location.getAccuracy() < 50) // Add only if delta > 50 m and uncertainty < 50m
{
dist_total += d;
if (dist_total > min_dist) {
fare_total = min_fare + (dist_total - min_dist) * rate_per_km;
} else {
fare_total = min_fare;
}
Log.i("Distance", Double.toString(dist_total));
last_lat = location.getLatitude();
last_lon = location.getLongitude();
}
}
DecimalFormat df = new DecimalFormat("#.0");
df.format(fare_total);
df.format(dist_total);
} else return;
}
public void onDestroy() {
isInited = false;
mHandler.removeCallbacks(mUpdateTimeTask);
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
public boolean isInited() {
return isInited;
}
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
private Runnable mUpdateTimeTask = new TimerTask() {
@Override
public void run() {
int hrs = 0,min = 0,sec= 0;
if(start_time != -1)
{
int interval = (int) (System.currentTimeMillis() - start_time)/1000;
sec = interval%60;
min = interval/60;
hrs = interval/3600;
rideTime = String.format("%02dh:%02dm:%02ds", hrs,min,sec);
}
if(isInited){
mHandler.postDelayed(this,1000);
}
}};
}
这是我的活动
public class TukTukHomeActivity extends AppCompatActivity implements View.OnClickListener, NavigationView.OnNavigationItemSelectedListener {
LocationManager mLocationManager;
public static final int REQUEST_ENABLE_GPS = 100;
boolean bound = false;
TextView rideDistance, totalFare, rideTotalTime, mapsTv;
private DrawerLayout mDrawerLayout;
double distance = 0;
double fareTotal = 0;
String rideTime = "00h:00m:00s";
boolean isRunning = false;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
LocationManager.TukTukMeterBinder mBinder = (LocationManager.TukTukMeterBinder) service;
mLocationManager = mBinder.getBinder();
bound = true;
initUI();
displayDistance();
}
@Override
public void onServiceDisconnected(ComponentName name) {
bound = false;
mLocationManager = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
initUI();
findViewById(R.id.startRide).setOnClickListener(this);
toolbar.setNavigationIcon(R.drawable.menu);
toolbar.setNavigationOnClickListener(this);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, mDrawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close);
mDrawerLayout.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.navigation);
navigationView.setNavigationItemSelectedListener(this);
}
private void initUI(){
rideDistance = (TextView)findViewById(R.id.rideDistance) ;
totalFare = (TextView)findViewById(R.id.fareTotal);
rideTotalTime = (TextView)findViewById(R.id.rideTime) ;
mapsTv = (TextView)findViewById(R.id.openMaps);
mapsTv.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.startRide:
startMeterService();
break;
case R.id.drawerLayout:
mDrawerLayout.openDrawer(GravityCompat.START);
break;
case R.id.openMaps:
startActivity(new Intent(this,TukTukMaps.class));
break;
}
}
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawerLayout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.items, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
startActivity(new Intent(TukTukHomeActivity.this, TukTukSettings.class));
return true;
}
if(id == R.id.navigation){
mDrawerLayout.openDrawer(GravityCompat.START);
return true;
}
return super.onOptionsItemSelected(item);
}
private void startMeterService() {
Intent startIntent = new Intent(this, LocationManager.class);
startIntent.setAction(AppConstants.ACTION.STARTFOREGROUND_ACTION);
startService(startIntent);
bindService(startIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
displayDistance();
}
@Override
protected void onResume() {
super.onResume();
initUI();
displayDistance();
}
private void displayDistance() {
final Handler handler = new Handler();
handler.post(new Runnable() {
@Override
public void run() {
if (mLocationManager != null) {
distance = mLocationManager.getDistanceTraveled();
fareTotal = mLocationManager.getFare_total();
rideTime = mLocationManager.getRideTime();
}
rideDistance.setText(String.valueOf(distance)+"km");
totalFare.setText(getResources().getString(R.string.min_fare_symbol)+String.valueOf(fareTotal));
rideTotalTime.setText(String.valueOf(rideTime));
handler.postDelayed(this, 1000);
}
});
}
@Override
protected void onStop() {
super.onStop();
if (bound) {
unbindService(mServiceConnection);
bound = false;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_ENABLE_GPS:
switch (resultCode) {
case Activity.RESULT_OK:
startMeterService();
break;
case Activity.RESULT_CANCELED:
break;
}
break;
}
}
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.about_us:
startActivity(new Intent(TukTukHomeActivity.this,AboutUs.class));
mDrawerLayout.closeDrawers();
return true;
}
return true;
}
}
答案 0 :(得分:0)
将数据从服务发送到活动
Intent i = new Intent();
i.setAction(SOME_ACTION_NAME);
i.setExtra(KEY,VALUE);
context.sendBroadcast(i);
在活动中使用广播接收器
BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(SOME_ACTION_NAME) {
//read your extra from intent
}
}
}
将您的操作名称添加到意图过滤器并注册广播接收器。
答案 1 :(得分:0)