安卓启动画面

81
我正在开发一个应用程序,在应用程序启动时会下载大量数据并在ListActivity中显示。我的计划是在数据加载完成前显示闪屏界面。
到目前为止,所有的尝试都没有成功。我尝试了anddev.org上提到的方法,但我的问题是主Activity应该启动,但是在填充ListActivity之前应该显示闪屏界面。因此,简单来说,我必须执行以下步骤:
1. 启动主Activity。 2. 显示闪屏界面。 3. 在后台持续运行进程。 4. 当处理完成并显示主List时退出闪屏界面。
希望您明白我的需求。

有人能解释一下为什么即使我在主列表的OnCreate函数中尝试创建和启动进度条,并在我的进程完成后将其关闭,进度条仍然无法加载吗?甚至这个方法也不起作用。我的意思是,是否有任何默认的方法论需要遵循,比如在OnStart()中启动进度条或其他什么? - JaVadid
你试过 https://dev59.com/6nE95IYBdhLWcg3wn_f2 上被接受的答案说的吗?编辑:好的,被接受的答案有点相同。 - noloman
6个回答

89
问题很可能是您在同一个线程上运行启动屏幕(某种Dialog,例如ProgressDialog)和所有工作。这将阻止启动屏幕的视图更新,这可能会使其甚至无法显示到屏幕上。您需要显示启动屏幕,启动AsyncTask实例以下载所有数据,然后在任务完成后隐藏启动屏幕。
因此,您的Activity的onCreate()方法只需创建一个ProgressDialog并显示它。然后创建AsyncTask并启动它。我会将AsyncTask设置为主Activity的内部类,这样它可以将已下载的数据存储到Activity中的某个变量中,并在其onPostExecute()方法中关闭ProgressDialog。
不确定如何进一步详细说明,而不仅仅是展示代码,因此这里是:
public class MyActivity extends Activity {
    private ProgressDialog pd = null;
    private Object data = null;

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

        // Show the ProgressDialog on this thread
        this.pd = ProgressDialog.show(this, "Working..", "Downloading Data...", true, false);

        // Start a new thread that will download all the data
        new DownloadTask().execute("Any parameters my download task needs here");
    }

    private class DownloadTask extends AsyncTask<String, Void, Object> {
         protected Object doInBackground(String... args) {
             Log.i("MyApp", "Background thread starting");

             // This is where you would do all the work of downloading your data

             return "replace this with your data object";
         }

         protected void onPostExecute(Object result) {
             // Pass the result data back to the main activity
             MyActivity.this.data = result;

             if (MyActivity.this.pd != null) {
                 MyActivity.this.pd.dismiss();
             }
         }
    }    
}

显然,你需要填写一些代码,但这段代码应该可以运行并为你提供一个很好的起点(如果有代码错误,请原谅我,因为我目前没有访问Android SDK)。
在Android中,关于AsyncTasks的更多好的阅读材料可以在这里这里找到。

你说的“用数据对象替换”是什么意思?我有两个函数想要像你说的那样在异步任务中加载,但我不知道应该返回什么。我试着返回null,但应用程序崩溃了。 - Nick
这可能有点老了,但我已经尝试实现它了,ProgressDialog(在我的情况下是加载布局的常规对话框)从未显示。只有当我在onPostExecute中注释掉.dismiss()时才能看到它。我看到的第一个屏幕仍然是MyActivity主题。之后直接进入R.layout.main - Kevin_TA
@Kevin_TA 如果 .dismiss() 导致它无法显示,则您的 AsyncTask 立即结束。我概述的方法是为了显示一个启动画面,该画面在运行某些长时间启动任务时显示。 - Mark B
@mbaird 它不会立即结束。我确实有一个后台进程需要2-3秒钟才能完成。但出于某种原因,UI上的任何内容在异步完成之前都不会更新,从而失去了意义。 - Kevin_TA
@Kevin_TA,.dismiss() 调用立即关闭它,而 .dismiss() 调用发生在 onPostExecute() 中,这告诉我您没有将后台进程作为 AsyncTask 运行。您需要确保 doInBackground() 方法在后台进程完成之前不返回。 - Mark B
显示剩余2条评论

62

只是为了参考,这是我发现的制作闪屏界面的最佳方法:http://android-developers.blogspot.de/2009/03/window-backgrounds-ui-speed.html

我搜索了一段时间才从Android文档中找到了这个方法...如果你想避免那些黑屏,你需要创建一个带有windowBackground的主题,如下:

<resources>
    <style name="Theme.Shelves" parent="android:Theme">
        <item name="android:windowBackground">@drawable/background_shelf</item>
        <item name="android:windowNoTitle">true</item>
    </style>
</resources>

将此主题设置为您的主活动的主题...... TADA,在第一秒中出现闪屏。

如果您想要一个复杂的背景而不仅仅是一个会被拉伸以填充的图像,您可以使用Drawable。下面是一个layer-list的例子,它将保持标志居中并带有黑色背景:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <item android:drawable="@color/black">
    </item>
    <item>
        <bitmap
            android:gravity="center"
            android:src="@drawable/logo"
            android:tileMode="disabled" >
        </bitmap>
    </item>
</layer-list>

