这就是我要做的事情。我有一个需要处理一些加速度计数据的活动。所以我创建了一个服务,扩展了" Service"并实现" SensorEventListener"
这是我的活动代码:
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Color;
import android.os.IBinder;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import com.jjoe64.graphview.GraphView;
import com.jjoe64.graphview.series.DataPoint;
import com.jjoe64.graphview.series.LineGraphSeries;
public class GraphActivity1 extends ActionBarActivity {
private GraphView graph1;
private GraphView graph2;
private DataPoint[] xdata = new DataPoint[64];
private DataPoint[] ydata = new DataPoint[64];
private DataPoint[] zdata = new DataPoint[64];
private DataPoint[] fxdata = new DataPoint[64];
private DataPoint[] fydata = new DataPoint[64];
private DataPoint[] fzdata = new DataPoint[64];
private Complex[] xcdata = new Complex[64];
private Complex[] ycdata = new Complex[64];
private Complex[] zcdata = new Complex[64];
private Complex[] xfdata = new Complex[64];
private Complex[] yfdata = new Complex[64];
private Complex[] zfdata = new Complex[64];
private final int FFT_SIZE = 64;
private boolean RUN_FLAG = true;
private char run_times = 10;
BoundService myService;
boolean isBound = false;
private ServiceConnection myConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
BoundService.MyLocalBinder binder = (BoundService.MyLocalBinder) service;
myService = binder.getService();
isBound = true;
}
public void onServiceDisconnected(ComponentName arg0) {
isBound = false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_graph_activity1);
Log.i("New Tag", "Graph Activity Created");
graph1 = (GraphView)findViewById(R.id.timegraph);
graph2 = (GraphView)findViewById(R.id.frequencygraph);
Intent intent = new Intent(this, BoundService.class);
startService(intent);
Log.i("New Tag", "Service Started");
bindService(intent, myConnection, Context.BIND_AUTO_CREATE);
while (!isBound){
Log.i("New Tag", "Service Binding in Progress");
}
Log.i("New Tag", "Service Bound");
}
@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_graph_activity1, 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 onStart(){
Log.i("New Tag", "Graph Activity Started");
while(RUN_FLAG){
Log.i("New Tag", "Entered While Loop");
int i_state = myService.getStatus();
//Log.i("New Tag", "State is"+i_state);
if (i_state == 1){
Log.i("New Tag", "Entered Second While Loop");
Complex[][] alldata = myService.getData();
xcdata = alldata[0];
ycdata = alldata[1];
zcdata = alldata[2];
for (int i = 0; i < FFT_SIZE; i++){
xdata[i] = new DataPoint(i, xcdata[i].re());
ydata[i] = new DataPoint(i, ycdata[i].re());
zdata[i] = new DataPoint(i, zcdata[i].re());
}
xfdata = FFT.fft(xcdata);
yfdata = FFT.fft(ycdata);
zfdata = FFT.fft(zcdata);
for (int i = 0; i < FFT_SIZE; i++){
fxdata[i] = new DataPoint(i, xfdata[i].abs());
fydata[i] = new DataPoint(i, yfdata[i].abs());
fzdata[i] = new DataPoint(i, zfdata[i].abs());
}
LineGraphSeries<DataPoint> series1t = new LineGraphSeries<DataPoint>(xdata);
LineGraphSeries<DataPoint> series2t = new LineGraphSeries<DataPoint>(ydata);
LineGraphSeries<DataPoint> series3t = new LineGraphSeries<DataPoint>(zdata);
LineGraphSeries<DataPoint> series1f = new LineGraphSeries<DataPoint>(fxdata);
LineGraphSeries<DataPoint> series2f = new LineGraphSeries<DataPoint>(fydata);
LineGraphSeries<DataPoint> series3f = new LineGraphSeries<DataPoint>(fzdata);
series1t.setColor(Color.RED);
series2t.setColor(Color.GREEN);
series3t.setColor(Color.BLUE);
graph1.addSeries(series1t);
graph1.addSeries(series2t);
graph1.addSeries(series3t);
graph1.setTitle("Time Domain Data [x(red), y(green), z(blue)]");
series1f.setColor(Color.RED);
series2f.setColor(Color.GREEN);
series3f.setColor(Color.BLUE);
graph2.addSeries(series1f);
graph2.addSeries(series2f);
graph2.addSeries(series3f);
graph2.setTitle("Frequency Domain Data [x(red), y(green), z(blue)]");
graph1.removeAllSeries();
graph2.removeAllSeries();
}
run_times --;
if (run_times == 0)
{
RUN_FLAG = false;
}
}
}
}
以及我的服务代码:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
import com.jjoe64.graphview.series.DataPoint;
public class BoundService extends Service implements SensorEventListener {
private SensorManager senSensorManager;
private Sensor senAccelerometer;
private long lastUpdate = 0;
private int data_index = 0;
private static final int FFT_SIZE = 64;
private Complex[] xdata;
private Complex[] ydata;
private Complex[] zdata;
private Complex[][] alldata;
private final IBinder myBinder = new MyLocalBinder();
private int data_ready = 0;
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return myBinder;
}
public int onStartCommand (Intent intent, int flags, int startId){
Log.i("New Tag","Service Called");
senSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
senAccelerometer = senSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
senSensorManager.registerListener(this, senAccelerometer , SensorManager.SENSOR_DELAY_NORMAL);
return START_STICKY;
}
public Complex[][] getData() {
if (data_ready == 0){
Log.i("New Tag","getStatus Called, Data not ready");
return null;
}else {
Log.i("New Tag","getStatus Called, Data is ready");
alldata[0] = xdata;
alldata[1] = ydata;
alldata[2] = zdata;
data_ready = 0;
data_index = 0;
return alldata;
}
}
public class MyLocalBinder extends Binder {
BoundService getService() {
return BoundService.this;
}
}
public int getStatus(){
Log.i("New Tag","getStatus Called");
return data_ready;
}
public void onSensorChanged(SensorEvent sensorEvent) {
long nowTime = System.currentTimeMillis();
if ((nowTime - lastUpdate) > 100){
lastUpdate = nowTime;
Sensor mySensor = sensorEvent.sensor;
if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER) {
float x = sensorEvent.values[0];
float y = sensorEvent.values[1];
float z = sensorEvent.values[2];
if (data_index < FFT_SIZE) {
xdata[data_index] = new Complex(x);
ydata[data_index] = new Complex(y);
zdata[data_index] = new Complex(z);
data_index++;
Log.i("New Tag","Data not Ready");
}
else if (data_index == FFT_SIZE)
{
data_ready = 1;
Log.i("New Tag","Data is Ready");
Toast.makeText(getApplicationContext(), "Data Reading Complete", Toast.LENGTH_SHORT).show();
}
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
运行此代码时,程序崩溃。当我跟踪标签时,它们会在显示后停止:
06-28 15:16:14.632 28418-28441/adameve.relsa D/OpenGLRenderer﹕ endAllStagingAnimators on 0xb49b8b00 (RippleDrawable) with handle 0xaec2cfe0
06-28 15:16:20.921 28418-28418/adameve.relsa I/New Tag﹕ Graph Activity Created
06-28 15:16:20.929 28418-28418/adameve.relsa I/New Tag﹕ Service Bound
06-28 15:16:20.929 28418-28418/adameve.relsa I/New Tag﹕ Graph Activity Started
06-28 15:16:20.929 28418-28418/adameve.relsa I/New Tag﹕ Entered While Loop
06-28 15:16:20.930 28418-28418/adameve.relsa D/AndroidRuntime﹕ Shutting down VM
06-28 15:16:20.932 28418-28418/adameve.relsa E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: adameve.relsa, PID: 28418
java.lang.RuntimeException: Unable to start activity ComponentInfo{adameve.relsa/adameve.relsa.GraphActivity1}: java.lang.NullPointerException: Attempt to invoke virtual method 'int adameve.relsa.BoundService.getStatus()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2325)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
at android.app.ActivityThread.access$800(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int adameve.relsa.BoundService.getStatus()' on a null object reference
at adameve.relsa.GraphActivity1.onStart(GraphActivity1.java:107)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1236)
at android.app.Activity.performStart(Activity.java:6006)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2288)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
at android.app.ActivityThread.access$800(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
非常感谢您的帮助。
此致
答案 0 :(得分:1)
guide for Bound Services解释了对bindService()
的调用立即返回,但实际绑定是异步发生的。在您的活动收到onServiceConnected()
回调之前,该服务无法使用。您的活动在bindService()
中致电onCreate()
。然后它会在myService.getStatus()
中调用onStart()
。这是在绑定完成并且已调用onServiceConnected()
之前发生的,因此myService
为空,并且您获得异常。
您需要重新构建代码,以便在服务绑定完成之前不启动图创建处理。
还需要进行另一项更改。您无法将图表处理放在onStart()
中的无限循环中。无法在主线程上执行长时间运行的处理。它会干扰其他UI处理,并在几秒钟后导致“应用程序无响应”失败。