2017-10-09 388 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