最近匆匆看了许多开源项目,SpintNBA这个开源项目写的很好,打算用自己的方式重构,做不到的部分再返回来看源码,这样才有助于吸收。
源码地址:https://github.com/smuyyh/SprintNBA
源码:
没想到一开始就卡住了。。。我们知道,每个应用为了开启时不空白,有个启动页面,但是这个启动页面一般是固定的,但是这个项目的启动页是从几张图中随机选择一张,这是怎么做的呢?于是看回源码的style.xml:
<style name="AppTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="windowActionBar">true</item>
<item name="windowNoTitle">true</item>
<!--<item name="actionBarSize">100dip</item>-->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowAnimationStyle">@style/SlideRightAnimation</item>
<item name="android:windowContentOverlay">@android:color/transparent</item>
<item name="android:windowBackground">@color/colorWindowBg</item>
<item name="android:actionMenuTextColor">@android:color/white</item>
</style>
<style name="NoTitleFullscreen" parent="AppTheme.Base">
<item name="android:windowNoTitle">true</item>
<item name="windowActionBar">false</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowContentOverlay">@null</item>
</style>
注意,中间有这么一句:
<item name="android:windowContentOverlay">@null</item>
这一句是关键,有了这一句,就可以不用担心启动图被白色或者黑色破坏了,可以按照自己的逻辑加载启动图。
写着写着,想起来没加自定义Application以及父类BaseActivity,问题又来了,自定义Application要放些什么,BaseActivity又该放些什么?
或许,你看到这个问题一笑置之,你这家伙是小白吧?好吧,我Andoid也工作一年半了,知道一般Crash和第三方一般放入Application,而BaseActivity应该放类似头部Toolbar初始化,点击事件分发这种的,只不过想看看作者有什么特别的东西,值得学习的。
自定义Application,onCreate()中,作者的特别做法:
mContext = this;
AppUtils.init(mContext);
mContext:作者设置的全局静态变量,Application的生存周期较长,用此方法可省去一些特殊位置获取Context的烦恼,另外一定程度上降低了Context为空的风险。
然后第二句,因为这个类不长,让我们看一下AppUtil的源码:
public class AppUtils {
private static Context mContext;
private static Thread mUiThread;
private static Handler sHandler = new Handler(Looper.getMainLooper());
public static void init(Context context) { //在Application中初始化
mContext = context;
mUiThread = Thread.currentThread();
}
public static Context getAppContext() {
return mContext;
}
public static AssetManager getAssets() {
return mContext.getAssets();
}
public static Resources getResource() {
return mContext.getResources();
}
public static boolean isUIThread() {
return Thread.currentThread() == mUiThread;
}
public static void runOnUI(Runnable r) {
sHandler.post(r);
}
public static void runOnUIDelayed(Runnable r, long delayMills) {
sHandler.postDelayed(r, delayMills);
}
public static void removeRunnable(Runnable r) {
if (r == null) {
sHandler.removeCallbacksAndMessages(null);
} else
这个类主要关注三点,
- mContext
在此类中用于获取资源,没什么好说的 - sHandler
这个很有用,因为Handler是导致内存泄漏的主因之一,这样写可以防止内存泄漏,而且handler.post,handler.postDelayed这两个方法用途也比较广,自从5.0以后,view.post方法有改动,最好使用handler.post,这样有助于兼容后面的版本。
removeCallbacks在每次调用handler后使用,防止内存泄漏。可在base中destroy中调用:
AppUtils.removeCallbacks(null) - mUiThread
这个用于Handler消息循环判断是否在主线程。
另:Application一般与项目名相同,看个人习惯。
个人认为这个类棒极了,于是写了三次加深印象,写着写着发现一点:初始化其实可以不必传入Context。因为下面的方法没有一个在application需要调用的,也就是说,在调用时,application已经完成了初始化,思考了一下,感觉改成这样比较好:
SprintNBA.getSuperContext().getResources();
然后,原项目报错了。
为啥呀?这样做不是比较好么0 0,我哪里错了???
于是看了一下,作者把一些常见工具类封装了一个包,里面有一些常用工具类,常用自定义控件,权限处理以及异常处理,好吧,这样做确实省时间,打算自己封装一个,不打算抄作者的。