2017-10-09 205 views
1

我是使用Android Studio的新手,目前正在編寫一個應用程序,該應用程序使用手機中的傳感器來控制其他設備。我搜索了,但沒有找到太多可以幫助我解決我的問題。最終我需要通過網絡傳輸從傳感器獲得的數據,但我還沒有接近那個點,所以這是另一天。Android Studio - 使用按鈕開始和停止循環按

此時,應用程序可以訪問傳感器並將其顯示在手機屏幕上。每次按下屏幕上的按鈕,它都會更新讀數。我想要做的事情是,只要按一次按鈕,隨着手機的移動,不斷更新實時值。如果再次按下該按鈕,我希望它停止。以下是我目前在主要活動中的代碼。我試圖做的是使用一個整數,每次按下按鈕時都會切換,並在其中一個值上運行do while循環。當while循環在那裏時,它不會做任何事情。如果我把它拿出來,就像它每次按下按鈕時更新值一樣運行。我還在傳感器值旁邊顯示「切換」的值,並在do while循環不在時切換。我不明白爲什麼while循環不會運行。我也嘗試過使用布爾值並在true和false之間切換,但我得到了相同的結果。我也意識到do while循環的設置方式可能無法停止,但我會認爲它至少會進入循環並保持運行,至少讓我開始運行。

import android.support.v7.app.AppCompatActivity; 
    import android.os.Bundle; 
    import android.app.Activity; 
    import android.hardware.Sensor; 
    import android.hardware.SensorEvent; 
    import android.hardware.SensorEventListener; 
    import android.hardware.SensorManager; 
    import android.widget.TextView; 
    import android.widget.Button; 
    import android.view.View; 





    public class MainActivity extends AppCompatActivity 
    { 
MySensorUpdateThread mySensorUpdateThread = null; 

@Override 

public void onCreate(Bundle savedInstanceState) 
{ 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    mySensorUpdateThread = new MySensorUpdateThread(this); 

    SensorManager sensorManager = (SensorManager) this.getSystemService(SENSOR_SERVICE); 

    final float[] mValuesMagnet = new float[3]; 
    final float[] mValuesAccel = new float[3]; 
    final float[] mValuesOrientation = new float[3]; 
    final float[] mRotationMatrix = new float[9]; 

    final Button btn_valider = (Button) findViewById(R.id.btn1); 
    final TextView txt1 = (TextView) findViewById(R.id.textView1); 
    final SensorEventListener mEventListener = new SensorEventListener() { 
     public void onAccuracyChanged(Sensor sensor, int accuracy) { 
     } 

     public void onSensorChanged(SensorEvent event) { 
      switch (event.sensor.getType()) { 
       case Sensor.TYPE_ACCELEROMETER: 
        System.arraycopy(event.values, 0, mValuesAccel, 0, 3); 
        break; 

       case Sensor.TYPE_MAGNETIC_FIELD: 
        System.arraycopy(event.values, 0, mValuesMagnet, 0, 3); 
        break; 
      } 
     } 
     ; 
    }; 

    setListners(sensorManager, mEventListener); 

    btn_valider.setOnClickListener(new View.OnClickListener() 
     { 

     public void onClick(View view) 
     { 
      mySensorUpdateThread.toggleThread(); 
      if (mySensorUpdateThread.isRunning()) 
      { 
       mySensorUpdateThread.start(); 
      } 
     } 

     }); 
} 

public void setListners(SensorManager sensorManager, SensorEventListener mEventListener) 
{ 
    sensorManager.registerListener(mEventListener, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), 
      SensorManager.SENSOR_DELAY_NORMAL); 
    sensorManager.registerListener(mEventListener, sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), 
      SensorManager.SENSOR_DELAY_NORMAL); 
} 

public class MySensorUpdateThread extends Thread 
{ 
    private boolean keepRunning = false; 
    private String sensorResults = ""; 


    private MainActivity mActivity; 

    public MySensorUpdateThread(MainActivity activity) 
    { 
     this.mActivity = activity; 
    } 
    public void toggleThread() 
    { 
     this.keepRunning = !this.keepRunning; 
    } 

    public boolean isRunning() 
    { 
     return this.keepRunning; 
    } 

    public String getSensorResults() 
    { 
     return this.sensorResults; 
    } 

    @Override 
    public void run() 
    { 

     int i = 0; 
     int maxIterations = 100; 
     try{ 
      while(this.keepRunning) 
      { 
       // This keeps the thread from going on too long in case 
       if(i > maxIterations) 
       { 
        this.keepRunning = false; 
        break; 
       } 

       // This causes the thread to rest for 50ms to 
       // slow things down 

       try 
       { 
        Thread.sleep(50); 
       } 
       catch(InterruptedException e) 
       { 
       } 
       SensorManager.getRotationMatrix(mRotationMatrix, null, mValuesAccel, mValuesMagnet); 
       SensorManager.getOrientation(mRotationMatrix, mValuesOrientation); 

       sensorResults = "Roll/Pitch (degrees): " + /*mValuesOrientation[0]*(180/Math.PI) + " "+ "," + " " +*/ 
         mValuesOrientation[1] * (180/Math.PI) + " " + "/" + " " + 
         mValuesOrientation[2] * (-180/Math.PI); 

       // Now post the results to the UI Thread 
       runOnUiThread(new Runnable(){ 
        @Override 
        public void run(){ 
         txt1.setText(getSensorResults()); 
        } 
       }); 
      } 
     } 
     catch() 
     { 
      Log.e(TAG, ex.getMessage()); 
     } 
    } 
} 

}

