We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
目前SplashActivity的设计 目前市场上的应用在启动时基本上都会先启动一个SplashActivity,作为一个欢迎界面,为什么这样设计呢? 个人总结有三个优点:
1、可以给用户更好的体验 比如:可以由后台动态的改变欢迎的图片,或者显欢迎xxx回来,新浪微博的就是这种交互。
2、可以缩减App的启动时间 由上一篇博文中知道app启动的耗时主要是在Application初始化中和MainActivity的界面绘制前,由于MainActivity的业务和布局复杂度肯定比只显示一张图片的界面高,所以,加入一个显示一张图片的Splash页可以优化应用的启动。
3、可以在应用启动时做更多的事 一般来说SplashActivity一般会设计成停留2到4s不等,或者根据数据的加载程度来动态的设置Splash界面的停留时间,既然停留那么久,那么当然可以在这个界面背后做一些事以备MainActivity的快速显示,比如:数据的预加载、sp的初始化、网络请求等。
当然你可能有些疑问,那这样初始化放在Application中也可以啊?也用异步操作数据也是一样啊?
答案是不一样!正如上篇所说的,Application初始化时并不会加载界面,而是在它创建完和初始化完成后,开始创建Activity时才开始绘制Theme中的background和绘制布局,所以用一个轻量的Splash页给它设置一张背景欢迎图,这样就立马能显示界面了,而在这个界面中还可以做其它的初始化操作,这样在视觉上即达到了app的快速启动,又添加了体验和做数据的初始化。
相反如果过多的放在Application中,则在点击app图标启动时会感觉延迟,必须要把Application中的东西都做完才进入Activity的配置和绘制中。
目前大多数应用的Splash页设计的不足之处 目前大多应用的Splash页设计都是利用一个Activity,取名叫SplashActivity,然后在这个SplashActivity中加入一个背景图,然后再new Handler().postDelayed()几秒中,再startActivity跳入主界面,这样设计看起来非常不错,既可以在SplashActivity初始化、预加载数据,还可以提高应用的启动速度。
不过这确实提高了应用的启动速度,毕竟我们比较快的看到了第一帧——SplashActivity,不过在SplashActivity之后,还需要调到MainActivity啊,虽然MainActivity中的一些数据可以在SplashActivity做预取,不过这中间需要有Intent的传递过程,而且MainActivity中布局还没加载进来,所以还是需要再加载和绘制布局界面,然后才能填入数据,所以这样看来,在跳转到MainActivity中,还是需要做界面的绘制和数据的加载(包括Intent的数据传递)。
以往的SplashActivity的设计图 这样看来上面这个设计流程可以这样表示: 这里写图片描述
性能优且体验棒的Splash页的设计 从上面这个设计图来看,其中有些操作能不能去除呢?既能达到app启动速度的提高,也能对数据的预加载还能减去Splash和MainActivity之间不必要的数据传递和View的分开绘制。
答案是能的,既然SplashActivity和MainActivity分开进行操作还是不完美,那么可以考虑把它们合为一起,即:一开始还是显示MainActivity,SplashActivity变为SplashFragment,然后放一个FrameLayout作为根布局去显示SplashFragment界面,这样在SplashFragment显示时候利用显示的2~4s间的空隙时间做网络请求去加载数据,这样待SplashFragment显示完后再remove,这样将看到的是有内容的MainActivity,就不必再去等待网络请求去返回数据了。 当然,这种方式是把load Splash View和ContentView合二为一了一起加载,这可能会影响应用的启动时间,这时我们可以用ViewStub延迟加载MainActivity中某些View从而减去这个影响。
如下设计: 这里写图片描述
优化前后效果对比 这里为了测试,我把Splash页的delay时间都设为2.5s。 优化前: 这里写图片描述 优化后: 这里写图片描述 优化后其实是把SplashActivity用Fragment显示,显示完后再remove,这样在显示的时候,MainActivity中还可以直接加载网络数据,这样在显示完SplashFragment后则直接显示主页了,而省去了ProgressBar进度条的网络加载过程。 代码:
private Handler mHandler = new Handler();
//... final SplashFragment splashFragment = new SplashFragment(); final FragmentTransaction transaction = getFragmentManager().beginTransaction(); transaction.replace(R.id.frame, splashFragment); transaction.commit(); //... mHandler.postDelayed(new DelayRunnable(this, splashFragment, mProgressBar), 2500); //... static class DelayRunnable implements Runnable { private WeakReference contextRef; private WeakReference fragmentRef; private WeakReference progressBarRef;
public DelayRunnable(Context context, SplashFragment splashFragment, ProgressBar progressBar) { contextRef = new WeakReference<Context>(context); fragmentRef = new WeakReference<SplashFragment>(splashFragment); progressBarRef = new WeakReference<ProgressBar>(progressBar); } @Override public void run() { ProgressBar progressBar = progressBarRef.get(); if (progressBar != null) progressBar.setVisibility(View.GONE); Activity context = (Activity) contextRef.get(); if (context != null) { SplashFragment splashFragment = fragmentRef.get(); if (splashFragment == null) return; final FragmentTransaction transaction = context.getFragmentManager().beginTransaction(); transaction.remove(splashFragment); transaction.commit(); } } } @Override protected void onDestroy() { super.onDestroy(); mHandler.removeCallbacksAndMessages(null); }
其中FrameLayout作为MainActivity的根布局用作SplashFragment的全屏显示。 为了更优则可以考虑ViewStub,在SplashFragment显示时再进行加载额外的View。
关于耦合性,其实很低,Splash页面有专门一个SplashFragment去配置,而MainActivity只是控制它的加载与remove。
关于应用DelayLoad延迟加载的几种方式 1、View.postDelayed(); 2、Handler.postDelayed(); 3、getWindow().getDecorView().post(){Handler.postDelay()}
而前两种方式虽然都有Delay效果,但并不是真正Delay了我们设置的时间,而第三种方式才是正确的Delay了我们想要的时间,原因如下: 关于Activity界面的启动,首先是在onCreate()方法中会对contentView、DecorView和ActionBar等进行初始化,比如:contentView进行inflate,我们便可以在这个方法中通过findViewById来找到对应的控件了,但是此时我们只是把那些对应的控件创建了一个对象而已,它们并没有add在界面上。而真正把contentView 添加到界面上的操作是在OnResume()方法执行时候,包括ViewRootImpl的初始化。而contentView的绘制会在onResume()方法执行完后的二次performTraversals()方法进行绘制。
所以要想达到DelayLoad懒加载效果,是在所有的View绘制完成后进行Delay效果,而上面的第一第二种方式都是在第一次performTraversals()后执行,该次只是为第二次调用performTraversals()方法做一些准备工作,这样就达不到准确的Delay效果了,因为第二次的performTraversals()就是真正的进行View的测量布局和绘制了,这肯定是需要时间的,所以第一和第二种方式Delay的时间是需要再减去这个View绘制的时间的。
如果是想在界面刚绘制完成后做一些事情,或者有些事情必须在UI绘制完成显示后做的话,那可以通过这个方法:
getWindow().getDecorView().post(new Runnable() { @Override public void run() { mHandler.post(new Runnable() { @Override public void run() { //do something } }); } });
如果想Delay的话,可以这样:
getWindow().getDecorView().post(new Runnable() { @Override public void run() { mHandler.postDelayed(new Runnable() { @Override public void run() { //do something } },3000); } });
The text was updated successfully, but these errors were encountered:
No branches or pull requests
目前SplashActivity的设计
目前市场上的应用在启动时基本上都会先启动一个SplashActivity,作为一个欢迎界面,为什么这样设计呢?
个人总结有三个优点:
1、可以给用户更好的体验
比如:可以由后台动态的改变欢迎的图片,或者显欢迎xxx回来,新浪微博的就是这种交互。
2、可以缩减App的启动时间
由上一篇博文中知道app启动的耗时主要是在Application初始化中和MainActivity的界面绘制前,由于MainActivity的业务和布局复杂度肯定比只显示一张图片的界面高,所以,加入一个显示一张图片的Splash页可以优化应用的启动。
3、可以在应用启动时做更多的事
一般来说SplashActivity一般会设计成停留2到4s不等,或者根据数据的加载程度来动态的设置Splash界面的停留时间,既然停留那么久,那么当然可以在这个界面背后做一些事以备MainActivity的快速显示,比如:数据的预加载、sp的初始化、网络请求等。
当然你可能有些疑问,那这样初始化放在Application中也可以啊?也用异步操作数据也是一样啊?
答案是不一样!正如上篇所说的,Application初始化时并不会加载界面,而是在它创建完和初始化完成后,开始创建Activity时才开始绘制Theme中的background和绘制布局,所以用一个轻量的Splash页给它设置一张背景欢迎图,这样就立马能显示界面了,而在这个界面中还可以做其它的初始化操作,这样在视觉上即达到了app的快速启动,又添加了体验和做数据的初始化。
相反如果过多的放在Application中,则在点击app图标启动时会感觉延迟,必须要把Application中的东西都做完才进入Activity的配置和绘制中。
目前大多数应用的Splash页设计的不足之处
目前大多应用的Splash页设计都是利用一个Activity,取名叫SplashActivity,然后在这个SplashActivity中加入一个背景图,然后再new Handler().postDelayed()几秒中,再startActivity跳入主界面,这样设计看起来非常不错,既可以在SplashActivity初始化、预加载数据,还可以提高应用的启动速度。
不过这确实提高了应用的启动速度,毕竟我们比较快的看到了第一帧——SplashActivity,不过在SplashActivity之后,还需要调到MainActivity啊,虽然MainActivity中的一些数据可以在SplashActivity做预取,不过这中间需要有Intent的传递过程,而且MainActivity中布局还没加载进来,所以还是需要再加载和绘制布局界面,然后才能填入数据,所以这样看来,在跳转到MainActivity中,还是需要做界面的绘制和数据的加载(包括Intent的数据传递)。
以往的SplashActivity的设计图
这样看来上面这个设计流程可以这样表示:
这里写图片描述
性能优且体验棒的Splash页的设计
从上面这个设计图来看,其中有些操作能不能去除呢?既能达到app启动速度的提高,也能对数据的预加载还能减去Splash和MainActivity之间不必要的数据传递和View的分开绘制。
答案是能的,既然SplashActivity和MainActivity分开进行操作还是不完美,那么可以考虑把它们合为一起,即:一开始还是显示MainActivity,SplashActivity变为SplashFragment,然后放一个FrameLayout作为根布局去显示SplashFragment界面,这样在SplashFragment显示时候利用显示的2~4s间的空隙时间做网络请求去加载数据,这样待SplashFragment显示完后再remove,这样将看到的是有内容的MainActivity,就不必再去等待网络请求去返回数据了。
当然,这种方式是把load Splash View和ContentView合二为一了一起加载,这可能会影响应用的启动时间,这时我们可以用ViewStub延迟加载MainActivity中某些View从而减去这个影响。
如下设计:
这里写图片描述
优化前后效果对比
这里为了测试,我把Splash页的delay时间都设为2.5s。
优化前:
这里写图片描述
优化后:
这里写图片描述
优化后其实是把SplashActivity用Fragment显示,显示完后再remove,这样在显示的时候,MainActivity中还可以直接加载网络数据,这样在显示完SplashFragment后则直接显示主页了,而省去了ProgressBar进度条的网络加载过程。
代码:
//...
final SplashFragment splashFragment = new SplashFragment();
final FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.frame, splashFragment);
transaction.commit();
//...
mHandler.postDelayed(new DelayRunnable(this, splashFragment, mProgressBar), 2500);
//...
static class DelayRunnable implements Runnable {
private WeakReference contextRef;
private WeakReference fragmentRef;
private WeakReference progressBarRef;
其中FrameLayout作为MainActivity的根布局用作SplashFragment的全屏显示。
为了更优则可以考虑ViewStub,在SplashFragment显示时再进行加载额外的View。
关于耦合性,其实很低,Splash页面有专门一个SplashFragment去配置,而MainActivity只是控制它的加载与remove。
关于应用DelayLoad延迟加载的几种方式
1、View.postDelayed();
2、Handler.postDelayed();
3、getWindow().getDecorView().post(){Handler.postDelay()}
而前两种方式虽然都有Delay效果,但并不是真正Delay了我们设置的时间,而第三种方式才是正确的Delay了我们想要的时间,原因如下:
关于Activity界面的启动,首先是在onCreate()方法中会对contentView、DecorView和ActionBar等进行初始化,比如:contentView进行inflate,我们便可以在这个方法中通过findViewById来找到对应的控件了,但是此时我们只是把那些对应的控件创建了一个对象而已,它们并没有add在界面上。而真正把contentView 添加到界面上的操作是在OnResume()方法执行时候,包括ViewRootImpl的初始化。而contentView的绘制会在onResume()方法执行完后的二次performTraversals()方法进行绘制。
所以要想达到DelayLoad懒加载效果,是在所有的View绘制完成后进行Delay效果,而上面的第一第二种方式都是在第一次performTraversals()后执行,该次只是为第二次调用performTraversals()方法做一些准备工作,这样就达不到准确的Delay效果了,因为第二次的performTraversals()就是真正的进行View的测量布局和绘制了,这肯定是需要时间的,所以第一和第二种方式Delay的时间是需要再减去这个View绘制的时间的。
如果是想在界面刚绘制完成后做一些事情,或者有些事情必须在UI绘制完成显示后做的话,那可以通过这个方法:
如果想Delay的话,可以这样:
The text was updated successfully, but these errors were encountered: