安卓:启动画面为何未显示?

5

我正在学习Android技术。从我目前阅读的文档中,我无法弄清如何显示启动画面(在休眠期间屏幕保持空白)。看起来我需要为主布局启动一个新的活动,但这似乎很浪费(启动画面应该永远消失,我想重用它的线程)。

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class Ext3 extends Activity {

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.splash);

        Log.v("Ext3", "starting to sleep");

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

        Log.v("Ext3", "done sleeping");

        setContentView (R.layout.main);
    }

}
4个回答

7
我认为你的启动画面从未显示,因为你只是在那里睡觉,没有给UI线程(你所在的线程)绘制它的机会。
与其使用Thread.sleep,我建议你考虑使用计时器或类似的东西来安排刷新和更改视图内容;另一种选择是启动一个异步任务,在更改视图之前可以像现在一样休眠。
不要阻塞UI线程,这很糟糕...(会导致ANR)。

1
请参考http://www.anddev.org/simple_splash_screen-t811.html以获取实现此功能的示例。 - levis501
所以显然我的信念,在调用函数和它返回其工作之间完成,是错误的。这严重质疑了我所拥有的机器模型。显然线程比我的代码做得更多。这些操作是什么,何时发生? - kasterma
1
@kasterma - 这在 Activity docs 的Activity Lifecycle部分和Activities guide的Managing the Activity Lifecycle部分中有详细描述。 - Ted Hopp
所以在UI线程中,工作是由其他代码完成的,我的代码只是将一些变量设置为正确的值。我已经阅读了Activity生命周期,但并没有理解其重要性。 - kasterma
你是正确的,UI线程是执行所有绘制、布局等操作的线程...其中一部分是调用你的活动来设置所有这些组件。如果你阻塞它(睡眠或等待某些东西),那么你就会冻结你的用户界面,使你的应用程序无响应。 - Matthieu

1
当您像这样调用sleep时,您正在阻塞UI线程。相反,将第二次调用setContentView放在一个Runnable中,创建一个Handler,并使用Handler的postDelayed方法来运行Runnable。类似这样:
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.splash);
    Runnable endSplash = new Runnable() {
        @Override
        public void run() {
            setContentView (R.layout.main);
        }
    }
    new Handler().postDelayed(endSplash, 5000L);
}

请看我在@Matthieu的回答中的评论,我期望在UI线程中的睡眠会阻止任何进一步的交互。但是我已经设置了布局;根据我的心理模型,我不应该再阻止任何东西了。 - kasterma
1
设置布局不会自动导致屏幕呈现。这是在onCreate返回后执行的框架内代码。由于您直到更改内容视图才返回,因此启动画面从未有机会显示。整个应用程序的用户界面在睡眠期间被阻塞。 - Ted Hopp

1

我已经在我的应用程序中尝试了这段代码,它完美地工作。或许它也能帮助到你。

public class SplashScreen extends Activity {

    /**
     * The thread to process splash screen events
     */
    private Thread mSplashThread;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Splash screen view
        setContentView(R.layout.splash);



        final SplashScreen sPlashScreen = this;

        // The thread to wait for splash screen events
        mSplashThread = new Thread() {
            @Override
            public void run() {
                try {
                    synchronized (this) {
                        // Wait given period of time or exit on touch
                        wait(5000);
                    }
                } catch (InterruptedException ex) {
                }

                finish();

                // Run next activity
                Intent intent = new Intent();
                intent.setClass(sPlashScreen, MainActivity.class);
                startActivity(intent);
                stop();
            }
        };

        mSplashThread.start();

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        return false;
    }

    /**
     * Processes splash screen touch events
     */
    @Override
    public boolean onTouchEvent(MotionEvent evt) {
        if (evt.getAction() == MotionEvent.ACTION_DOWN) {
            synchronized (mSplashThread) {
                mSplashThread.notifyAll();
            }
        }
        return true;
    }

}

启动一个新的活动肯定比启动一个新的线程更费力。 - kasterma
@kasterma - 不一定。这种方法有很多值得称赞的地方。首先,它将闪屏界面与主活动分开。但是,它的主要问题在于,我认为闪屏界面的主要目的是进行耗时的初始化,否则主视图无法立即显示出来。在单独的闪屏活动中进行初始化意味着必须将初始化数据传输到主活动中。 (顺便说一句,在线程的run()方法中调用已弃用的stop()方法是错误的;我不知道人们为什么要这样做。) - Ted Hopp

0
这是一个基本启动画面的代码片段。
public class Splash extends Activity {

//private ProgressDialog pd = null;
private final int SPLASH_DISPLAY_LENGTH = 3000; 

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.splashscreen);
    //this.pd = ProgressDialog.show(this, "Initializing..", "Initializing Infraline...", true, false);

    /* New Handler to start the InfralineTabWidget-Activity
     * and close this Splash-Screen after some seconds.*/

    new Handler().postDelayed(new Runnable(){
        @Override
        public void run() {
        /* Create an Intent that will start the InfralineTabWidget-Activity. */
            Intent mainIntent = new Intent(Splash.this,InfralineTabWidget.class);
            Splash.this.startActivity(mainIntent);
            Splash.this.finish();
        }
    }, SPLASH_DISPLAY_LENGTH);

}

}

在你的 AndroidManifest.xml 文件中添加以下内容:

    <activity android:name=".Splash" android:theme="@android:style/Theme.NoTitleBar" android:configChanges="orientation|keyboardHidden">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

希望这对你有用 :)

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