如何在Android TextView中更改文本

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()方法阻塞有关。因此,有人可以向我展示如何“异步”实现计时器吗?

谢谢。


2
它只显示第二行的原因是因为.setText()用你设置的文本替换整个“小部件”,包括你已经放置在那里的文本。 - georgiaboy82
8个回答

145

你的onCreate()方法存在几个严重的缺陷:

1)onCreate用于准备你的Activity,因此在此期间进行的任何操作都不会对用户产生影响,直到该方法完成为止!例如 - 你将永远无法在此处更改TextView的文本超过一次,因为只有最后一次更改才会被绘制并对用户可见!

2)请记住,Android程序默认情况下只运行一个线程!因此,永远不要在负责UI的主线程中使用Thread.sleep()Thread.wait()(请阅读“保持应用程序响应”以获取更多信息!)

你的Activity初始化做了以下事情:

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

解决方案:

  1. Set text only once in onCreate() - this must be the first text that should be visible.

  2. Create a Runnable and a 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. install this runnable as a handler, possible in onCreate() (but read my advice below):

    // run the mUpdateUITimerTask's run() method in 10 seconds from now
    mHandler.postDelayed(mUpdateUITimerTask, 10 * 1000);
    
建议:确保您了解Activity的生命周期!如果您在onCreate()中执行此类操作,这仅会在Activity首次创建时发生!即使Activity不可见,Android也可能将其保持活动状态更长时间!
当用户再次“启动”它并且它仍然存在时,您将无法看到您的第一条文本!
=>始终在onResume()中安装处理程序,并在onPause()中禁用它们!否则,您将在Activity完全不可见时收到“更新”!
对于您的情况,如果您想再次查看重新激活时的第一条文本,则必须在onResume()中设置它,而不是在onCreate()中!

46

我刚在android-discuss谷歌小组中发布了这个答案。

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

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

Runnable example sadboy gave

祝好运


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");
            }
        };

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...");

3

根据您的建议,我正在使用handle和runnables来使用“计时器”切换/更改TextView的内容。但是由于某种原因,在运行时,应用程序总是跳过第二个步骤(“Step Two: fry egg”),仅显示最后一个步骤(第三步:“Step three: serve egg”)。

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);      
    ...
}

1
这行不通!只有一个处理程序 - 你如何让唯一存在的mWaitRunnable runner“知道”sText曾经被设置为“第二步”,然后是“第三步”!!? 当它第一次被调用时(3秒后),sText的值只是“第三步”!在尝试Android编程之前,你应该先熟悉基本的Java技能! :-) - Zordid
实际上我最终做的是在可运行对象内添加了一个计数器,如果它是1,文本将是这个,如果它是2,文本将是那个,以此类推。 - user270811

0

@Zordid @Iambda 的回答很好,但我发现如果我放置

mHandler.postDelayed(mUpdateUITimerTask, 10 * 1000);

在run()方法中和

mHandler.postDelayed(mUpdateUITimerTask, 0);

在onCreate方法中使该物件保持更新。

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(); 
}

就是这样。


0

将文本设置两次到同一个TextView会覆盖第一次写入的文本。 因此,第二次使用setText时,我们只需将新字符串附加到原有文本后面即可。

textview.append("Step Two: fry egg");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接