1
这个链接已经失效了,但页面内容和源代码可以在archive.org上找到:http://web.archive.org/web/20101113015720/http://developer.android.com/resources/articles/window-bg-speed.html - Spoonface
1
@Ranaan的主题解决方案对我有用,但是我应该如何将图层列表连接到主题? - deko
2
@deko item name="android:windowBackground" 可以是固定的颜色或图像,也可以是放置在 res/drawable 文件夹中的 xml drawable,例如 layer-list。您可以在此处阅读有关 Drawables 的信息:http://developer.android.com/guide/topics/resources/drawable-resource.html - Raanan
@Ranaan 我试过了,但我的应用程序在启动时崩溃并出现异常:二进制XML文件第18行:<bitmap>需要有效的src属性。 - deko
@Ranaan 你说得对,我确实做了:http://stackoverflow.com/questions/22940232/android-splash-screen-how-to-make-it-centered - deko
显示剩余5条评论

1
  1. 启动主活动。
  2. 显示闪屏界面。
  3. 在后台继续运行进程。
  4. 当处理完成并显示主列表时,退出闪屏界面。

我尝试过这种方式,但问题是:它会在启动闪屏界面活动之前显示主活动。

我这样做:

  1. 启动闪屏界面
  2. 当进程完成时,启动“主活动”
  3. 不要忘记处理返回按钮,因此如果在主活动中按下它将关闭App。否则将回到闪屏界面(循环)

我的问题是如何通过按菜单按钮来禁用“显示闪屏界面活动的菜单”。

编辑:

禁用显示菜单:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // getMenuInflater().inflate(R.menu.activity_main, menu);
    return false;
}

@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {       
    // return super.onMenuItemSelected(featureId, item);
    return false;
}

1
闪屏示例:
public class MainActivity extends Activity {
    private ImageView splashImageView;
    boolean splashloading = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        splashImageView = new ImageView(this);
        splashImageView.setScaleType(ScaleType.FIT_XY);
        splashImageView.setImageResource(R.drawable.ic_launcher);
        setContentView(splashImageView);
        splashloading = true;
        Handler h = new Handler();
        h.postDelayed(new Runnable() {
            public void run() {
                splashloading = false;
                setContentView(R.layout.activity_main);
            }

        }, 3000);

    }

}

0

在编写启动屏幕时,您应该使用 Android 平台的 SplashScreen API,它可以提供自适应图标或 AVD,并控制其可见时间。请查看文档以获取更多信息。

 class MainActivity : Activity() {
    
       override fun onCreate(savedInstanceState: Bundle?) {
           // Handle the splash screen transition.
           val splashScreen = installSplashScreen()
    
           super.onCreate(savedInstanceState)
           setContentView(R.layout.main_activity)

同时创建一个启动页主题,并将其提供在清单文件中

<style name="Theme.App.Starting" parent="Theme.SplashScreen">
   <!-- Set the splash screen background, animated icon, and animation duration. -->
   <item name="windowSplashScreenBackground">@color/...</item>

   <!-- Use windowSplashScreenAnimatedIcon to add either a drawable or an
        animated drawable. One of these is required. -->
   <item name="windowSplashScreenAnimatedIcon">@drawable/...</item>
   <!-- Required for animated icons -->
   <item name="windowSplashScreenAnimationDuration">200</item>

   <!-- Set the theme of the Activity that directly follows your splash screen. -->
   <!-- Required -->
   <item name="postSplashScreenTheme">@style/Theme.App</item>
</style>

在你的清单文件中进行设置:

<manifest>
   <application android:theme="@style/Theme.App.Starting">
    <!-- or -->
        <activity android:theme="@style/Theme.App.Starting">
...

0

我知道这个问题已经很老了,而且提问者可能不再需要它。但我想添加这个答案来帮助那些可能需要实现启动画面的人。

答案(仅适用于Android Oreo或更高版本)


实际上,在Android的新版本(Android Oreo之后),它已经支持内置启动画面实现。这意味着您不需要创建额外的活动来完成此操作。您只需要一个可显示的可绘制资源文件。

使用这种方式可以更快地显示您的启动画面,并在初始化后立即显示内容。但请注意,这仅适用于Android Oreo或更高版本。在以前的版本中,它将显示白色而不是您的启动画面(至少我认为是这样)。

您需要在AppTheme样式中添加此行:

<item name="android:windowSplashscreenContent">@drawable/YOUR_SPLASH_SCREEN_DRAWABLE</item>

这是一个完整的示例:

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->

    <!-- Set your splash screen here, it accept a resource from drawable directory-->
    <item name="android:windowSplashscreenContent" tools:targetApi="o">@drawable/splash_screen</item>
</style>

参考资料


更多关于这个属性的信息,请参考官方文档:https://developer.android.com/reference/android/R.attr#windowSplashscreenContent

如上所述,此属性在API 26中添加。

以下是其中提到的简短摘录:

引用要用作窗口闪屏内容的可绘制对象。此可绘制对象将放置在windowBackground之上,并通过系统栏进行边界插入。如果可绘制对象不应由系统栏插入,请使用全屏主题。

请注意,即使在主题中没有设置闪屏内容,系统仍可能使用主题上的其他属性(例如windowBackground)显示闪屏。


这与您在此处发布的内容完全相同:https://stackoverflow.com/a/65783070/549372 - Martin Zeitler
@Martin Zeitler,我已经删除了那个回答,因为它与那个问题无关。我把它移到这里,这样更相关。 - user12949439

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