android原生browser分析(二)--界面篇
来源:互联网 发布:域名注册不用实名 编辑:程序博客网 时间:2024/06/03 14:35
本文转载,感觉写的很详细,原文地址:http://blog.csdn.net/android_hasen/article/details/32910627
我们先看一张浏览器的主界面,上面标示浏览器界面各部分对应的类,这里是以平板上的界面为例。给张图是为了给大家一个直观的感觉。
BrowserActivity是整个应用的主界面,在onCreate中创建了Controller对象,Controller对象是整个应用最重要的管理类,这个后面再说。
- @Override
- public void onCreate(Bundle icicle) {
- mController = createController();
- }
Controller的创建中新建了UI类,UI类是最主要的视图类,它虽然不是View类的子类,只是一个包含很多抽象方法的接口,但是它的实现类包含了重要的View视图成员。后面将通过UI的实现类BaseUi将这些视图成员和BrowserActivity中布局文件中视图ID一一对应起来,关于这点后面描述。
- private Controller createController() {
- Controller controller = new Controller(this);
- boolean xlarge = isTablet(this);
- UI ui = null;
- if (xlarge) {
- ui = new XLargeUi(this, controller);
- } else {
- ui = new PhoneUi(this, controller);
- }
- controller.setUi(ui);
- return controller;
- }
由上,我们看到根据isTablet() 方法获取的值,将会创建不同的UI类。
看一下isTablet()方法:
- public static boolean isTablet(Context context) {
- return context.getResources().getBoolean(R.bool.isTablet);
- }
可以看出,这里是通过一个资源文件的值来确定的,实际上这里是用来区分这个是手机应用还是平板应用的。取值为true的时候获取的是XLargeUi对象,取值为false的时候,获取的是PhoneUi对象。由于我的项目是平板的,就以XLargeUi 为例进行分析。
在此,我们把这几个类的继承关系理一理:
- public interface UI {
- //....
- }
- public abstract class BaseUi implements UI {
- //...
- }
- public class XLargeUi extends BaseUi {
- //...
- }
- public class PhoneUi extends BaseUi {
- //...
- }
我们现在来看看XLargeUi 的定义:
- public class XLargeUi extends BaseUi {
- private ActionBar mActionBar;
- private TabBar mTabBar;
- private NavigationBarTablet mNavBar;
- /**
- * @param browser
- * @param controller
- */
- public XLargeUi(Activity browser, UiController controller) {
- super(browser, controller);
- //other code
- mNavBar = (NavigationBarTablet) mTitleBar.getNavigationBar();
- mTabBar = new TabBar(mActivity, mUiController, this);
- mActionBar = mActivity.getActionBar();
- setupActionBar();
- }
- private void setupActionBar() { mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
- mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
- mActionBar.setCustomView(mTabBar);
- }
- //other code
- }
构造方法中传入了两个参数,第一个是应用的主界面BrowserActivity,第二个是UiController 对象,该对象主要做Ui进行控制,如对选项卡的操作,加载URL等。
构造函数中主要做了下面的事情:
1、通过TitleBar类型成员变量mTitleBar获取NavigationBarTablet类型的对象mNavBar ,这个对象即是导航工具栏。就是浏览器界面的如下的工具栏
该对象主要用于更新导航栏的状态,即对前进后退键、URL输入框、URL图标进行操作。
成员变量mTitleBar是从BaseUi继承而来的。
2、新创建一个TabBar类型的对象,这个TabBar对象是只有平板才有的。创建时传入主界面BrowserActivity、UiController 对象、XLargeUi自身。创建的对象即选项卡栏
该对象将用来进行选项卡的相关操作,增加、删除、更新选项卡,改变收藏夹图标favicon,修改URL标题等。
3、通过主界面BrowserActivity获取ActionBar对象。
4、设置ActionBar的样式,并将选项卡栏TabBar对象设置为ActionBar的自定义视图。
关于BaseUi
BaseUi是平板界面XLargeUi和手机界面PhoneUi共有的父类。
- public abstract class BaseUi implements UI {
- Activity mActivity;
- UiController mUiController;
- TabControl mTabControl;
- private UrlBarAutoShowManager mUrlBarAutoShowManager;
- protected TitleBar mTitleBar;
- private NavigationBarBase mNavigationBar;
- protected PieControl mPieControl;
- public BaseUi(Activity browser, UiController controller) {
- mActivity = browser;
- mUiController = controller;
- mTabControl = controller.getTabControl();
- FrameLayout frameLayout = (FrameLayout) mActivity.getWindow()
- .getDecorView().findViewById(android.R.id.content);
- LayoutInflater.from(mActivity)
- .inflate(R.layout.custom_screen, frameLayout);
- //...
- setFullscreen(BrowserSettings.getInstance().useFullscreen());
- mTitleBar = new TitleBar(mActivity, mUiController, this,
- mContentView);
- mTitleBar.setProgress(100);
- mNavigationBar = mTitleBar.getNavigationBar();
- mUrlBarAutoShowManager = new UrlBarAutoShowManager(this);
- }
- }
先从构造方法来看:
构造方法传入了两个参数:第一个是应用的主界面BrowserActivity,第二个是UiController 对象,也就是创建XLargeUi时传入的两个参数。
构造方法中主要完成了如下的事情:
1、通过UiController 对象获取TabControl类型的对象mTabControl 。
2、为BrowserActivity设置视图。查看BrowserActivity的代码,通篇没有找到setContentView的影子,那么它是怎么为activity设置视图的呢?原来是在这里。
- FrameLayout frameLayout = (FrameLayout) mActivity.getWindow()
- .getDecorView().findViewById(android.R.id.content);
- LayoutInflater.from(mActivity)
- .inflate(R.layout.custom_screen, frameLayout);
这里是将资源文件对应的视图加入到android.R.id.content定义的FrameLayout中。这是怎么回事呢?
原来activity中的setContentView如下:
- public void setContentView(int layoutResID) {
- getWindow().setContentView(layoutResID);
- //...
- }
Activity中:
- public Window getWindow() {
- return mWindow;
- }
- mWindow = PolicyManager.makeNewWindow(this);
PolicyManager中:
- public final class PolicyManager {
- private static final String POLICY_IMPL_CLASS_NAME =
- "com.android.internal.policy.impl.Policy";
- private static final IPolicy sPolicy;
- static {
- try {
- Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
- sPolicy = (IPolicy)policyClass.newInstance();
- } catch (InstantiationException ex) {
- throw new RuntimeException( "exception", ex);
- }
- }
- public static Window makeNewWindow(Context context) {
- return sPolicy.makeNewWindow(context);
- }
- }
IPolicy 中:
- public interface IPolicy {
- public Window makeNewWindow(Context context);
- }
Policy中
- public class Policy implements IPolicy
- //...
- public Window makeNewWindow(Context context) {
- return new PhoneWindow(context);
- }
- }
所以Activity的getWindow()获取的是PhoneWindow对象。
而PhoneWindow继承了Window,并覆写了setContentView,PhoneWindow中setContentView(int layoutResID)方法如下:
- @Override
- public void setContentView(int layoutResID) {
- if (mContentParent == null) {
- installDecor();
- } else {
- mContentParent.removeAllViews();
- }
- mLayoutInflater.inflate(layoutResID, mContentParent);
- final Callback cb = getCallback();
- if (cb != null && !isDestroyed()) {
- cb.onContentChanged();
- }
- }
就是将该布局资源文件填入mContentParent,那么mContentParent是什么呢?看下面
- private void installDecor() {
- if (mContentParent == null) {
- mContentParent = generateLayout(mDecor);
- //....
- }
- }
- protected ViewGroup generateLayout(DecorView decor) {
- //...
- ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
- //...
- return contentParent;
- }
由上可知,是由ID为ID_ANDROID_CONTENT的资源文件定义的。
该值由Window类继承而来,看看定义
- public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
mActivity.getWindow()获得一个Window对象,该对象调用getDecorView()找到的android.R.id.content,正是此处的com.android.internal.R.id.content,所以activity的setContentView实际就是将view加入到android.R.id.content定义的ViewGroup中,上面的第二步操作就等价于在BrowserActivity中setContentView。
3、根据BrowserSettings中的配置值设置是否全屏。
4、新建一个TitleBar对象。需要传入的参数是BrowserActivity,UiController,BaseUi,FrameLayout,前两个参数是作为BaseUi构造方法的参数传进来的,第三个是BaseUi本身,第四个参数是布局中的一个FrameLayout。TitleBar对象是手机和平板共有的,而TabBar是平板特有的,故有这样的设计。
5、设置TitleBar中的ProgressBar的最大值为100。这个ProgressBar也就是显示加载网页的进度的。加载时显现,加载完毕时消失。
6、获得NavigationBarBase对象,在平板中获得的是NavigationBarTablet,在手机中获得的是NavigationBarPhone.即导航栏。
7、创建一个UrlBarAutoShowManager对象,该对象用来控制网页滚动过程中显示和隐藏标题栏TitleBar.
回过头来看一下XLargeUi ,我们提到了NavigationBarTablet类型的对象mNavBar和TabBar类型的对象,为什么这两个不在BaseUi里面定义呢?
这是因为这两个是平板界面中特有的,手机界面中不存在。mNavBar在手机界面中是转为NavigationBarPhone类型的,而TabBar是选项卡栏,手机屏幕小,所有没有选项卡栏。
- android原生browser分析(二)--界面篇
- android原生browser分析(二)--界面篇
- android原生browser分析(2)--界面篇
- Android 原生浏览器 (Browser Activity)分析(二)
- android原生browser分析(一)--Application
- android原生browser分析(1)-Application
- Android 原生浏览器 (Browser Activity)分析(一)
- Android Browser App 源码分析(二)
- android源生Browser分析(二)---APP层基本架构
- Android Browser源码分析(二)BrowserActivity初始化
- Android Browser的界面layout
- Android原生应用Dialer--界面和数据库整体分析
- Android——锁定launch - 原生Browser启动 -引导provision
- React native 界面跳转原生Android界面
- Android原生拼音输入法分析
- Android浏览器Browser二次开发(二)支持WML
- Android Browser zoom In/Out 分析
- chromium for android Browser进程结构分析
- C++创建对象的两种方法(C++用new和不用new创建类对象)
- spring mvc注解方式实现向导式跳转页面
- 《NoSQL精粹》读后感(一)
- [Unity3D]蓝港面试题
- 单点登录cas与权限管理框架shiro集成------普通web项目方式
- android原生browser分析(二)--界面篇
- 基于MATLAB GUI的图像处理软件平台的开发(转自深寒的博客)
- [C++]LeetCode: 8 Pascal's Triangle II
- memset的用法
- 实验一:SNMP MIB信息的访问
- 世上最伟大的十个公式
- Github多个SSH key切换管理项目
- spring mvc注入配置文件里的属性
- 高速运放输入问题