Bài đăng phổ biến

Thứ Bảy, 3 tháng 11, 2012

Splash Creen trong android

Có rất nhiều ứng dụng, đặc biệt là Game. Khi khởi chạy game thì đầu tiên màn hình hiển thị thông thường là Splash Screen, mà màn hình hiển thị lúc này thường là giới thiệu tác giả hoặc giới thiệu logo của nhà sản xuất...

Bài này tôi sẽ hướng dẫn các bạn cài đặt Splash Screen một cách thật đơn giản, nó hiển thị lúc khởi động và sẽ chạy trong một khoảng thời gian ngắn nào đó.

OK! let's start

1. Create Launcher activity (Đây sẽ là SplashScreen của bạn)
2. Tạo main Activity của bạn (Màn hình chính của game)
3. Cài đặt Splash với một layout chứa 1 progressBar
4. Bắt đầu a Task để load Resource của bạn
5. Gọi lại Plash của bạn mà bạn vừa mới finish();
6. Start yout app
Đầu tiên chúng ta bắt đầu với SplashActivity. Cái này chưa ProgressBar mà biểu diễn ứng dụng của bạn loading.
SplashActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.blundell.tut.ui;
 
import com.blundell.tut.R;
import com.blundell.tut.task.LoadingTask;
import com.blundell.tut.task.LoadingTask.LoadingTaskFinishedListener;
 
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.ProgressBar;
 
public class SplashActivity extends Activity implements LoadingTaskFinishedListener {
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Show the splash screen
        setContentView(R.layout.activity_splash);
        // Find the progress bar
        ProgressBar progressBar = (ProgressBar) findViewById(R.id.activity_splash_progress_bar);
        // Start your loading
        new LoadingTask(progressBar, this).execute("www.google.co.uk"); // Pass in whatever you need a url is just an example we don't use it in this tutorial
    }
 
    // This is the callback for when your async task has finished
    @Override
    public void onTaskFinished() {
        completeSplash();
    }
 
    private void completeSplash(){
        startApp();
        finish(); // Don't forget to finish this Splash Activity so the user can't return to it!
    }
 
    private void startApp() {
        Intent intent = new Intent(SplashActivity.this, MainActivity.class);
        startActivity(intent);
    }
}


Bạn chú ý. Lớp trên cài đặt giao diện LoadingTaskFinishedListener sử dụng giao diện là 1 cách của việc giao tiếp giữa các lớp. Bạn đang nói "Tôi có khả năng nhận về một thông điệp mà trông giống ...this" Bởi vì ASyncTask có 1 trường mà là 1 đối tượng của giao diện đó nó có thể bất chợt phát ra những thông điệp đó và Activity của bạn sẽ nhận được chúng . Tiếp theo là ASyncTask

LoadingTask.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package com.blundell.tut.task;
 
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ProgressBar;
 
public class LoadingTask extends AsyncTask<String, Integer, Integer> {
 
    public interface LoadingTaskFinishedListener {
        void onTaskFinished(); // If you want to pass something back to the listener add a param to this method
    }
 
    // This is the progress bar you want to update while the task is in progress
    private final ProgressBar progressBar;
    // This is the listener that will be told when this task is finished
    private final LoadingTaskFinishedListener finishedListener;
 
    /**
     * A Loading task that will load some resources that are necessary for the app to start
     * @param progressBar - the progress bar you want to update while the task is in progress
     * @param finishedListener - the listener that will be told when this task is finished
     */
    public LoadingTask(ProgressBar progressBar, LoadingTaskFinishedListener finishedListener) {
        this.progressBar = progressBar;
        this.finishedListener = finishedListener;
    }
 
    @Override
    protected Integer doInBackground(String... params) {
        Log.i("Tutorial", "Starting task with url: "+params[0]);
        if(resourcesDontAlreadyExist()){
            downloadResources();
        }
        // Perhaps you want to return something to your post execute
        return 1234;
    }
 
    private boolean resourcesDontAlreadyExist() {
        // Here you would query your app's internal state to see if this download had been performed before
        // Perhaps once checked save this in a shared preference for speed of access next time
        return true; // returning true so we show the splash every time
    }
 
 
    private void downloadResources() {
        // We are just imitating some process thats takes a bit of time (loading of resources / downloading)
        int count = 10;
        for (int i = 0; i < count; i++) {
 
            // Update the progress bar after every step
            int progress = (int) ((i / (float) count) * 100);
            publishProgress(progress);
 
            // Do some long loading things
            try { Thread.sleep(1000); } catch (InterruptedException ignore) {}
        }
    }
 
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        progressBar.setProgress(values[0]); // This is ran on the UI thread so it is ok to update our progress bar ( a UI view ) here
    }
 
    @Override
    protected void onPostExecute(Integer result) {
        super.onPostExecute(result);
        finishedListener.onTaskFinished(); // Tell whoever was listening we have finished
    }
}


LoadingTask là bộ khung của ASyncTask, chúng ta cài đặt 1 callBack trong constructor. sau đó kiểm tra nếu Resources của ta tải về mà tồn tại,......nếu không. Một khi chúng ta tải về kết thúc chúng ta thông báo lại Listener.
Nhiệm vụ này bắt trước.....kiểu như giả loadding Nhưng ở bài này nó không phải là trọng tâm. Bạn nhận thấy mỗi vòng lặp được hoàn tất chúng sẽ update progressbar. Bạn hãy nhớ rằng 1 progressbar là 1 Android View Object. View Object là 1 phần của UI vì vậy có thể update trên UIThread. Vì vậy chúng ta sử dụng onProgressUpdate() method mà android cung cấp chắc chắn chạy trên UIThead.

