Java Android-调用bindservice,但无法访问该服务中的任何方法
所以我一直在写一个应用程序来确定你的跑步速度,并将其整合到日常锻炼中。由于我是Android新手,我在一项活动中做了所有的事情,但我已经达到了一个点,我想将速度计算部分以及涉及GPS的所有事情转移到一项服务上,这项服务将绑定到任何需要它的锻炼 这是锻炼活动:Java Android-调用bindservice,但无法访问该服务中的任何方法,java,android,android-service,android-binder,Java,Android,Android Service,Android Binder,所以我一直在写一个应用程序来确定你的跑步速度,并将其整合到日常锻炼中。由于我是Android新手,我在一项活动中做了所有的事情,但我已经达到了一个点,我想将速度计算部分以及涉及GPS的所有事情转移到一项服务上,这项服务将绑定到任何需要它的锻炼 这是锻炼活动: package com.example.stropheum.speedcalculatortest; import android.content.ComponentName; import android.content.Context
package com.example.stropheum.speedcalculatortest;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.IBinder;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.os.Vibrator;
import com.example.stropheum.speedcalculatortest.SpeedCalculationService.SpeedCalculationBinder;
public class SpeedAlarmActivity extends ActionBarActivity {
public SpeedCalculationService speedCalculator;
boolean isBound = false;
final int MILLI_TO_SEC = 1000;
final int SEC_TO_HOUR = 3600;
double currentPace, goalPace;
String paceText;
Vibrator vibrator;
// Allow 15 seconds of error for time calculations
final double MILE_TIME_ERROR = 0.25;
LocationManager locationManager;
LocationListener locationListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent i = new Intent(this, SpeedCalculationService.class);
startService(i);
bindService(i, speedConnection, Context.BIND_AUTO_CREATE);
// Starts the service for calulating user's speed
//startService(new Intent(getBaseContext(), SpeedCalculationService.class)); // was below bind before
vibrator = (Vibrator) this.getSystemService(Context.VIBRATOR_SERVICE);
setContentView(R.layout.activity_speed_alarm);
double startTime, elapsedTime;
double alertIntervalStart, alertIntervalElapsed;
double speed, goalPace, currentPace;
String paceText = "Waiting for GPS signal";
updatePaceText(paceText);
if (isBound);
// Delays workout until the service finds a signal
while (!speedCalculator.gpsSignalFound());
// Once GPS connection is established, being the workout
paceText = "Begin!";
updatePaceText(paceText);
///////////////////
// Part One Begins
/////////////////
startTime = System.currentTimeMillis();
elapsedTime = 0;
alertIntervalStart = startTime; // Initialize 30 second timer on workout start
goalPace = 10.0;
updateGoalPace(goalPace);
do {
// Update time since last alert
alertIntervalElapsed = System.currentTimeMillis() - alertIntervalStart;
speed = speedCalculator.getCurrentSpeed();
currentPace = 60 / speed;
// Update speed and pace every second
if (elapsedTime >= 1.0 * MILLI_TO_SEC) {
updateSpeed(speed);
updateCurrentPace(currentPace);
}
// Alerts user if 30 seconds have gone by with no change
if (alertIntervalStart >= 30 * MILLI_TO_SEC) {
paceAlert();
alertIntervalStart = System.currentTimeMillis();
}
// If 5 seconds have elapsed and perfect pace, alert user
if (alertIntervalElapsed >= 5 * MILLI_TO_SEC && checkPace(currentPace, goalPace)) {
paceAlert();
alertIntervalStart = System.currentTimeMillis();
}
elapsedTime = System.currentTimeMillis() - startTime;
} while (elapsedTime < 120 * MILLI_TO_SEC);
paceText = "Workout Complete!";
updatePaceText(paceText);
// ///////////////////
// // Part Two Begins
// /////////////////
// startTime = System.currentTimeMillis();
// elapsedTime = 0;
// alertIntervalStart = startTime; // Initialize 30 second timer on workout start
//
// goalPace = 6.0;
//
// do {
//
// elapsedTime = System.currentTimeMillis() - startTime;
// } while (elapsedTime < 60 * MILLI_TO_SEC);
//
//
}
/**
* Checks if the user is running in an acceptable range of the goal pace
* @param currentPace Current speed of the user
* @param goalPace Goal speed of the user
* @return True if the pace is acceptable, false otherwise
*/
private boolean checkPace(double currentPace, double goalPace) {
boolean result = true;
if (currentPace > goalPace + MILE_TIME_ERROR || currentPace < goalPace - MILE_TIME_ERROR) {
result = false;
}
return result;
}
/**
* Updates the display to show the current speed
* @param speed The current speed of the user
*/
private void updateSpeed(double speed) {
final TextView speedVal = (TextView) findViewById(R.id.SpeedVal);
speedVal.setText(String.format("%.2f", speed));
}
/**
* Updates the current estimated mile time
* @param currentPace User's current mile time
*/
private void updateCurrentPace(double currentPace) {
int minutes = (int)currentPace;
int seconds = (int)(((currentPace * 100) % 100) * 0.6);
final TextView emtVal = (TextView) findViewById(R.id.emtVal);
emtVal.setText(String.format("%d:%02d", minutes, seconds));
}
/**
* Updates the current goal mile time
* @param goalPace New goal mile time
*/
private void updateGoalPace(double goalPace) {
int minutes = (int)goalPace;
int seconds = (int)(((goalPace * 100) % 100) * 0.6);
final TextView gmtVal = (TextView) findViewById(R.id.gmtVal);
gmtVal.setText(String.format("%d:%02d", minutes, seconds));
}
/**
* Updates the current pace text
* @param paceText indicator for user;s current speed in relation to goal time
*/
private void updatePaceText(String paceText) {
final TextView pace = (TextView) findViewById(R.id.paceView);
pace.setText(paceText);
}
/**
* Checks current pace and assigns appropriate text
*/
private void paceAlert() {
if (currentPace > goalPace + MILE_TIME_ERROR) {
paceText = "Speed up";
vibrator.vibrate(300);
try {
Thread.sleep(300);
} catch (Exception e) {}
vibrator.vibrate(300);
try {
Thread.sleep(300);
} catch (Exception e) {}
vibrator.vibrate(300);
} else if (currentPace < goalPace - MILE_TIME_ERROR) {
paceText = "Slow Down";
vibrator.vibrate(1000);
} else {
paceText = "Perfect Pace!";
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_speed_alarm, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
locationManager.removeUpdates(locationListener);
// Terminate the speed calculation service
stopService(new Intent(getBaseContext(), SpeedCalculationService.class));
finish();
return;
}
ServiceConnection speedConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
SpeedCalculationBinder binder = (SpeedCalculationBinder) service;
speedCalculator = binder.getService();
isBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
}
};
}
我已经设法缩小了错误来自于调用时返回null值的服务中的方法的范围,并且我添加了一些调试行,以确定isBound变量从未设置为true,因此服务实际上没有绑定到活动,我非常确定这就是为什么我会得到NullPointerException
任何帮助都将是美妙的,我似乎在我的搜索中找不到任何关于我的问题是什么。据我所知,我已经正确地绑定了服务。谢谢你的时间 我没有看到您启动该服务,您应该执行以下操作:
Intent intent = new Intent(this, SpeedCalculationService.class);
startService(intent);
bindService(intent, speedConnection, Context.BIND_AUTO_CREATE);
您需要确保在启动和绑定服务时使用相同的意图
以下是“Context.BIND\u AUTO\u CREATE”的一些文档:
请注意,只有显式调用startService时才会调用onCommandStart。您需要调用startService(i);在BindServiceAllow之前-这段代码很糟糕。你会因为其他十几个原因而崩溃。你不能只是在onCreate中等待,你会绊倒看门狗并被杀。即使你没有,这也是一个糟糕的用户体验。我真的不明白你想告诉我什么。你说等待是什么意思?你说让看门狗绊倒是什么意思?为什么这是一种糟糕的用户体验?我一开始就有这种体验,我读到绑定服务会启动它,所以我认为这会引起某种冲突。我刚加了那一行,错误与你不能加的那一行完全相同。您需要使用相同的目的您应该确保您的代码到达ServiceConnection中的OnServiceConnection。然后在确定服务已连接后,从那里启动与服务相关的任何内容
Intent intent = new Intent(this, SpeedCalculationService.class);
startService(intent);
bindService(intent, speedConnection, Context.BIND_AUTO_CREATE);
* Flag for {@link #bindService}: automatically create the service as long
* as the binding exists. Note that while this will create the service,
* its {@link android.app.Service#onStartCommand}
* method will still only be called due to an
* explicit call to {@link #startService}. Even without that, though,
* this still provides you with access to the service object while the
* service is created.