如何做一个编码良好的闪屏

时间:2013-08-13 20:44:54

标签: java android android-asynctask splash-screen

我们都知道有很多关于如何在Android上进行启动画面的教程。但我们也知道那些是伪启动画面。我搜索了很多,我总是看到Thread.sleep(x)。这不是很好的编码,这只是为了使应用程序美观,看起来像一个专业的应用程序,这不是我想要的!
这些启动画面的另一个问题是它们无法解决我的问题,因为它们只在活动开始后显示 并显示内容视图。

我有一个应用程序在初始化时执行很多操作,当应用程序启动时,用户会看到黑屏几秒钟,有足够的时间来烦恼。 所以这就是为什么我想要显示一个编码良好的启动画面,删除在设置内容视图之前出现的黑屏。

我试了一下。我将启动画面(RelativeLayout)包含在MainActivity中设置的布局中,但据我所知,Android只会在加载完所有内容后显示内容,所以如果我正在尝试要从内容视图中显示一些视图,我必须等到一切都完成。不过,我会发送我的代码,它可以帮助某种程度......

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    new SplashTask().execute();
}

private class SplashTask extends AsyncTask<Void, Void, Void> {

    @Override
    protected void onPreExecute() {
        initializeViews();
        mSplashScreen.setVisibility(View.VISIBLE);
    }

    @Override
    protected Void doInBackground(Void... params) {
        return null;
    }

    @Override
    protected void onPostExecute(Void params) {
        Standard.Initiate(MainActivity.this);
        verifyListStats();
        loadListAdapters();
        setOnClickListeners();
        mSplashScreen.setVisibility(View.GONE); 
    }

}

我尝试在doInBackground(...)中加载一些资源但是因为我在onResume()中执行了一些需要这些资源的操作,我无法做到(或者至少我认为我做不到)。 / p>

有什么想法吗?我听说过类似于iOS发布图像的内置机制,也许这可能是一种方式。

8 个答案:

答案 0 :(得分:5)

当一项活动启动时,Android会启动Zygote,这是一项无效的空活动,并在其上设置您的活动主题,然后启动它。一旦您的活动准备好显示,它就会将显示的活动交换给您的活动。有关Zygote的更多信息,您可以阅读Cyril Motier的this article

所以要回答你的问题,你可以这样做:

  1. 创建一个小主题,其中显示您的初始信息的自定义窗口背景(您可以使用9补丁中心未缩放的内容);
  2. 在您的清单中,将此启动主题用于您的活动;
  3. 在你的活动的onCreate()方法中,调用setTheme(R.id.yourActivityTheme)(在setContentView()之前调用它);
  4. 享受......
  5. 这样,在您的活动准备好显示之前,您的“启动画面”(即:具有您的启动主题的合子)将一直可见。

答案 1 :(得分:3)

编辑:这是一个很棒的启动画面教程,您希望启动画面显示一段时间,或者进行一些处理。它也提供了几种方法的优点/缺点。

http://blogactivity.wordpress.com/2012/02/24/writing-splash-screens-the-right-way/

答案 2 :(得分:2)

创建一个SplashScreen活动,并在您的应用中将其声明为默认值,即将其添加到您的AndroidManifest.xml

  <activity
        android:name="package.SplashScreen"
        android:icon="@drawable/icon"
        android:label="@string/app_name"
        android:noHistory="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity>

在你的SplashActivity onCreate中启动一个新的AsyncTask:

public class SplashScreen extends Activity {

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

      new InitAsyncTask().execute();
   }

   private class InitAsyncTask extends AsyncTask<?, ?, ?> {

      protected ? doInBackground(?... params) {
         // PERFORM YOUR INITIALIZATION HERE
      }

      protected void onPostExecute(? result) {
          // Initialization is completed, close SplashScreen 
          // and launch your MainActivity:
          SplashScreen.this.finish();
          startActivity(new Intent(MainActivity.class, SplashScreen.this);

     }
   }
}

答案 3 :(得分:0)

我通过创建一个全屏启动对话框然后在我完成加载时关闭它来完成此操作

splashDialog = new Dialog(getActivity(), android.R.style.Theme_Black_NoTitleBar_Fullscreen);
        splashDialog.setContentView(R.layout.yourSplashLayout);

答案 4 :(得分:0)