Khi updating 1 progressbar bạn gửi nó giá trị từ 0-100 và giá trị này sẽ là progressbar của nó. Trong ví dụ này chúng ta chạy qua 1 vòng lặp đếm tới 10 do đó mỗi vòng lặp sẽ là 10% của progressbar.

VD: In AndEngine

  1. public class MainGameActivity extends BaseGameActivity {
  2.         // ===========================================================
  3.         // Final Fields
  4.         // ===========================================================
  5.         // ===========================================================
  6.         // Constants
  7.         // ===========================================================
  8.         private static final int CAMERA_WIDTH = 480;
  9.         private static final int CAMERA_HEIGHT = 800;
  10.         // ===========================================================
  11.         // Fields
  12.         // ===========================================================
  13.         protected Camera mCamera;
  14.         // splash scene
  15.         protected Scene mSplashScene;
  16.         private BitmapTextureAtlas mSplashBackgroundTextureAtlas;
  17.         private TextureRegion mSplashBackgroundTextureRegion;
  18.         // menu scene
  19.         protected Scene mMenuScene;
  20.         // ...
  21.         // ===========================================================
  22.         // Methods for/from SuperClass/Interfaces
  23.         // ===========================================================
  24.         @Override
  25.         public Engine onLoadEngine() {
  26.                 this.mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
  27.                 return new Engine(new EngineOptions(true, ScreenOrientation.PORTRAIT,new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT),this.mCamera).setNeedsSound(true));
  28.         }
  29.         @Override
  30.         public void onLoadResources() {
  31.                 BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
  32.                 mSplashBackgroundTextureAtlas = new BitmapTextureAtlas(512, 1024, TextureOptions.NEAREST);
  33.                 mSplashBackgroundTextureRegion =BitmapTextureAtlasTextureRegionFactory.createFromAsset(mSplashBackgroundTextureAtlas,this"splash.jpg", 0, 0);
  34.                 mEngine.getTextureManager().loadTextures(mSplashBackgroundTextureAtlas);
  35.         }
  36.         @Override
  37.         public Scene onLoadScene() {
  38.                 mSplashScene = new Scene();
  39.                 mSplashScene.setBackgroundEnabled(false);
  40.                 mSplashScene.attachChild(new Sprite(0, 0, mSplashBackgroundTextureRegion));
  41.                 return this.mSplashScene;
  42.         }
  43.        
  44.         @Override
  45.         public void onLoadComplete() {
  46.                 mEngine.registerUpdateHandler(new TimerHandler(0.01f, newITimerCallback() {
  47.                         @Override
  48.                         public void onTimePassed(final TimerHandler pTimerHandler) {
  49.                                 mEngine.unregisterUpdateHandler(pTimerHandler);
  50.                                 loadResources();
  51.                                 loadScenes();
  52.                                 mEngine.setScene(mMenuScene);
  53.                         }
  54.                 }));
  55.         }
  56.         // ===========================================================
  57.         // Methods
  58.         // ===========================================================
  59.         public void loadResources() {
  60.                 // menu resources
  61.                 // help resources
  62.                 // pick level resources
  63.                 // game resources
  64.         }
  65.         public void loadScenes() {
  66.                 // menu scene
  67.                 // help scene
  68.                 // pick level scene
  69.                 // game scene
  70.         }
  71. }

ViDu:

The problem is most likely that you are running the splash screen (some sort of Dialog such asProgressDialog I assume) in the same thread as all the work being done. This will keep the view of the splash screen from being updated, which can keep it from even getting displayed to the screen. You need to display the splash screen, kick off an instance of AsyncTask to go download all your data, then hide the splash screen once the task is complete.
So your Activity's onCreate() method would simply create a ProgressDialog and show it. Then create the AsyncTask and start it. I would make the AsyncTask an inner class of your main Activity, so it can store the data it has downloaded to some variable in your Activity and close the ProgressDialog in its onPostExecute() method.
Not sure how to elaborate anymore without just showing the code, so here it is:

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

Obviously there are some pieces you need to fill in there, but this code should run and give you a good starting point (forgive me if there is a code error, I don't have access to the Android SDK as I'm typing this currently).
Some more good reading on the subject of AsyncTasks in Android can be found here and here.


Hoac:

public class SplashScreen extends Activity{
   @Override
   public void onCreate(Bundle savedInstanceState){
      super.onCreate(savedInstanceState);
      // set the content view for your splash screen you defined in an xml file
      setContentView(R.layout.splashscreen);

      // perform other stuff you need to do

      // execute your xml news feed loader
      new AsyncLoadXMLFeed().execute();

   }

   private class AsyncLoadXMLFeed extends AsyncTask<Void, Void, Void>{
      @Override
      protected void onPreExecute(){
            // show your progress dialog

      }

      @Override
      protected Void doInBackground(Void... voids){
            // load your xml feed asynchronously
      }

      @Override
      protected void onPostExecute(Void params){
            // dismiss your dialog
            // launch your News activity
            Intent intent = new Intent(SplashScreen.this, News.class);
            startActivity(intent);

            // close this activity
            finish();
      }

   }
}

Không có nhận xét nào:

Đăng nhận xét