在UI线程中使用while循环而不在睡眠中睡眠

时间:2013-09-21 11:56:11

标签: android multithreading while-loop ui-thread

如何在不延迟UIThread的情况下使用while循环中的延迟? 我的while循环应该在每次app运行循环时更新UI,但是也应该有可能与按钮交互。我当前版本的问题是,当while循环启动时,应用程序暂停,直到while循环结束,然后更新UI。我希望它能在每次传递时更新UI。

你有什么想法,也许是另一种更有效的方法吗?

这是我目前的版本:

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Button;
import android.widget.ProgressBar;
import android.view.View.OnClickListener;
import android.widget.Toast;
import java.util.regex.Pattern;


public class ReaderFragment extends Fragment
{

ProgressBar progress_in_main_thread;
private int progressBarStatus = 0;
TextView main_text;
Pattern p = Pattern.compile(" ");
String[] splitted_text;
Button start_button;
Button pause_button;
public boolean paused;
int index = 0;
long wait = 1000;

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
//Layout des Fragments verknuepfen
{
    View ReaderFragmentView = inflater.inflate(R.layout.reader_fgmt, container, false);

    progress_in_main_thread = (ProgressBar) ReaderFragmentView.findViewById(R.id.reader_progress);
    progress_in_main_thread.setProgress(0);
    progress_in_main_thread.setVisibility(progress_in_main_thread.VISIBLE);

    main_text = (TextView) ReaderFragmentView.findViewById(R.id.center_view);

    start_button = (Button) ReaderFragmentView.findViewById(R.id.go);
    start_button.setOnClickListener(new OnClickListener()
    {
       @Override
       public void onClick(View view)
       {
           if(InputFragment.text.trim().length() == 0)
           {
               Toast.makeText(getActivity().getApplicationContext(), "Es wurde kein Text eingegeben!", Toast.LENGTH_SHORT).show();
           }
           else
           {
               paused = false;
               splitted_text = p.split(InputFragment.text);
               progress_in_main_thread.setMax(splitted_text.length-1);

               mainThread();
           }

       }
    });

    pause_button = (Button) ReaderFragmentView.findViewById(R.id.pause);
    pause_button.setOnClickListener(new OnClickListener()
    {
        @Override
        public void onClick(View view)
        {
                paused = true;
        }
    });




    return ReaderFragmentView;
}

private void mainThread()
{
    new Thread(new Runnable()
    {
        @Override
        public void run()
        {
            while(progressBarStatus < (splitted_text.length)-1)
            {
                progressBarStatus = index;

                progress_in_main_thread.setProgress(progressBarStatus);
            }
        }
    }).start();

    getActivity().runOnUiThread(new Runnable()
    {
        public void run()
        {

        while(!paused)
        {
           main_text.setText(splitted_text[index]);

           if(paused)
           {
                break;
           }
           else if(index == (splitted_text.length)-1)
           {
                Toast.makeText(getActivity().getApplicationContext(), "Ende", Toast.LENGTH_LONG).show();
                break;
           }
            index++;
            try
            {
                Thread.sleep(wait);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }

        }

    });
}
}

谢谢大家!

1 个答案:

答案 0 :(得分:1)

根据定义,您不能在不延迟UI线程的情况下延迟UI线程。

从根本上说,您需要从 loop 程序样式切换到事件驱动程序,其中必须处理Android UI。你的程序没有while循环 - 相反,Android框架将调用你的代码来执行事件函数,每个函数都必须尽快返回。

Android已经开箱即用,可以提供用户交互事件,例如触摸和按钮推送以及生命周期事件。要为UI的定期演变添加事件(你试图用while循环和延迟做什么),你可以创建一个Timer并让它的TimerTask使用RunOnUiThread将一些与UI相关的工作推送到UI线程上;如果您需要做的事情不涉及UI,那么您可以在TimerTask执行的后台线程中执行此操作。

在您发布的代码中,您可能尝试创建自己的后台线程,该线程将运行具有睡眠延迟的循环,并使用RunOnUiThread将工作推送到UI线程;技术上这是可行的,但与计时器方法相比并没有真正鼓励。但是,你这样做有两个问题:

  • 首先,你为后台线程mainThread命名了启动器方法,这有点令人困惑,因为在Android上“主线程”和“UI线程”是同一个 - 最好是调用它createBackgroundThread()或其他东西。

  • 其次,你有时间和睡眠发生在它推送到UI线程执行的代码中,这是行不通的。您将需要移动while循环并睡眠到后台线程,而是在需要将UI线程小批量工作推送到UI线程时重复使用RunOnUiThread,例如每次实际的可视化更新。

此外,您可能需要考虑一下,如果您的实现最终会因重复按钮推送而导致创建多个并发后台线程,或者您的某个线程在发生重大活动生命周期事件时仍在运行。