Android Browser App 源码分析(三)之UI篇第一讲
2017-01-03 17:24
489 查看
Android Native Browser的界面还是比较单一,比较少的。主要体现为:主界面(主要用于加载网页)、设置页面(用于设置浏览器中各个属性,比如是否启用JavaScript、是否保存密码等)、书签&历史记录页面(展示书签以及访问网页的历史记录)。
首先从代码层面分析下主界面的UI逻辑实现,看看到底是如何加载网页的。
因Browser App同时也要兼容平板设备,所以,这里又抽象出一个抽象类BaseUi来实现手机与平板公共通用的部分,然后将差异性的方法通过派生类PhoneUi与XLargeUi来实现。
Browser主界面头部会有一个标题栏,主要用于输入网址、保存书签,因为平板与手机的尺寸是不同的,对应的头部Tab页导航展示也就不同了,所以Browser内部又声明了NavigationBarPhone、NavigationBarTablet类来进行处理,他们继承于NavigationBarBase类。
整个结构关系如下:
启动页:BrowserActivity::onCreate()
初始化Controller 对象
然后调用Controller start方法
然后调用CrashRecoveryHandler startRecovery方法
CrashRecoveryHandler实例的初始化调用在Controller构造函数中:
mCrashRecoveryHandler = CrashRecoveryHandler.initialize(this); //实例化CrashRecoveryHandler对象,CrashRecoveryHandler构造函数中同时又创建了foregroundHandler和backgroundHandler
mCrashRecoveryHandler.preloadCrashState();
//mBackgroundHandler.sendEmptyMessage(MSG_PRELOAD_STATE);
调用loadCrashState,从STATE_FILE(browser_state.parcel)文件中读入到mRecoveryState中
调用mController.doStart(mRecoveryState, intent); 将mRecoveryState传递过去
然后对mRecoveryState中的lastActiveDate进行判断,如果最后一次浏览器的使用时间在24小时内,否则的话销毁所有剩余的隐身标签页。
调用mTabControl.canRestoreState来获取TabId
如果等于-1,执行CookieManager.getInstance().removeSessionCookie()
然后调用GoogleAccountLogin.startLoginIfNeeded进行登录
如果已经登录或者没有找到账号,直接执行runnable.run 方法
否则执行登录操作
onPreloginFinished 方法:
如果tabId等于-1(默认的情况下第一次进来为-1):
如果intent为null:调用openTabToHomePage方法,打开主页
如果intent不为null:获取urlData,如果为空:调用openTabToHomePage方法,打开主页
否则打开Tab,加载对应的urlData
调用openTabToHomePage:
openTab(mSettings.getHomePage(), false, true, false);
最终会调用这个openTab(String url, boolean incognito, boolean setActive,boolean useCurrent, Tab parent)方法:
通过createNewTab创建一个Tab对象
内部是通过TabControl.createNewTab来进行创建
createNewTab(boolean privateBrowsing)---> createNewTab(Bundle state, boolean privateBrowsing) ----> createNewWebView实例化WebView对象---> mController.getWebViewFactory().createWebView(privateBrowsing)
----> BrowserWebViewFactory.createWebView 创建WebView
-----> instantiateWebView、initWebViewSettings
WebView创建完毕之后,开始实例化一个Tab对象,并添加到mTabs集合中:
Tab t = new Tab(mController, w, state);
mTabs.add(t);
调用Controller.onSetWebView ---> mUi.onSetWebView(tab, view);
----->BaseUi.onSetWebView
然后container = mActivity.getLayoutInflater().inflate(R.layout.tab, mContentView, false); 创建装载WebView的Tab容器
之后调用 t.putInBackground(); 先把标签放入后台
调用addTab()-->mUi.addTab 将tab传递到对应的UI中
这个方法PhoneUi没有重写,XLargeUi重写了。
然后调用 Controller.setActiveTab(tab) ---> mTabControl.setCurrentTab(tab)、mUi.setActiveTab(tab)
--->PhoneUi::setActiveTab
--->BaseUi::setActiveTab
--->attachTabToContentView(tab)
获取Tab的ViewContainer,获取container中的webview_wrapper控件,然后将tab对应的webView添加到其中,然后再将container添加到mContentView中
那mContentView是从哪里来的呢?
是通过实例化PhoneUi对象来的,在BaseUi构造函数中;
然后调用loadUrl来加载url
loadUrl(Tab tab, String url)-->loadUrl(Tab tab, String url, Map<String, String> headers)
Tab.java:
最终执行mMainView loadUrl方法加载url,显示对应url的网页。
首先从代码层面分析下主界面的UI逻辑实现,看看到底是如何加载网页的。
(一)基础架构
Browser定义了UI接口来统管整个主界面的操作,以及对Activity生命周期发生变化的处理。因Browser App同时也要兼容平板设备,所以,这里又抽象出一个抽象类BaseUi来实现手机与平板公共通用的部分,然后将差异性的方法通过派生类PhoneUi与XLargeUi来实现。
Browser主界面头部会有一个标题栏,主要用于输入网址、保存书签,因为平板与手机的尺寸是不同的,对应的头部Tab页导航展示也就不同了,所以Browser内部又声明了NavigationBarPhone、NavigationBarTablet类来进行处理,他们继承于NavigationBarBase类。
整个结构关系如下:
(二)主界面如何Load出来的
启动页:BrowserActivity::onCreate()初始化Controller 对象
然后调用Controller start方法
然后调用CrashRecoveryHandler startRecovery方法
CrashRecoveryHandler实例的初始化调用在Controller构造函数中:
mCrashRecoveryHandler = CrashRecoveryHandler.initialize(this); //实例化CrashRecoveryHandler对象,CrashRecoveryHandler构造函数中同时又创建了foregroundHandler和backgroundHandler
mCrashRecoveryHandler.preloadCrashState();
//mBackgroundHandler.sendEmptyMessage(MSG_PRELOAD_STATE);
调用loadCrashState,从STATE_FILE(browser_state.parcel)文件中读入到mRecoveryState中
调用mController.doStart(mRecoveryState, intent); 将mRecoveryState传递过去
然后对mRecoveryState中的lastActiveDate进行判断,如果最后一次浏览器的使用时间在24小时内,否则的话销毁所有剩余的隐身标签页。
调用mTabControl.canRestoreState来获取TabId
如果等于-1,执行CookieManager.getInstance().removeSessionCookie()
然后调用GoogleAccountLogin.startLoginIfNeeded进行登录
如果已经登录或者没有找到账号,直接执行runnable.run 方法
否则执行登录操作
onPreloginFinished 方法:
如果tabId等于-1(默认的情况下第一次进来为-1):
如果intent为null:调用openTabToHomePage方法,打开主页
如果intent不为null:获取urlData,如果为空:调用openTabToHomePage方法,打开主页
否则打开Tab,加载对应的urlData
调用openTabToHomePage:
openTab(mSettings.getHomePage(), false, true, false);
最终会调用这个openTab(String url, boolean incognito, boolean setActive,boolean useCurrent, Tab parent)方法:
通过createNewTab创建一个Tab对象
内部是通过TabControl.createNewTab来进行创建
createNewTab(boolean privateBrowsing)---> createNewTab(Bundle state, boolean privateBrowsing) ----> createNewWebView实例化WebView对象---> mController.getWebViewFactory().createWebView(privateBrowsing)
----> BrowserWebViewFactory.createWebView 创建WebView
-----> instantiateWebView、initWebViewSettings
WebView创建完毕之后,开始实例化一个Tab对象,并添加到mTabs集合中:
Tab t = new Tab(mController, w, state);
mTabs.add(t);
调用Controller.onSetWebView ---> mUi.onSetWebView(tab, view);
----->BaseUi.onSetWebView
然后container = mActivity.getLayoutInflater().inflate(R.layout.tab, mContentView, false); 创建装载WebView的Tab容器
之后调用 t.putInBackground(); 先把标签放入后台
调用addTab()-->mUi.addTab 将tab传递到对应的UI中
这个方法PhoneUi没有重写,XLargeUi重写了。
然后调用 Controller.setActiveTab(tab) ---> mTabControl.setCurrentTab(tab)、mUi.setActiveTab(tab)
--->PhoneUi::setActiveTab
--->BaseUi::setActiveTab
--->attachTabToContentView(tab)
protected void attachTabToContentView(Tab tab) { if ((tab == null) || (tab.getWebView() == null)) { return; } View container = tab.getViewContainer(); WebView mainView = tab.getWebView(); // Attach the WebView to the container and then attach the // container to the content view. FrameLayout wrapper = (FrameLayout) container.findViewById(R.id.webview_wrapper); ViewGroup parent = (ViewGroup) mainView.getParent(); if (parent != wrapper) { if (parent != null) { parent.removeView(mainView); } wrapper.addView(mainView); } parent = (ViewGroup) container.getParent(); if (parent != mContentView) { if (parent != null) { parent.removeView(container); } mContentView.addView(container, COVER_SCREEN_PARAMS); } mUiController.attachSubWindow(tab); }
获取Tab的ViewContainer,获取container中的webview_wrapper控件,然后将tab对应的webView添加到其中,然后再将container添加到mContentView中
那mContentView是从哪里来的呢?
是通过实例化PhoneUi对象来的,在BaseUi构造函数中;
FrameLayout frameLayout = (FrameLayout) mActivity.getWindow() .getDecorView().findViewById(android.R.id.content); LayoutInflater.from(mActivity) .inflate(R.layout.custom_screen, frameLayout); mContentView = (FrameLayout) frameLayout.findViewById(R.id.main_content);
然后调用loadUrl来加载url
loadUrl(Tab tab, String url)-->loadUrl(Tab tab, String url, Map<String, String> headers)
if (tab != null) { dismissSubWindow(tab); tab.loadUrl(url, headers); mUi.onProgressChanged(tab); }
Tab.java:
public void loadUrl(String url, Map<String, String> headers) { if (mMainView != null) { mPageLoadProgress = INITIAL_PROGRESS; mInPageLoad = true; mCurrentState = new PageState(mContext, false, url, null); mWebViewController.onPageStarted(this, mMainView, null); mMainView.loadUrl(url, headers); } }
最终执行mMainView loadUrl方法加载url,显示对应url的网页。
相关文章推荐
- Android Browser App 源码分析(一)
- Android Browser App 源码分析(二)
- F8App-ReactNative项目源码分析3-Android端
- Android M 启动源码分析笔记之 - App 进程
- Android仿今日头条和知乎等App顶部滑动导航实现代码分析及源码下载
- Android App 源码分析(贪吃蛇游戏)
- [Android]从Launcher开始启动App流程源码分析
- [置顶] Android 双开沙箱 VirtualApp 源码分析(四)启动插件 Service
- 开源中国 OsChina Android 客户端源码分析(1)启动界面 app_start
- [置顶] Android 双开沙箱 VirtualApp 源码分析(一)
- Android App签名(证书)校验过程源码分析
- [置顶] Android 双开沙箱 VirtualApp 源码分析(三)App 启动
- [置顶] Android 双开沙箱 VirtualApp 源码分析(五)BroadcastReceiver
- Android之App界面的挂载与显示及源码分析
- android App启动源码分析
- Android App启动时Apk资源加载机制源码分析
- [置顶] Android 双开沙箱 VirtualApp 源码分析(六)ContentProvider
- [Android]从Launcher开始启动App流程源码分析
- [置顶] Android 双开沙箱 VirtualApp 源码分析(二)
- Android App启动时Apk资源加载机制源码分析