打开启动画面的最佳方法是你可以为它创建一个新的活动,然后在该活动中你可以设置一个计时器来打开一个新的活动,这将是你的主要活动。我想使用这个你可以摆脱它在启动时从黑屏中移出。在清单中将启动活动作为默认启动活动。这是示例: -

SplashActivity.java

public class SplashActivity extends Activity {

private Timer timer;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.layout_splash_activity);
}

@Override
protected void onResume() {

    timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    Intent intialScreenIntent = new Intent(SplashActivity.this, MainActivity.class);
                    startActivity(intialScreenIntent);
                }
            }, 2000l);
            super.onResume();       
}


@Override
public void onBackPressed() {
    try {
        timer.cancel();
        timer = null;
    } catch (Exception e) {
    }
    super.onBackPressed();
}}

答案 5 :(得分:0)

我也在寻找同样的东西。最后,我实现了这个满足我的要求。

注意:

  • 在创建第二项活动时,请做好所有繁重的工作。因此,当所有工作完成后,活动会在onStart()被调用后自动启动。
  • 如果您希望某些代码在应用程序生命周期中仅运行一次,则可以在onCreate()中放置一些检查。
  • 不要在ApplicationClass onCreate()方法中做繁重的工作,因为它在应用程序启动时执行。因此在执行期间会出现黑屏。

这是启动画面xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="@drawable/splash_screen"
  tools:context=".SplashScreenActivity">
</RelativeLayout>

这是活动类

公共类SplashScreenActivity扩展了Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_splash_screen);
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            Intent mainIntent = new Intent(SplashScreenActivity.this,
                    MyLauncherActivity.class);
            SplashScreenActivity.this.startActivity(mainIntent);
                         // SplashScreenActivity.this.finish(); No need to finish it as "noHistory" tag is true in the manifest
        }
    }, 1500);

}

@Override
public void onBackPressed() {
}
}

清单中的条目:

 <activity
        android:name="com.wokomoco.test.activities.SplashScreenActivity"
        android:label="@string/app_name"
        android:noHistory="true"
        android:screenOrientation="portrait" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
 </activity>

希望这会帮助你。 享受编码!!

答案 6 :(得分:0)

我的一个非许可项目即使没有必要也需要启动画面。也许它对您的项目很有用,因为它基于对话而不是活动。如果点击或手势处理启动画面,它将被解除以及完成动画(定时淡出)后。可以对类进行修改,以便在允许点击或手势解除图像之前检查某种“就绪状态布尔值”。

类文件:AppIntro.java

import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;

public class AppIntro extends Dialog {
    protected int mLayoutRes = 0;
    protected int mAnimRes = 0;
    protected Animation mIntroAnim = null;
    protected View mLayout = null;

    public AppIntro(Context aContext, int aLayoutRes, int aAnimRes) {
        super(aContext);
        mLayoutRes = aLayoutRes;
        mAnimRes = aAnimRes;
    }

    @Override
    protected void onCreate(Bundle aSavedState) {
        super.onCreate(aSavedState);
        mLayout = LayoutInflater.from(getContext()).inflate(mLayoutRes,null);
        mLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                AppIntro.this.dismiss();
            }
        });
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(mLayout);
        mIntroAnim = AnimationUtils.loadAnimation(getContext(),mAnimRes);
        mIntroAnim.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {
                //nothing to do
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                //nothing to do
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                AppIntro.this.dismiss();
            }
        });
    }

    @Override
    public boolean onGenericMotionEvent(MotionEvent event) {
        dismiss();
        return true;
    }

    @Override
    public void show() {
        super.show();
        mLayout.startAnimation(mIntroAnim);
    }

}

接下来,我们在文件“res / anim / intro_anim.xml”中定义我们的动画淡出(将持续时间更改为加载应用程序所需的时间)。 4200 = 4.2秒。

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" 
    >
    <alpha 
        android:fromAlpha="1.0" android:toAlpha="0.0" 
        android:interpolator="@android:anim/accelerate_interpolator" 
        android:duration="4200" 
        android:repeatCount="0" >
    </alpha>
</set>

