【问题标题】:Android Studio - Starting and Stopping a Loop With a Button PressAndroid Studio - 按下按钮启动和停止循环
【发布时间】:2018-03-20 03:14:03
【问题描述】:

我是使用 Android Studio 的新手,目前正在编写一个应用,该应用利用手机中的传感器来控制另一台设备。我搜索并没有找到太多可以帮助我解决问题的东西。最终我需要通过网络传输从传感器获得的数据,但我离那个点还很远,所以改天再说吧。

现在,该应用可以访问传感器并将其显示在手机屏幕上。每次按下屏幕按钮都会更新读数。我想要它做的是,一旦我按下按钮一次,随着手机的移动不断实时更新值。如果再次按下按钮,我希望它停止。以下是我在主要活动中的当前代码。我试图做的是使用一个整数,每次按下按钮时我都会切换它并在其中一个值上运行一个 do while 循环。当 do while 循环在那里时,它不会做任何事情。如果我把它拿出来,它会像每次按下按钮时更新值一样运行。我还在传感器值旁边显示“切换”的值,并且当 do while 循环不存在时它正在切换。我不明白为什么 do while 循环根本不会运行。我也尝试使用布尔值并在真假之间切换,但我得到了相同的结果。我也意识到 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());
        }
    }
}

}

【问题讨论】:

  • 您是否遇到任何错误?
  • 我认为您的问题不在于 while 循环本身,而在于您如何使用它。我猜你在等待结果的同时不停地做,对吗?并且您是否在运行 for 循环时遇到 UI 中的冻结时刻,并且真的感觉什么都没有发生?
  • 杰斯是对的。您在循环期间阻塞了您的 ui。您需要在后台线程中运行循环。
  • 我已经编辑了我的答案以简化代码的工作方式。现在我只是跟踪迭代次数并将该信息发布到 txt1 TextView。这应该让您更好地了解正在发生的事情以及如何中断线程。
  • 我认为您的问题更多地与设备SensorSensorManager 的有效实现有关,而不是线程。我建议您就该主题提出一个新问题 - 我认为您会得到更好的回应和更明智的答案。

标签: java android loops


【解决方案1】:

当我使用处理程序线程处理长时间任务时,我发现它很有帮助,处理程序线程是 androids 处理长时间运行任务的官方方式。这里是官方链接 有关如何使用处理程序线程的更多信息。

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

【讨论】:

  • HandlerThread 基本上只是 java 的 Thread 类的包装器。使用任何你觉得舒服的东西。
  • handler thread 是一个包装器,是的,但它提供的东西很漂亮,我宁愿使用官方的方法而不是实现我自己的线程,因为你永远不知道他可能会将代码传递给谁接下来,如果他不是自己从事该项目,则最好使用官方方式。但每一个他自己。处理程序线程还有助于防止其使用的进程发生内存泄漏。
【解决方案2】:

将您的传感器读数放在后台线程中。这只是一个例子。根据需要进行修改!

在您的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() 上重新启动它。

【讨论】:

  • Barns52 感谢您提供的信息。你所说的使用后台线程是有道理的,但我在设置它时有点迷失了。我已经采用了您的示例代码并修改了我的代码以包含它。我在解决变量时遇到了一些问题,我确定我在这里错过了一些基本的东西。自从我编写任何代码以来已经有一段时间了,正如我之前所说,我是 Android Studio 的新手。我一直在尝试发布我的最新代码。如果不使用“回答您的问题”链接,我怎么能做到这一点,或者这是唯一的方法?
  • 答案底部应该有一个“编辑”链接。使用它来发布对您的问题或代码的任何更改。
  • 我刚刚添加了更新的代码。我对公共 void run() 类(mRotationMatrix、mvaluesAccel,所有这些)中的变量有错误。我需要将主要活动的值传递给它,我假设使用某种 setter/getter 方法?我不知道该怎么做。我正在翻阅我拥有的一本旧 Java 书籍,但代码示例比我这里的要简单得多,而且我很难将其应用于此。
  • 我没有使用过SensorManager 类,所以我真的没有任何实现它的经验。但是我的解决方案回答了您提出的“启动和停止循环......”的问题。我将不得不看一下 Sensor 类。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-14
  • 1970-01-01
  • 1970-01-01
  • 2021-03-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多