【问题标题】:Thread is started twice线程启动两次
【发布时间】:2017-05-16 13:30:32
【问题描述】:

我的 onCreate 方法有问题。我已经确定,当我切换到此活动时,onCreate 方法会被调用两次,因此会启动 2 个我不想要的线程。因为线程将坐标发送到 RaspberryPi,而第二个不需要的线程总是发送我不想要的 0 0 0。我似乎无法找到解决此问题的方法。 . .如果有人能告诉我一个修复程序以便线程只启动一次,我将不胜感激。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

        Joystick = (ImageView) findViewById(R.id.Joystick);
        Regler = (ImageView) findViewById(R.id.Regler);
        buttonFoto = (Button) findViewById(R.id.buttonFoto);
        buttonVideo = (Button) findViewById(R.id.buttonVideo);
        buttonNeu = (Button) findViewById(R.id.buttonNeu);
        buttonSpeichern = (Button) findViewById(R.id.buttonSpeichern);

        touchscreenJoystick = (TextView) findViewById(R.id.touchscreenJoystick);
        touchscreenJoystick.setOnTouchListener(this);
        touchscreenRegler = (TextView) findViewById(R.id.touchscreenRegler);
        touchscreenRegler.setOnTouchListener(this);

        RL = (RelativeLayout) findViewById(R.id.activity_main);
        running = true;
        firstTouch = true;

        Bild = (WebView) findViewById(R.id.webView);
        Bild.loadUrl("http://10.0.0.1:8080/stream");

        thread = new Thread(new MainActivity.TransmitThread());
        thread.start();
    }

编辑: 我尝试了 SaveInstanceState

    //Same onCreate-stuff as above
    if(savedInstanceState == null)
    {
        thread = new Thread(new MainActivity.TransmitThread());
        thread.start();
    }

}

@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putString("message","crashed");
    super.onSaveInstanceState(outState);
}

这很奇怪。现在我只有一个线程在发送一次坐标后立即崩溃。

日志:

发送前我放的Log.i:

I/sent: //X: 0 //Y: 0 //Z: 0

紧随其后的日志

I/System: core_booster, getBoosterConfig = false

编辑 2:

我也尝试过在其他时间启动线程。在我的 onTouch 中是这样的:

public boolean onTouch(View v, MotionEvent me)
{
    xt = me.getX();
    yt = me.getY();
    int Aktion = me.getAction();

    if(firstTouch)
    {

        thread = new Thread(new MainActivity.TransmitThread());
        thread.start();

        firstTouch = false;
    }
    //other stuff that i need to do here
}

但这与我尝试使用 SaveInstanceState 的结果相同,这是一个传输一次但不循环的线程。

编辑 3: 我可能也应该发布我的帖子

class TransmitThread implements Runnable
{
    @Override
    public void run()
    {
        while(running)
        {
            delay();       
            xss = xs;       
            yss = ys;
            zss = zs;
            Log.i("sent","//X: " + xss + " //Y: " + yss + " //Z: " + zss);
            transmit();     
        }
    }

    public void transmit()
    {
        try{
            socket = new Socket(ServerIP,ServerPort);   

            OutputStream outputStream = socket.getOutputStream();
            PrintStream printStream = new PrintStream(outputStream);

            BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            printStream.print(xs + " " + ys + " " + zs);
            Akkustand = input.readLine();

            handler.sendEmptyMessage(0);

        }catch(UnknownHostException e){
            e.printStackTrace();
        }catch(IOException e){
            e.printStackTrace();
        }
    }

    public void delay(){
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

最终编辑:

我设法解决了问题。我在发送之前检查该值是否为 0,如果是,则将其更改为 200。另一方面,我检查其是否为 200 并将其更改为 0,并忽略我得到的任何 0。

【问题讨论】:

  • 使用布尔标志
  • @Slimestone 尝试调试您的代码并找到它。这很简单。您甚至可以检查该变量是否包含 0 并在发送之前避免它。
  • 你最终可以使用thread.isAlive() docs.oracle.com/javase/7/docs/api/java/lang/…,但你必须检查thread != null
  • 启动时使用易失字段,使其为真。启动前请检查布尔标志

标签: java android


【解决方案1】:

首先,在 Activity 的每个生命周期中,OnCreate 只会被调用一次。但是,有许多情况可能会导致您的活动被终止并恢复活力。因此,再次调用 OnCreate。

首先你可以调试代码并找到它重复调用的地方。

注意:为避免这种情况,您可以将状态信息保存在 onSaveInstanceState 中,然后将其恢复到您在创建时进入的状态包中。

谢谢

【讨论】:

  • 你错了 - onCreate 应该被调用一次,但在其中创建线程使其再次被调用 - stackoverflow.com/a/22224038/4810277
  • 好的,我同意你的信息。我只是告诉 Activity 生命周期。我们可以多次调用同一个活动。但是我们需要自己调试多次调用。
【解决方案2】:

OnCreate() 已经创建了一个主线程,然后你通过手动创建主类的线程来调用主类的另一个实例。

【讨论】:

    【解决方案3】:

    根据this回答所有你不需要布尔检查,只需检查savedInstance是否为null,然后才启动第二个线程。

    更通用的解决方案是在 onStart() 中初始化并启动线程,但不要忘记在 onStop() 中停止它。如果你希望这个线程在后台长时间运行-我建议开始使用其他东西-Service docs

    【讨论】:

      【解决方案4】:

      任何配置更改都会导致Android重启你的Activity,比如屏幕旋转、键盘可用性等。系统实际做的是调用onDestroy()然后立即调用onCreate(),这意味着原来的Activity对象被替换为new 一个不知道正在执行的后台线程,所以只有启动线程的 Activity 对象才知道线程已经启动。

      更好的处理方法是在 Activity 中保留线程。

      Activity 类包含两种处理线程保留的方法:

      public Object onRetainNonConfigurationInstance()
      

      在配置更改发生之前调用

      public Object getLastNonConfigurationInstance()
      

      在新的Activity对象中调用,获取onRetainNonConfigurationInstance()返回的保留对象

      所以你可以通过以下方式实现。

      private static MyThread t;
      
          @Override
          public void onCreate(Bundle savedInstanceState) {
              Object retainedObject = getLastNonConfigurationInstance();
              if (retainedObject != null) {
                  t = (MyThread) retainedObject;
              }
              else{
                  t = new MyThread();
                  t.start();
              }
          }
      
          @Override
          public Object onRetainNonConfigurationInstance() {
              if (t != null && t.isAlive()) {
                  return t;
              }
              return null;
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-29
        • 1970-01-01
        • 2017-04-18
        • 1970-01-01
        • 2019-06-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多