最后,我们在“layout / intro.xml”中定义我们的初始屏幕布局(使用您想要的任何图像)。我特别的启动画面显示了带有图像的应用程序标题以及来自各种资金来源的3个徽标。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layout_intro"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/intro_Text_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:gravity="center"
        android:text="@string/title_intro"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <ImageView
        android:id="@+id/intro_Image_myproject"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/intro_Text_title"
        android:layout_centerHorizontal="true"
        android:src="@drawable/intro_image" />

    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/intro_Image_myproject" 
        android:layout_alignRight="@id/intro_Image_myproject" 
        android:layout_alignLeft="@id/intro_Image_myproject">

        <ImageView
            android:id="@+id/intro_Image_logo1"
            android:layout_width="80dp"
            android:layout_height="50dp"
            android:scaleType="fitXY"
            android:src="@drawable/logo1" 
            android:layout_gravity="left|center_vertical"/>

        <ImageView
            android:id="@+id/intro_Image_logo2"
            android:layout_width="150dp"
            android:layout_height="wrap_content"
            android:src="@drawable/logo2" 
            android:layout_gravity="center" 
            android:scaleType="centerInside"/>

        <ImageView
            android:id="@+id/intro_Image_logo3"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:scaleType="fitXY"
            android:src="@drawable/logo3" 
            android:layout_gravity="right|center_vertical"/>

    </FrameLayout>

</RelativeLayout>

用于弹出对话框的代码:

@Override
protected void onCreate(Bundle aSavedState) {
    super.onCreate(aSavedState);
    if (aSavedState==null) {
        //only show splash screen at app start, not on rotate screen
        new AppIntro(this,R.layout.intro,R.anim.intro_anim).show();
    }
    setContentView(R.layout.main);
    //...rest of onCreate() 
}

我的应用程序在启动画面的同时显示了我的主视图,因此无法保证在您调用.show()时此对话框会立即显示。

答案 7 :(得分:0)

以下是我在所有项目中使用的启动画面活动。请检查它是否对您有帮助。

public class SplashActivity extends Activity {

    private SharedPreferences myPrefs;
    private SharedPreferences.Editor prefsEditor;
    private boolean login;
    private boolean connectivityState;
    private String connectedNetworkType;
    private ConnectivityManager connectivityManager;
    private CheckInternet checkInternet;
    private File file = new File(API.file_dir);
    public static Location loc;
    Configuration newConfig;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.splash_layout);



        //----------------------
        myPrefs = getSharedPreferences("myPrefs", MODE_WORLD_READABLE);
        boolean login = myPrefs.getBoolean("login", false); 

            checkForInternetAndNextFlow();
    }


    // Check for the Internet Connection
    private void checkForInternetAndNextFlow() {

        connectivityManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
        checkInternet = new CheckInternet(getApplicationContext());
        connectivityState = checkInternet.isConnected(connectivityManager);

        if (connectivityState) {
            connectedNetworkType = checkInternet.getNetworkType();
            // Toast.makeText(getApplicationContext(), "Connected via : " +
            // connectedNetworkType, Toast.LENGTH_LONG).show();

            // check for the login or not from preference
            myPrefs = this.getSharedPreferences("myPrefs", MODE_WORLD_READABLE);
            login = myPrefs.getBoolean("login", false);

            System.out.println("Loging value is:" + login);
            Thread t = new Thread() {
                public void run() {
                    try {
                        Thread.sleep(1500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        if (login) {
                            Intent i = new Intent(SplashActivity.this,MainTabActivity.class);
                            startActivity(i);
                        } else {
                            Intent i = new Intent(SplashActivity.this,LoginActivity.class);
                            startActivity(i);
                        }
                    }
                }
            };
            t.start();

        } else {
            // Toast.makeText(getApplicationContext(), "NOT connected",
            // Toast.LENGTH_LONG).show();
            final Dialog dialog = new Dialog(SplashActivity.this,R.style.CustomDialogTheme);
            dialog.getWindow();
            dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
            dialog.setContentView(R.layout.internet_dialog);
            dialog.setCancelable(false);

            Button retryBtn = (Button) dialog.findViewById(R.id.retryBtn);
            Button cancel = (Button) dialog.findViewById(R.id.cancelBtn);

            retryBtn.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View arg0) {
                    dialog.dismiss();
                    checkForInternetAndNextFlow();
                }
            });

            cancel.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View arg0) {
                    dialog.dismiss();
                    finish();
                }
            });
            dialog.show();
        }

    }


}

希望它会对你有所帮助。 享受编码...... :)