2015-06-28 34 views
2

以下是我正在嘗試的操作。我有一個需要處理一些加速度計數據的活動。所以我創建的延伸「服務」和實現「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

程序崩潰時發生了什麼異常?如果它發生在除代碼之外的其他地方,你可能不得不把它混淆在logcat過濾器中。 – trooper

+0

我剛剛用完整的logcat編輯了這篇文章。 – Mohamed

回答

1

guide for Bound Services解釋說,立即bindService()回報通話,但實際結合異步發生。在您的活動收到onServiceConnected()回叫之前,該服務無法使用。您的活動在onCreate()中呼叫bindService()。然後在onStart()中調用myService.getStatus()。這在綁定完成之前發生並且onServiceConnected()已被調用,因此myService爲空,並且您會得到異常。

您需要重構代碼,以便在服務綁定完成之前不啓動圖形創建處理。

還有一個需要改變。您不能將圖形處理放在onStart()的無盡循環中。長時間運行的處理無法在主線程上執行。它會干擾其他UI處理,幾秒鐘後會導致「應用程序未響應」失敗。

+0

好吧,我根據您的建議修改了代碼,但線程部分除外。我添加了while循環來檢查服務是否綁定。當我運行代碼時,它一直給我提供服務綁定仍在進行中的標籤,直到應用程序凍結。綁定服務需要多長時間? – Mohamed

+0

綁定通常在不到一秒的時間內完成。 –

+0

那麼,爲什麼在我的情況下永遠需要。我在其他地方讀過,除非onCreate和onStart先完成運行,否則服務將在ServiceConnected上運行。這是真的 ? – Mohamed