Создайте настоящий заставку

Как я могу сделать реальный заставку в Android? Я не хочу таймеров или задержек. Просто заставка, отображаемая до загрузки приложения.

Solutions Collecting From Web of "Создайте настоящий заставку"

Что-то вроде

public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.splash); handler = new Handler(); new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { //Do some heavy stuff return null; } @Override public void onPostExecute(Void result){ handler.post(new Runnable(){ @Override public void run(){ setContentView(R.layout.main); } }); } }.execute(); } 

Ниже приводится решение с кодом, которое, похоже, работает безупречно на нескольких тестовых устройствах в течение последних шести недель.

Тем не менее, есть несколько предварительных условий, которые следует рассмотреть, прежде чем погрузиться в полный экран заставки.

Прежде всего, если вы можете избежать необходимости в заставке, сразу создав основной вид приложения, предоставив пользователю немедленный доступ к вашему приложению, это ваш самый лучший вариант.

Вы можете часто выполнять это, сразу же создавая графику своего основного дисплея, а затем создавая рабочий поток для выполнения любых трудоемких задач инициализации, таких как загрузка таблицы, которая всегда используется приложением.

Однако может показаться, что графика вашего основного представления занимает много времени, чтобы настроить и отобразить, и вы хотите, чтобы во время этой инициализации было видно что-то еще.

Теперь, если ваш основной вид активности имеет простой (например, по умолчанию), легкий или черный, непрозрачный фон, который обеспечит немедленное подтверждение того, что по крайней мере что-то происходит, когда пользователь запускает ваше приложение. Фоновые темы, которые я лично нашел в качестве примитивных «всплесков», включают следующее (для добавления в тег активности вашего основного действия в вашем файле манифеста):

 android:theme="@style/Theme.Light.NoTitleBar" android:theme="@style/Theme.Black.NoTitleBar" 

В этом отношении я хотел бы отметить, что если для фона вашей деятельности требуется какой-либо растровый рисунок или анимация или другое значение, выходящее за пределы темы по умолчанию (или простая светлая или черная тема, как показано выше), мой опыт в том, что фон активности не отображается Пока ваше основное представление не будет отображаться в любом случае, и поэтому просто изменение фона вашей деятельности для себя будет вашим всплесковым дисплеем, который (по моему опыту) не выполняет более немедленный ответ, чем ваш основной экран уже предоставляет.

Хотя вышеуказанные простые темы будут работать как примитивные «всплески», возможно, вы считаете, что простой светлый или черный фон активности слишком неописуемый, что ваше приложение запустилось, и вы хотите что-то, что показывает имя или логотип вашего приложения, в то время как Пользователь ждет. Или, может быть, ваш фокус активности должен быть прозрачным , потому что вы хотите, чтобы иметь возможность накладывать какое-то другое приложение на свои собственные приложения (такой прозрачный фон, конечно же, невидим во время запуска, и поэтому не будет сигнализировать пользователю о том, что ваше приложение Был запущен).

Если, рассмотрев все альтернативы, представленные выше, вы по-прежнему считаете, что вам нужен заставку, вот такой подход, который я лично нашел для работы очень хорошо.

Для этого подхода вам нужно будет определить новый класс, который расширяет LinearLayout. Причина, по которой вам нужен ваш собственный класс, заключается в том, что вам нужно получить положительное подтверждение того, что ваш экран заставки фактически отобразился, поэтому вы можете сразу перейти к отображению основного вида без какого-либо тайма таймера, который может только догадываться, сколько времени потребуется Ваш экран заставки появится. В этой связи я хотел бы отметить, что если вы сразу же начнете показывать свой основной вид после отображения своего всплеска, всплывающее представление никогда не будет видно; Использование этого подхода позволяет избежать этой возможности.

Вот пример такого класса:

 public class SplashView extends LinearLayout { public interface SplashEvents { //This event is signaled after the splash and all of its child views, // if any, have been drawn. // As currently implemented, it will trigger BEFORE any scrollbars are drawn. // We are assuming that there will BE no scrollbars on a SplashView. public void onSplashDrawComplete(); } private SplashEvents splashEventHandler = null; public void setSplashEventHandler(SplashEvents splashEventHandler) { this.splashEventHandler = splashEventHandler; } private void fireSplashDrawCompleteEvent() { if(this.splashEventHandler != null) { this.splashEventHandler.onSplashDrawComplete(); } } public SplashView(Context context) { super(context); //This is set by default for a LinearLayout, but just making sure! this.setWillNotDraw(true); //If the cache is not enabled, then I think that helps to ensure that // dispatchDraw override WILL // get called. Because if caching were enabled, then the //drawing might not occur. this.setDrawingCacheEnabled(false); setGravity(Gravity.CENTER); //This splices in your XML definition (see below) to the SplashView layout LayoutInflater.from(context).inflate(R.layout.splashscreen, this, true); } @Override protected void dispatchDraw(Canvas canvas) { //Draw any child views super.dispatchDraw(canvas); //Signal client objects (in this case, your main activity) that // we have finished initializing and drawing the view. fireSplashDrawCompleteEvent(); } } 

Поскольку мы загружаем наш XML из представления, нам нужно определить его в XML, используя <merge> для «сращивания» в элементах, определяемых XML, как дети нашего класса SplashView. Вот пример (для размещения в папке res / layout вашего приложения), который вы можете адаптировать к своим собственным потребностям:

 <merge xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center_horizontal" > <TextView android:id="@+id/tvHeading" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" android:textSize="30dp" android:textStyle="bold" android:text="Loading..." android:layout_weight="1.0" android:textColor="#00ff00" android:background="#AA000000" /> </merge> 

Обратите внимание, что TextView определен с полупрозрачным черным фоном, так что это приведет к уменьшению отображения панели запуска, при этом текст «Загрузка …» накладывается сверху зеленым цветом.

Остается только отредактировать что-то вроде следующего (и выше) метода onCreate () вашего основного вида деятельности:

 private Handler uiThreadHandler = new Handler(); @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); //Create an instance of the splash view, and perform a setContentView() SplashView splashView = new SplashView(this); //Doing this allows you to access the "this" pointer of the main // activity inside the Runnable below. final main mainThis = this; // Set an event handler on the SplashView object, so that as soon // as it completes drawing we are // informed. In response to that cue, we will *then* put up the main view, // replacing the content view of the main activity with that main view. splashView.setSplashEventHandler(new SplashView.SplashEvents() { @Override public void onSplashDrawComplete() { //Post the runnable that will put up the main view uiThreadHandler.post(new Runnable() { @Override public void run() { //This method is where you will have moved // the entire initialization of your app's // main display, which normally would have been // in your onCreate() method prior to adding the // splash display. launchMainView(mainThis, savedInstanceState); } }); } }); //This will cause your splash view to draw. When it finishes, it will trigger the code above. this.setContentView(splashView); //At this point, do *not* move directly on to performing a setContentView() on your main view. // If you do, you will never see the splash view at all. // You simply wait for the splash view to signal you that it has completed drawing itself, and // *then* call launchMainView(), which will itself call setContentView() again, passing it // your main view. } //Here is a stripped-down version of launchMainView(). You will typically have some additional // initializations here - whatever might have been present originally in your onCreate() method. public void launchMainView(main mainThis, Bundle savedInstanceState) { myRootView = new MyRootView(mainThis); setContentView(myRootView); } 

Этот подход работает для меня очень хорошо. Я использовал его только для уровня API 8 и тестировал этот код на разных устройствах, включая как телефоны, так и планшеты, работающие под управлением Android 2.2.1, 2.3.3 и 4.0.1 (ICS).

Предостережение:

Потенциальная ответственность вышеупомянутого подхода заключается в том, что при некоторых сочетаниях обстоятельств брызговое представление может не сигнализировать о том, что оно завершено, и поэтому всплеск будет «застревать» на главном дисплее без основного вида для его замены , Это никогда не случалось со мной, но я хотел бы получить комментарии здесь относительно того, может ли переопределить dispatchDraw () в SplashView выше, возможно, когда-либо не будет вызван. Я выполнил визуальный осмотр кода, который запускает dispatchDraw (), и он выглядит так, как будто он всегда будет вызван, учитывая инициализации, которые я сделал в конструкторе SplashView.

Если у кого-то есть лучший способ переопределить для этой же цели, я бы хотел услышать об этом. Я был удивлен тем, что не смог найти какой-либо переопределенный вариант, специально предназначенный для стрельбы, когда представление закончило отображение, и поэтому, если он существует, и я как-то пропустил его, отправьте комментарий ниже. Комментарии, подтверждающие, что этот подход будет работать, также очень приветствуются!

Это не так сложно; Вы просто создаете представление, которое вы будете использовать в качестве своего заставки (тот, который имеет простой макет и не требует большого количества измерений), установите его как контент для активности с помощью setContentView;

Затем снова вызовите setContentView в действии со сложной компоновкой, которая требует времени для сборки. Вы можете даже использовать Asynctask для загрузки данных, прежде чем вы вызовите setContent во второй раз с помощью сложной компоновки. Это зависит от того, насколько вы связаны с загрузкой или просмотром здания.

 public class MyLocationListener extends Activity { public Handler myHandler = new Handler(){ public void handlerMessage(Message msg){ set you contentView here after splash screen } } public MyLocationListener(Context context){ this.context = context; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.splashscreen); // don't set Content View here instead start a thread here to do the task yiou want to do. // Now post message from new thread to UI Thread using handlers. } } 

Лучший способ сделать заставку:

  1. Если пользователь нажимает назад, вам нужно быстро перейти на главный экран.
  2. Нет анимации.

Я пришел в это хорошее решение:

 import android.app.Activity; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.view.WindowManager; import br.eti.fml.android.sigame.R; import java.util.concurrent.atomic.AtomicBoolean; public class LauncherActivity extends Activity { private AsyncTask goingToNextScreen; private AtomicBoolean alreadyShown = new AtomicBoolean(false); public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.launcher); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); //noinspection unchecked goingToNextScreen = new AsyncTask() { @Override protected Object doInBackground(Object... objects) { try { Thread.sleep(1500); } catch (InterruptedException e) { // ignores } return null; } @Override protected void onPostExecute(Object o) { goNext(); } }.execute(); } @Override public void onBackPressed() { if (goingToNextScreen != null) { goingToNextScreen.cancel(true); goNext(); } } private void goNext() { if (alreadyShown.compareAndSet(false, true)) { startActivity(new Intent(LauncherActivity.this, HomeActivity.class)); overridePendingTransition(0, 0); finish(); overridePendingTransition(0, 0); } } } 

Когда-нибудь, используя всплеск, для загрузки содержимого Activity потребуется несколько миллисекунд или секунду.

Если вам нужен только «обратный образ», как обычный экран заставки. Я думаю, что лучший способ – использовать Темы.

Использование SherlockActionBar, например:

 <style name="SplashTheme" parent="Theme.Sherlock.NoActionBar"> ... <item name="android:windowBackground">@drawable/splash</item> ... </style> 

Где splash может быть файлом .9 для заполнения экрана.

И деятельность в манифесте должна быть чем-то вроде

  <activity android:name=".SplashActivity" ... android:theme="@style/SplashTheme" ...> ... </activity> 

То вам не нужна строка setContent (View) в вашем коде. И тема будет загружена быстрее, чем содержимое.

Это позволяет вам иметь заставку с начала загрузки приложения. Без черных окон или actionBars или что-то в этом роде.

// код для кода Splash

 public class SplashScreen extends Activity { static int SPLASH_TIMEOUT = 5000; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.splash_layout); new Handler().postDelayed(new Runnable() { @Override public void run() { startActivity(new Intent(SplashScreen.this, MainActivity.class)); finish(); } }, SPLASH_TIMEOUT); } } 

Здесь SPLASH_TIMEOUT будет определять после того, как будет отображаться ваша собственная деятельность, поэтому измените это значение в соответствии с вашими потребностями.

// код для MainActivity.class

 public class MainActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }