【问题标题】:Android: Viewpager, thread and orientation changeAndroid:Viewpager、线程和方向更改
【发布时间】:2014-05-29 02:29:27
【问题描述】:

我对 Android 编程还是很陌生,现在正在努力改变屏幕方向。

我正在使用带有 FragmentPagerAdapter 的 viewPager,如 Android Developers 中所述,以显示两个通过选项卡访问的片段。

在 Fragment1 中,当按下按钮时会启动一个新线程。该线程计算数据并不断更新 UI(使用 UI 线程)。当再次按下按钮时,标志设置为 false,停止线程。当滑动到 Fragment2 或按下 home 键时,线程继续运行。当按下后退按钮时,活动和片段被破坏,线程也是如此(我认为?)。那将是预期的行为。

我想了解当屏幕改变方向时会发生什么。如果它正在运行,碎片和我的线程会发生什么?您能否指向一个链接,解释我应该如何在方向更改后继续保持线程运行和更新 UI?

编辑:我找到了一种获得我想要的行为的方法(如下所述)。不过,我仍然不确定幕后究竟发生了什么。

我只需要把这一行放在片段构造函数中:

savedInstanceState(true);

使用此行,屏幕旋转后 UI 仍会更新。由于按钮文本在激活时会发生变化,所以我还不得不在片段onCreateView() 方法中添加这样的内容:

if(flag) {
    mStartButton.setText();
}

这些问题对我有帮助:

编辑 2: 以下是关于我的代码的一些附加信息。在我的片段OnCreateView() 中,我有一个简单按钮的监听器:

// Start-Stop button listener
mStartButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (!mIsRunning) { // START
            // New thread
            Thread myThread = new Thread(new Runnable() {
                public void run() {
                    runFunction();
                }
            });
            myThread.start();

            mIsRunning = true;
            mStartButton.setText(getString(R.string.stop));
        }
        else { // STOP
            mIsRunning = false;
            mStartButton.setText(getString(R.string.start));
        }
    }
});

runFunction() 的定义如下:

private void runFunction() {
    while(mIsRunning) {
        // Do something
    }
}

【问题讨论】:

标签: android multithreading android-fragments


【解决方案1】:

处理线程中断

我建议像这样更改onClickrunFunction()source):

// in fragments oncreate
myThread = new Thread(new Runnable() {
    public void run() {
        runFunction();
    }
});

// Start-Stop button listener
mStartButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (!mIsRunning) { // START
            myThread.start();
            mStartButton.setText(getString(R.string.stop));
        } else { // STOP
            myThread.interrupt();
            mStartButton.setText(getString(R.string.start));
        }
        mIsRunning = !mIsRunning
    }
});

runFunction() 的定义如下:

private void runFunction() {
    while(!Thread.currentThread().isInterrupted()) {
        // Do something
    }
}

保证线程会在您单击按钮后立即停止。 gui 线程和myThread 之间存在竞争条件。在您的版本中,假设您单击了按钮并发生了上下文切换。您的线程在第 1 行被激活

while(mIsRunning) {

并且布尔值被检查为真。发生上下文切换,gui 线程生成值false。上下文切换再发生一次,线程继续运行而不检查布尔值。它仅在单次迭代后停止。这种情况可能很少见,您不必担心这个问题。

处理方向变化

当你改变方向时,onSaveInstanceState 被调用。在这里您可以保存重新创建活动后要使用的变量。

public void onSaveInstanceState(Bundle savedState) {
    super.onSaveInstanceState(savedState);
    savedState.putBool("mIsRunning", mIsRunning);
}

方向改变后再次调用onCreate

public void onCreate (Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    myThread = new Thread(new Runnable() {
        public void run() {
            runFunction();
        }
    });

    if (savedInstanceState != null) {
        mIsRunning = savedInstanceState.getBool("mIsRunning");
        if (mIsRunning) {
           myThread.start();
           mStartButton.setText(getString(R.string.stop));
        }
    }
    ...
}

【讨论】:

  • 非常感谢您的回答!如果我理解正确,使用 Thread.interrupt() 将做与我的标志相同的事情,但以“更清洁”的方式。关于方向变化,使用您建议的方法与使用savedInstanceState(true); 的优点(和/或缺点)是什么?
  • 你是对的。在这两种情况下都将出现竞争条件。你的意思是setRetainState(true)?如果是这样,请参阅this 评论和回答。我没有太多关于这方面的信息。对不起:/
  • savedInstanceState(true) 确实是我目前正在使用的。关于这个功能,我会做更多的阅读。再次感谢您的帮助!
猜你喜欢
  • 2011-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多