Android 具有网络负载和最短启动显示时间的启动画面
Android Splash Screen with network load and minimum splash display time
我目前在启动画面活动中使用以下结构,以便在指定时间段内显示它:
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
startMainActivity();
}
}, SPLASH_DISPLAY_LENGHT);
然而,我只是创建一个应用程序,它使用 AsyncTask 从网络加载一些信息到它的初始屏幕上,如下所示:
startUpAsyncTask = new StartUpAsyncTask(this);
startUpAsyncTask.execute();
现在我想这样实现处理程序:
- 如果在网络加载期间出现故障,它会停止处理程序以移至 MainActivity。
- 如果网络加载持续时间超过
SPLASH_DISPLAY_LENGHT
activity 等到网络加载在 StartUpAsyncTask
完成,然后转到下一个 activity。
- 如果网络
StartUpAsyncTask
很快结束,启动画面至少显示 SPLASH_DISPLAY_LENGHT
时间长度。
我的问题是如何同步这个AsyncTask和Handler来实现这样的约束。
您可以在启动画面中注册一个 BroadcastReceiver
并注册一个 LocalBroadcastManager
,它将收到来自您的 AsyncTask
的成功消息并设置一个标志。另一个 BroadcastReceiver
将在您的处理程序中注册,以防在 SPLASH_DISPLAY_LENGHT
已经过去时尚未设置标志,并且将在 startMainActivity()
从您的 AsyncTask
收到广播时注册;否则,如果在您的处理程序中完成 SPLASH_DISPLAY_LENGHT
时已经设置了标志,它将直接 startMainActivity()
.
在你的SplashActivity
中:
private class SplashActivity extends Activity {
public static final String ACTION_DATA_LOADING_COMPLETE = "com.example.myapp.ACTION_DATA_LOADING_COMPLETE";
private LocalBroadcastManager localBroadcastManager;
private boolean dataLoadingComplete = false;
@Override
private void onCreate(Bundle savedInstanceState) {
...
localBroadcastManager = LocalBroadcastManager.getInstance(this);
localBroadcastManager .registerBroadcastReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
dataLoadingComplete = true;
}
}, new IntentFilter(ACTION_DATA_LOADING_COMPLETE));
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
localBroadcastManager.registerBroadcastReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
startMainActivity();
}
}, new IntentFilter(ACTION_DATA_LOADING_COMPLETE));
if (dataLoadingComplete)
localBroadcastManager.sendBroadcast(new Intent(ACTION_DATA_LOADING_COMPLETE));
}
}, SPLASH_DISPLAY_LENGHT);
}
}
在你的 AsyncTask
:
@Override
onPostExecute(...) {
super.onPostExecute(...)
...
LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent(SplashActivity.ACTION_DATA_LOADING_COMPLETE));
}
package com.example;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.AsyncTask;
public class SplashActivity extends Activity{
private Timer timer;
private boolean isTaskRunning = false;
private boolean isTimerFinished = false;
private long SPLASH_DURATION = 2*1000;
protected void onCreate(android.os.Bundle savedInstanceState) {
setContentView(R.layout.badgeview);
new MyTask().execute();
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
isTimerFinished = true;
if(!isTaskRunning){
//startNextActivity;
}
}
}, SPLASH_DURATION);
}
class MyTask extends AsyncTask<Void, Void, Void>{
@Override
protected void onPreExecute() {
super.onPreExecute();
isTaskRunning = true;
}
@Override
protected Void doInBackground(Void... params) {
//do whatever you require from network
return null;
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
isTaskRunning = false;
if(!isTimerFinished){
timer.cancel();
}
//startNextActivity
}
}
}
像这样在处理程序中放置条件
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if(isTaskSuccessfull)
startMainActivity();
else
isHandlerTimeout = true;
}
},
在 Asyn 的 OnPost() 方法中,当任务成功完成时,首先将 asyn 任务的 flag(isTaskSuccessfull) 的值更改为 true,然后检查 isHandlerTimeout 是否为真,如果是,则从 asyn 的 onPost() 调用方法 startMainActivity()。
private static final long SPLASH_DURATION = 2*1000;
private long mStartTimestamp;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
mStartTimestamp = System.currentTimeMillis();
new MyTask().execute();
}
class MyTask extends AsyncTask<Void, Void, Boolean>{
@Override
protected Boolean doInBackground(Void... params) {
// your logic here
return true;
}
@Override
protected void onPostExecute(Boolean success) {
super.onPostExecute(success);
// check your result here
if(success){
long timeStop = System.currentTimeMillis();
long delta = timeStop - mStartTimestamp;
if (delta >= SPLASH_DURATION) {
startMainActivity();
} else {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
startMainActivity();
}
}, SPLASH_DURATION - delta);
}
} else {
// handle the error
}
}
}
我目前在启动画面活动中使用以下结构,以便在指定时间段内显示它:
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
startMainActivity();
}
}, SPLASH_DISPLAY_LENGHT);
然而,我只是创建一个应用程序,它使用 AsyncTask 从网络加载一些信息到它的初始屏幕上,如下所示:
startUpAsyncTask = new StartUpAsyncTask(this);
startUpAsyncTask.execute();
现在我想这样实现处理程序:
- 如果在网络加载期间出现故障,它会停止处理程序以移至 MainActivity。
- 如果网络加载持续时间超过
SPLASH_DISPLAY_LENGHT
activity 等到网络加载在StartUpAsyncTask
完成,然后转到下一个 activity。 - 如果网络
StartUpAsyncTask
很快结束,启动画面至少显示SPLASH_DISPLAY_LENGHT
时间长度。
我的问题是如何同步这个AsyncTask和Handler来实现这样的约束。
您可以在启动画面中注册一个 BroadcastReceiver
并注册一个 LocalBroadcastManager
,它将收到来自您的 AsyncTask
的成功消息并设置一个标志。另一个 BroadcastReceiver
将在您的处理程序中注册,以防在 SPLASH_DISPLAY_LENGHT
已经过去时尚未设置标志,并且将在 startMainActivity()
从您的 AsyncTask
收到广播时注册;否则,如果在您的处理程序中完成 SPLASH_DISPLAY_LENGHT
时已经设置了标志,它将直接 startMainActivity()
.
在你的SplashActivity
中:
private class SplashActivity extends Activity {
public static final String ACTION_DATA_LOADING_COMPLETE = "com.example.myapp.ACTION_DATA_LOADING_COMPLETE";
private LocalBroadcastManager localBroadcastManager;
private boolean dataLoadingComplete = false;
@Override
private void onCreate(Bundle savedInstanceState) {
...
localBroadcastManager = LocalBroadcastManager.getInstance(this);
localBroadcastManager .registerBroadcastReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
dataLoadingComplete = true;
}
}, new IntentFilter(ACTION_DATA_LOADING_COMPLETE));
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
localBroadcastManager.registerBroadcastReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
startMainActivity();
}
}, new IntentFilter(ACTION_DATA_LOADING_COMPLETE));
if (dataLoadingComplete)
localBroadcastManager.sendBroadcast(new Intent(ACTION_DATA_LOADING_COMPLETE));
}
}, SPLASH_DISPLAY_LENGHT);
}
}
在你的 AsyncTask
:
@Override
onPostExecute(...) {
super.onPostExecute(...)
...
LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent(SplashActivity.ACTION_DATA_LOADING_COMPLETE));
}
package com.example;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.AsyncTask;
public class SplashActivity extends Activity{
private Timer timer;
private boolean isTaskRunning = false;
private boolean isTimerFinished = false;
private long SPLASH_DURATION = 2*1000;
protected void onCreate(android.os.Bundle savedInstanceState) {
setContentView(R.layout.badgeview);
new MyTask().execute();
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
isTimerFinished = true;
if(!isTaskRunning){
//startNextActivity;
}
}
}, SPLASH_DURATION);
}
class MyTask extends AsyncTask<Void, Void, Void>{
@Override
protected void onPreExecute() {
super.onPreExecute();
isTaskRunning = true;
}
@Override
protected Void doInBackground(Void... params) {
//do whatever you require from network
return null;
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
isTaskRunning = false;
if(!isTimerFinished){
timer.cancel();
}
//startNextActivity
}
}
}
像这样在处理程序中放置条件
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if(isTaskSuccessfull)
startMainActivity();
else
isHandlerTimeout = true;
}
},
在 Asyn 的 OnPost() 方法中,当任务成功完成时,首先将 asyn 任务的 flag(isTaskSuccessfull) 的值更改为 true,然后检查 isHandlerTimeout 是否为真,如果是,则从 asyn 的 onPost() 调用方法 startMainActivity()。
private static final long SPLASH_DURATION = 2*1000;
private long mStartTimestamp;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
mStartTimestamp = System.currentTimeMillis();
new MyTask().execute();
}
class MyTask extends AsyncTask<Void, Void, Boolean>{
@Override
protected Boolean doInBackground(Void... params) {
// your logic here
return true;
}
@Override
protected void onPostExecute(Boolean success) {
super.onPostExecute(success);
// check your result here
if(success){
long timeStop = System.currentTimeMillis();
long delta = timeStop - mStartTimestamp;
if (delta >= SPLASH_DURATION) {
startMainActivity();
} else {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
startMainActivity();
}
}, SPLASH_DURATION - delta);
}
} else {
// handle the error
}
}
}