从服务中收集加速度计数据 运行

Collecting Accelerometer Data from Service running

这就是我想要做的。我有一个 activity 需要处理一些加速度计数据。所以我创建了一个扩展 "Service" 并实现 "SensorEventListener"

的服务

这是我的 activity:

的代码
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.access0(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.access0(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)

非常感谢您的提前帮助。

此致

guide for Bound Services 解释说立即调用 bindService() returns,但实际绑定是异步发生的。在您的 activity 收到 onServiceConnected() 回调之前,该服务不可用。您的 activity 在 onCreate() 中调用了 bindService()。然后它在 onStart() 中调用 myService.getStatus()。这是在绑定完成并且调用 onServiceConnected() 之前发生的,因此 myService 为 null,您会得到异常。

您需要重组代码,以便在服务绑定完成之前不启动图形创建处理。

还需要进行另一项更改。您不能在 onStart() 中将图形处理置于无休止的 while 循环中。 Long 运行 处理不能在主线程上进行。它会干扰其他 UI 处理,并会在几秒后导致 "Application Not Responding" 失败。