+0

您是否收到任何錯誤? – Barns

+0

我認爲你的問題不在於循環本身,而在於你如何使用它。我想你在等待結果的同時不停地做,是嗎?並且在運行for循環時,您是否遇到了用戶界面中的凍結時刻,並且字面上感覺沒有任何反應? – jace

+1

傑斯是對的。你在循環中阻止你的用戶界面。你需要在後臺線程中運行循環。 – Barns

回答

0

把你的傳感器在後臺線程讀取。這只是一個例子。根據需要進行修改!

在你Activity類,你需要設置你的後臺線程對象:

MySensorUpdateThread mySensorUpdateThread = null; 

你們的活動onCreate()方法通過增加初始化後臺線程:

mySensorUpdateThread = new MySensorUpdateThread(); 

在你onClick()方法開始,阻止你後臺線程:

public void onClick(View view){ 
    mySensorUpdateThread.toggleThread(); 
    if(mySensorUpdateThread.isRunning()){ 
     mySensorUpdateThread.start(); 
    } 
}); 

現在,這裏是後臺線程的代碼:

public class MySensorUpdateThread extends Thread{ 
    SensorManager sensorManager = null; 
    private boolean keepRunning = false; 
    private String sensorResults = ""; 

    public void toggleThread(){ 
     this.keepRunning = !this.keepRunning; 
    } 

    public void isRunning(){ 
     return this.keepRunning; 
    } 

    public String getSensorResults(){ 
     return this.sensorResults; 
    } 

    @Override 
    public void run(){ 
     if(sensorManager == null){ 
      sensorManager = (SensorManager) this.getSystemService(SENSOR_SERVICE); 
     } 

     int i = 0; 
     int maxIterations = 100; 
     String mess = ""; 
     try{ 
      while(this.keepRunning){ 
       mess = "Number of iterations: " + i; 
       Log.e(TAG, mess); 
       // This keeps the thread from going on too long in case 
       if(i > maxIterations){ 
        this.keepRunning = false; 
        break; 
       } 

       // This causes your thread to rest for 500ms it might be a 
       // good idea to slow things down a bit -- just a suggestion 
       Thread.sleep(500); 


       // Get your sensor data here and set it to the 
       // local variable to be posted to the UI Thread 
       //this.sensorResults = sensorString; 


       // Now post the results to the UI Thread 
       runOnUiThread(new Runnable(){ 
        @Override 
        public void run(){ 
         txt1.setText(getSensorResults()); 
        } 
       } 

      } 
     } 
     catch(){ 
      Log.e(TAG, ex.getMessage()); 
     } 
    } 

} 

你可能會想停在活動onPause()方法後臺線程,並可能重新啓動它onResume()

+0

穀倉52感謝您的信息。這是有道理的,你說什麼關於使用後臺線程,但我設置了一些有點失落。我已經採取了您的示例代碼並修改了我的代碼以包含該代碼。我在解決變量時遇到了一些問題,我相信我在這裏錯過了一些基本的東西。自從我寫了任何代碼之後已經有一段時間了,正如我之前說的,我是Android Studio的新手。我一直試圖發佈我的最新代碼。我怎麼能做到這一點,而不使用「回答你的問題」鏈接,或者是唯一的方法來做到這一點? – thecause17

+0

應該有一個「編輯」鏈接朝着你的底部回答。使用它來發布對您的任何更改問題或代碼。 – Barns

+0

我剛剛添加了更新的代碼。我有public void run()類中的變量錯誤(mRotationMatrix,mvaluesAccel,所有這些)。我需要將主要活動中的值傳遞給它,我假定用某種setter/getter方法?我不知道該怎麼做。我正在瀏覽一本舊的Java書,但代碼示例比我在這裏要簡單得多,而且我很難將其應用於此。 – thecause17

0

我發現它很有幫助,當我使用處理線程處理長時間任務時,處理線程是androids官方處理長時間運行任務的方式。有關如何使用處理程序線程的更多信息,請參閱官方鏈接 。

https://developer.android.com/reference/android/os/HandlerThread.html

+0

HandlerThread基本上只是java的Thread類的包裝。使用任何你感到舒服的東西。 – Barns

+0

處理程序線程是一個包裝是的,但它提供的東西很漂亮,我寧願使用官方的方法,而不是實現我自己的線程,因爲你永遠不知道他可能將代碼傳遞給下一個,如果他不工作在他自己的項目上,他最好使用官方的方式。但每一個他自己。處理程序線程還有助於防止它使用的進程泄漏內存。 – sdfbhg