92

我试着这样做

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

    setContentView(R.layout.main);

    t=new TextView(this); 

    t=(TextView)findViewById(R.id.TextView01); 
    t.setText("Step One: blast egg");

    try {
        Thread.sleep(10000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    t.setText("Step Two: fry egg");

但由于某种原因,当我运行它时,只显示第二个文本。我认为这可能与Thread.sleep()方法阻塞有关。那么有人可以告诉我如何“异步”实现计时器吗?

谢谢。

4

8 回答 8

145

你的onCreate()方法有几个巨大的缺陷:

1)onCreate 准备您的活动 - 因此在此方法完成之前,您在此处所做的任何事情都不会对用户可见!例如 - 您将永远无法在TextView此处更改 a 的文本超过一次,因为只有最后一次更改将被绘制并且因此对用户可见!

2) 请记住,Android 程序将 - 默认情况下 - 仅在一个线程中运行!因此:永远不要在负责 UI 的主线程中使用Thread.sleep()or !Thread.wait()(阅读“让您的应用程序响应”了解更多信息!)

您对 Activity 的初始化是:

  • 无缘无故地创建一个新TextView对象t
  • 你稍后TextView在变量中选择你的布局。t
  • 您设置的文本t(但请记住:它只会 onCreate()完成后显示并且应用程序的主事件循环运行!)
  • 您在您的方法中等待10 秒-绝对不能这样做,因为它会停止所有 UI 活动并且肯定会强制 ANR(应用程序无响应,请参见上面的链接!)onCreate
  • 然后你设置另一个文本 - 一旦你的onCreate()方法完成并且其他几个Activity 生命周期方法已经被处理,这个文本就会显示出来!

解决方案:

  1. 只设置一次文本onCreate()- 这必须是第一个应该可见的文本。

  2. 创建一个Runnable和一个Handler

    private final Runnable mUpdateUITimerTask = new Runnable() {
        public void run() {
            // do whatever you want to change here, like:
            t.setText("Second text to display!");
        }
    };
    private final Handler mHandler = new Handler();
    
  3. 将此可运行文件安装为处理程序,可能在onCreate()(但请阅读下面的我的建议):

    // run the mUpdateUITimerTask's run() method in 10 seconds from now
    mHandler.postDelayed(mUpdateUITimerTask, 10 * 1000);
    

建议:确保你知道一个Activity的生命周期!如果你在onCreate()这只会在你Activity一次创建时发生这样的事情!即使它不可见, Android 也可能让您的生命更长久!当用户再次“启动”它时——它仍然存在——你将不再看到你的第一个文本!Activity


=> 始终在!中安装处理程序onResume()并禁用它们 onPause()否则,当您Activity根本不可见时,您将获得“更新”!在您的情况下,如果您想在重新激活时再次看到您的第一条文本,则必须将其设置为onResume(),而不是onCreate()

于 2010-02-24T12:18:27.700 回答
46

我刚刚在 android-discuss google 组中发布了这个答案

如果您只是想在视图中添加文本以使其显示“第一步:炸鸡蛋第二步:煎鸡蛋”然后考虑使用t.appendText("Step Two: fry egg"); 而不是t.setText("Step Two: fry egg");

如果您想完全更改其中的内容,TextView以便在启动时显示“第一步:炸鸡蛋”,然后一次显示“第二步:煎鸡蛋”,您可以随时使用

sadboy 给出的可运行示例

祝你好运

于 2010-02-20T06:17:32.783 回答
15

新文本视图的第一行是不必要的

t=new TextView(this); 

你可以这样做

TextView t = (TextView)findViewById(R.id.TextView01);

至于在这里休眠的后台线程就是一个例子,但我认为有一个计时器会更好。这是一个使用计时器的好例子的链接 http://android-developers.blogspot.com/2007/11/stitch-in-time.html

    Thread thr = new Thread(mTask);
    thr.start();
}

Runnable mTask = new Runnable() {
    public void run() {
        // just sleep for 30 seconds.
                    try {
                        Thread.sleep(3000);
                        runOnUiThread(done);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
        }
    };

    Runnable done = new Runnable() {
        public void run() {
                   // t.setText("done");
            }
        };
于 2010-02-19T23:01:08.960 回答
6

@user264892

我发现在使用字符串变量时,我需要使用字符串“”作为前缀或显式转换为 CharSequence。

所以而不是:

String Status = "Asking Server...";
txtStatus.setText(Status);

尝试:

String Status = "Asking Server...";
txtStatus.setText((CharSequence) Status);

或者:

String Status = "Asking Server...";    
txtStatus.setText("" + Status);

或者,由于您的字符串不是动态的,因此更好:

txtStatus.setText("AskingServer...");
于 2011-08-20T15:02:35.043 回答
3

根据您的建议,我正在使用句柄和可运行文件使用“计时器”切换/更改 TextView 的内容。由于某种原因,应用程序在运行时总是跳过第二步(“第二步:煎鸡蛋”),只显示最后(第三)步(“第三步:上菜”)。

TextView t; 
private String sText;

private Handler mHandler = new Handler();

private Runnable mWaitRunnable = new Runnable() {
    public void run() {
        t.setText(sText);
    }
};

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

    setContentView(R.layout.main);

    mMonster = BitmapFactory.decodeResource(getResources(),
            R.drawable.monster1);

    t=new TextView(this); 
    t=(TextView)findViewById(R.id.TextView01); 

    sText = "Step One: unpack egg";
    t.setText(sText);

    sText = "Step Two: fry egg";        
    mHandler.postDelayed(mWaitRunnable, 3000);

    sText = "Step three: serve egg";
    mHandler.postDelayed(mWaitRunnable, 4000);      
    ...
}
于 2010-02-23T05:50:35.497 回答
0

:) 您以错误的方式使用线程。只需执行以下操作:

private void runthread()
{

splashTread = new Thread() {
            @Override
            public void run() {
                try {
                    synchronized(this){

                        //wait 5 sec
                        wait(_splashTime);
                    }

                } catch(InterruptedException e) {}
                finally {
                    //call the handler to set the text
                }
            }
        };

        splashTread.start(); 
}

就是这样。

于 2012-10-03T18:29:35.877 回答
0

将文本两次设置为 sam textview 会覆盖第一个书面文本。因此,当我们第二次使用 settext 时,我们只需附加新字符串,例如

textview.append("Step Two: fry egg");
于 2014-05-05T06:04:23.193 回答
0

@Zordid @Iambda 答案很好,但我发现如果我把

mHandler.postDelayed(mUpdateUITimerTask, 10 * 1000);

在 run() 方法和

mHandler.postDelayed(mUpdateUITimerTask, 0);

在 onCreate 方法中使事物不断更新。

于 2015-04-13T22:09:51.400 回答