編輯:關於Android編程

用React Native架構的無論是Android APP還是iOS APP,在啟動時都出現白屏現象,時間大概1~3s(根據手機或模擬器的性能不同而不同)。
React Native應用在啟動時會將js bundle讀取到內存中,並完成渲染。這期間由於js bundle還沒有完成裝載並渲染,所以界面顯示的是白屏。
白屏給人的感覺很不友好,那有沒有辦法不顯示白屏呢?
上文解釋了:為什麼React Native應用會在啟動的時候顯示一會白屏。既然知道了出現問題的原因,那麼離解決問題也不遠了。市場上大部分APP在啟動的時候都會有個啟動屏,啟動屏對於用戶是比較友好的,一來展示歡迎信息,二來顯示一些產品信息或一些廣告,啟動頁對於程序來說,是為程序完成初始化加載數據,做一些初始化工作的所保留的時間,啟動屏等待的時間可長可短,具體根據業務而定。
下面我就教大家如何給React Native Android加啟動屏,並解決啟動白屏的問題。
為了實現為React Native Android添加啟動屏,我們需要給React Native動刀了了。下面就讓我們從源碼看起。
通過react-native init
public class MainActivity extends ReactActivity {
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "GitHubPopular";
}
}
通過上述代碼可以看出MainActivity很干淨,就一個getMainComponentName()方法。顯然啟動白屏不是因為MainActivity導致的。
接下來,我們就繼續探索,進入ReactActivity源碼一探究竟。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23) {
// Get permission to show redbox in dev builds.
if (!Settings.canDrawOverlays(this)) {
Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
startActivity(serviceIntent);
FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE);
Toast.makeText(this, REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show();
}
}
mReactRootView = createRootView();
mReactRootView.startReactApplication(
getReactNativeHost().getReactInstanceManager(),
getMainComponentName(),
getLaunchOptions());
setContentView(mReactRootView);
mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
}
上面代碼是ReactActivity的onCreate方法的代碼,onCreate作為一個Activity的入口,負責著程序初始化等一系列工作。
熟悉Android開發的小伙伴都知道,在onCreate方法通過setContentView()方法設置一個用於用戶交互界面。在ReactActivity的onCreate方法中也有使用setContentView()。
mReactRootView = createRootView();
mReactRootView.startReactApplication(
getReactNativeHost().getReactInstanceManager(),
getMainComponentName(),
getLaunchOptions());
setContentView(mReactRootView);
上述代碼中,首先通過mReactRootView = createRootView();創建一個根視圖,該視圖便是React Native應用的最頂部視圖。然後通過mReactRootView.startReactApplication方法,加載並渲染js bundle,此過程是比較耗時的。最後,通過setContentView(mReactRootView);將根視圖綁定到Activity界面上。
基本原理就是這些,下面我們就對ReactActivity動動刀子。
先說一下思路:
APP啟動的時候控制ReactActivity顯示啟動屏。 提供關閉啟動屏的公共接口。 在js的適當位(一般是程序初始化工作完成後)置調用上述公共接口關閉啟動屏。在給ReactActivity動刀子前我們需要進行一些准備工作。
基礎准備:
首先,我們需要將ReactActivity復制一份出來。
因為ReactActivity是React Native源碼中的一部分,我們無法直接對其源碼進行修改,所以我們需將它復制一份出來。然後將MainActivity繼承改為我們復制出來的這個ReactActivity。
其次。修改getUseDeveloperSupport方法。
因為,ReactNativeHost的getUseDeveloperSupport方法是受保護類型的,所以我們無法在它所屬包之外訪問該方法。但我們又需要在ReactActivity中調用該方法,那麼我們可以使用反射來滿足我們這一需求。
protected boolean getUseDeveloperSupport() {
ReactNativeHost rnh=((ReactApplication) getApplication()).getReactNativeHost();
Classcls=rnh.getClass();
Object support= null;
try {
Method method = cls.getDeclaredMethod("getUseDeveloperSupport", new Class[]{});
method.setAccessible(true);
support=method.invoke(rnh);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return (boolean) support;
}
前期工作准備玩了,現在讓我們開始吧。
為了讓ReactActivity顯示啟動屏我們需要創建一個View容器,來容納啟動屏視圖和React Native根視圖。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23) {
// Get permission to show redbox in dev builds.
if (!Settings.canDrawOverlays(this)) {
Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
startActivity(serviceIntent);
FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE);
Toast.makeText(this, REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show();
}
}
mRootView = new FrameLayout(this);
splashView = LayoutInflater.from(this).inflate(R.layout.launch_screen, null);
mReactRootView = createRootView();
mReactRootView.startReactApplication(
getReactNativeHost().getReactInstanceManager(),
getMainComponentName(),
getLaunchOptions());
mRootView.addView(mReactRootView);
mRootView.addView(splashView, new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
setContentView(mRootView);
mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
}
首先,我創建了一個mRootView = new FrameLayout(this);視圖容器。
其次,將啟動屏布局文件讀到內存中splashView = LayoutInflater.from(this).inflate(R.layout.launch_screen, null);。
再次,添加mReactRootView與splashView,注意添加順序。
最後,將mRootView綁定到Activity。
這樣一來,我們就控制了ReactActivity在啟動的時候顯示歡迎界面。下面我們需要讓ReactActivity開放關閉換用界面的接口方法。
/**
* 隱藏啟動屏幕
*/
public void hide() {
if (mRootView == null || splashView == null) return;
AlphaAnimation fadeOut = new AlphaAnimation(1, 0);
fadeOut.setDuration(1000);
splashView.startAnimation(fadeOut);
fadeOut.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
mRootView.removeView(splashView);
splashView = null;
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
上述方法,中加入了一個淡出動畫持續1s,目的是讓歡迎界面和其他界面之間過度自然些。
做到這裡還不夠,因為我們需要在js中調用hide方法還控制歡迎界面的關閉。js不能直接調Java,所有我們需要為他們搭建一個橋梁(Native Modules)。
首先,創建一個ReactContextBaseJavaModule類型的類,供js調用。
/**
* LaunchScreenModule
* 出自:http://www.cboy.me
* GitHub:https://github.com/crazycodeboy
* Eamil:crazycodeboy@gmail.com
*/
public class LaunchScreenModule extends ReactContextBaseJavaModule{
public LaunchScreenModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return "LaunchScreen";
}
@ReactMethod
public void hide(){
getCurrentActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
((ReactActivity)getCurrentActivity()).hide();
}
});
}
}
其次,創建一個ReactPackage類型的類,用於向React Native注冊我們的LaunchScreenModule組件。
/**
* LaunchScreenReactPackage
* 出自:http://www.cboy.me
* GitHub:https://github.com/crazycodeboy
* Eamil:crazycodeboy@gmail.com
*/
public class LaunchScreenReactPackage implements ReactPackage {
@Override
public List> createJSModules() {
return Collections.emptyList();
}
@Override
public List createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List createNativeModules(
ReactApplicationContext reactContext) {
List modules = new ArrayList<>();
modules.add(new LaunchScreenModule(reactContext));
return modules;
}
}
再次,在MainApplication中注冊LaunchScreenModule組件。
@Override protected ListgetPackages() { return Arrays. asList( new MainReactPackage(), new LaunchScreenReactPackage() ); }
最後,在js中調用LaunchScreenModule。
創建一個名為LaunchScreen的文件,加入下面代碼。
/**
* LaunchScreen
* Android啟動屏
* 出自:http://www.cboy.me
* GitHub:https://github.com/crazycodeboy
* Eamil:crazycodeboy@gmail.com
* @flow
*/
'use strict';
import { NativeModules } from 'react-native';
module.exports = NativeModules.LaunchScreen;
上述代碼,目的是向js暴露LaunchScreen模塊。
下面我們就可以在js中調用LaunchScreen的hide()方法來關閉啟動屏了。
LaunchScreen.hide();
不要忘記在使用LaunchScreen的js文件中導入它哦import LaunchScreen from './LaunchScreen。
到這裡,React Native Android的啟動白屏的原因,解決方案,原理,使用方法已經向大家介紹完了。大家如果還有什麼疑問可以加群:165774887,和我一起討論。
另外,跟大家分享一個Android啟動時閃現白屏或黑屏的解決方案。
這個問題是Android主題的問題和React Native無關,請往下看。
市場上有很多應用,在啟動的時候,會出現閃現黑屏或白屏,有的應用卻沒有。究其原因,是主題在搞鬼。
當單擊應用的圖標時,Android會為被單擊的應用創建一個進程,然後創建一個Application實例,然後應用主題,然後啟動Activity。
因為啟動Activity也是需要時間的,這之間的時間間隔,便是閃現白屏或黑屏的時間。
為解決啟動時閃現白屏或黑屏的問題,我們可以從主題下手,為應用創建一個透明的主題。
第一步:創建一個透明主題。
第二步:在AndroidManifest.xml中為application應用主題。
這樣一來,啟動時變不會閃現黑屏或白屏了。
如果,你的應用需要一個特定的主題,但該主題不是透明的,你可以先將application的默認主題設置成透明的主題,然後在程序啟動後(可以在啟動頁進行),通過public void setTheme(int resid)方法將主題設置成你想要的主題即可。
android:Activity數據傳遞之全局對象(application)
在activity之間數據傳遞中還有一種比較實用的方式,就是全局對象application Application和Activity,Service一樣是And
Android 解決build path errors的問題
新建一個eclipse-android項目後,如test2,從其它項目中拷貝若干個包到test2中,在編譯時總會出現以下錯誤:?主要看第三條:The projec
Android ATCID客制化AT命令
ATCID主要用來處理PC端傳輸過來的AT命令,從AT命令實際處理的地方來說,主要分為3類: 1. 需要Modem來處理的AT命令; 2. 需
華為榮耀note8怎麼預約 榮耀note8預約購買攻略
華為榮耀於8月1號下午正式發布了6.6吋大屏手機華為榮耀NOTE8,那麼想要購買新機的朋友是不是很想知道華為榮耀note8怎麼預約購買呢?下面小編就馬上帶來