理解安卓的视图体系结构

原文链接 理解安卓的视图体系结构

当我们想要写一个页面的时候,通过一个Activity,然后调用其setContentView方法,把一个布局文件当作一个参数传递过去,然后一个页面就好了,但是除此之外,我们还需要与一些组件打交道,比如像Window,WindowManager,那么这些东西到底 与我们的页面布局有什么关系,今天就来学习一下,以便对整体窗口有个更清楚的认知。

布局是一颗View tree

先从一个最简单的例子出发,平时我们写一个页面,都从一个布局文件出发。这其实是在构建一个View tree,为啥一定是tree呢,因为我们的布局文件,无论有多么的复杂,都是从一个根(通常是一个ViewGroup对象)开始的,父布局里面再写子布局,比如这样的:

<LinearLayout id="app_root">
  <TextView id="label"/>
  <Button id="submit"/>
</LinearLayout>

这会形成一个树状结构:

| app_root

   |- label

   |- submit

作为一个开发者,写布局是我们再熟悉不过的了,主要就是用所熟悉的各种Layout和View一起来构建想要的页面。

所写的布局,最终会生成一颗View tree,是一个树状的数据结构,每一个节点都是一个View对象(ViewGroup和View)。因此,布局优化的一个是感觉重要的点就是要先减少View tree的深度(也即平时所说的减少布局的嵌套),再想办法减少广度(减少个数)。

那么,我们写的布局的父布局又是哪里呢?这就又涉及两个东西,一个叫做decorView和contentView的东西。

DecorView与ContentView

我们平常所见的屏幕窗口的根布局是一个叫做DecorView的东西,它是我们通常意义上整个屏幕的根节点,它包含了上面的Status bar和下方的Navigation bar,以及属于应用程序的中间部分。它的源码路径是frameworks/base/core/java/com/android/internal/policy/DecorView.java。它是一个真实的view,它是FrameLayout的子类。

它下面有一个id为android.R.id.content的FrameLayout,我们平时在Activity中调用setContent时所传过去的布局文件所生成的View tree都是添加在这个FrameLayout下面,所以,通常对于我们一个Activity来说,这个FrameLayout是直接意义上的根节点,我们所写的布局都是添加它下面的。

ContentView所引申出来的奇技淫巧

布局优化技巧

首先,一个是布局的优化技巧,可以减少View tree的层级:假如你写的布局中根节点也是一个FrameLayout,那么可以直接用merge节点,把子view全部都直接加挂到前面提到的系统创建的Activity的根布局上面。

<merge>
  <Text />
  <Button />
</merge>

这可以把View tree减少一个层级(深度减1)。

页面内即插即用的弹窗

每个Activity都被回挂在一个id是android.R.id.content的FrameLayout下面,利用这一点,可以做一些即插即用的弹窗,即插即用的意思是,不用写在布局里面,而且显示的时间是不固定的,可能很多时候都不显示,在某个特定的逻辑或者时间才显示。就好比某些电商特定节日的弹窗一样,这种东西,一年也显示不了几回,如果直接添加在布局里面(哪怕你用ViewStub),不够优雅,毕竟不是常规逻辑下会出现的页面,这时可以利用content来做一些即时弹窗:

FrameLayout container = activity.findViewById(android.R.id.content);
View pop = <create or inflate your own view>;
container.addView(pop);

只要你能获得到Activity的实例(这个并不难),那么就可以非常优雅的添加弹窗,逻辑代码和布局文件都会相当独立,甚至可以用插件形式来异步加载。再进一步,如果 添加一个WebView,那么就可以做得更加的前端化,实时化和定制化,好多电商的弹窗就是这么干的。

Window与WindowManager

作为应用开发者,我们看一个View tree其实就是一坨布局,这是站在一个非常小的角度去看的,但如果站在整体系统架构角度来看的话,就会发现应用程序所在的view tree仅是系统可视化窗口架构中的末端,View只是用来构建视图的基本砖块而已。对于整体View tree是如何渲染的,何时渲染,这就涉及到了整体系统架构层面的重量级组件了。

对于现化代的视图窗口架构(Modern GUI),都有一个window server,作来管理视图窗口的核心组件,比如X11,Android当中也不例外。在Android里面,WindowManager就是专门用于管理视图窗口的,它是系统级别的server叫window manager server是一个系统级别的常驻进程,由init.rc启动。而Window则是一个基本的窗口的逻辑上的抽象。关于Window以及WindowManager本身就是相当大的话题,都可以单独写本书,这时不做过多的探讨,对于我们应用开发者来说,了解一下基本的知识就够用了。

每一个Activity,都有一个Window对象,所有一切与GUI有关的事情,都委派给了Window对象,Actvity本身并不参与GUI的具体流程,比如像上面提到的DecorView,ContentView等View tree的构建与管理,View tree的渲染,以及像事件的处理,都是Window对象处理的。Window是WindowManager的基本对象,与其server之间通过IPC通信,Window是供应用程序端使用的,其实真正一切都掌握在window server手中。Activity和Dialog使用的对象都是PhoneWindow,它在frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java,Window对象会具体负责创建像DecorView之类的一些基础设施。最为关键的一个方法就是其PhoneWindow#installDecor()方法,这个方法里面会先调用generateDecor()创建mDecor,它就是前面讲到的DecorView对象,再通过generateLayout()创建mContentParent对象,它就是前面讲到的id是android.R.id.content的那个FrameLayout,Activity或者Dialog通过setContentView送过来的View tree就是加在它的下面的。

WindowManager是一个接口(Android系统的代码接口用的特别多,很多关键的架构层面的组件 都是接口,实际使用的都是其一个实现。)实际使用的是WindowManagerImpl对象,而它也没干啥,它把事情 又委派给另外一个叫做WindowManagerGlobal的对象,这个WindowManagerGlobal则是GUI端的最后一站,它负责与wms(WindowManagerServer)通信。它在frameworks/base/core/java/android/view/WindowManagerGlobal.java

需要注意WindowManagerGlobal是一个单例,也就是说每一个应用程序(严格来说是每一个进程只有一个实例,但安卓上面带有GUI的应用程序只能存活在一个进程,所以可以理解 为一个应用程序)只有一个实例,所以它管理着一个应用程序中的所有的View tree。从它的成员中便可看出,它有一坨ViewRootImpl对象(一个列表),而每一个ViewRoot对象管理着一颗View tree。

最为关键的一个方法就是WindowManagerGlobal#addView,每一个Window的持有者对象(如Activity或者Dialog)都是通过这个方法将其DecorView对象添加给WindowManager的。addView方法,会先创建一个ViewRootImpl对象,然后把要添加的view以及刚创建出来的ViewRootImpl都放进它的列表中,最后再调用ViewRootImpl#setView(view),这就把几大关键对象建立好了连接,接下来的事情就归ViewRootImpl了。这里还有一个相当关键的对象,那就是LayoutParams,WindowManagerGlobal也有一个列表里面存着每个Viewtree根节点(也就是Decor view)的LayoutParams。

ViewRootImpl又是个啥

Window是从手机系统角度来看待的窗口的概念,而View tree则是从应用程序角度构建GUI页面的概念,view tree是Window的一部分,Window对象持有mView,而这个mView就是上面提到的DecorView,也即是View tree的根节点。这里又要涉及另外一个对象ViewRootImpl,它并非是View tree的一部分,虽然名字上比较容易混淆,因为它并不是View的子类,所以它不是任何一个View tree的节点,它的职责是管理View tree,像渲染以及事件派发,都是Window直接通过ViewRootImpl来进行的。在代码中实际使用的是ViewRootImpl对象,它实现了ViewParent接口。

所以,ViewRootImpl对象是值得细细研究的,因为实际上是它在管理着GUI系统–view tree的管理,渲染的三大步(measure, layout和draw)以及事件的派发,最源头的逻辑都在这个对象里面,当然 它也是非常复杂的,源码大概有1万行左右。

ViewParent又是个啥

它是一个接口,行使的职责是管理子View,也就是说在View tree当中管理子View的行为的集合便是ViewParent接口。View tree的节点都是View的子类,所以,你看ViewRootImpl实现了ViewParent接口,它是负责管理Window里面的View tree的。另外一个就是ViewGroup,ViewGroup是View的子类,所以它是Viewtree的一部分,父节点都是ViewGroup,它核心就两样东西一个是子View的列表,另外就是ViewGroup也实现了ViewParent的接口,因为它也要管理它的子节点(也即子View)。

Activity到底是个啥东西

它是系统的四大核心组件之一,如果想构建GUI页面,则Activity是绕不开的。如果再详细一点,Activity是一个系统给你的融合了应用生命周期管理,组件级别复用(Intent相关)和窗口管理的组件,生命周期也即ActivityManager干的事情,它通过Activity的回调告诉你;而GUI则是通过Activity的Window对象帮你实现(Activity的布局和事件的处理都是委派给其持有的Window对象来处理)。

如果,把Activity的Window对象拿掉,那么它跟一个Service组件就基本上没有差别了。如果把Activity的Intent相关拿掉,那么它跟一个Dialog就没啥区别了。

Fragment又是个啥

坦白说,Fragment是Google挖的一个大坑,这玩意儿不符合Android的核心设计思想,因为Android出世的时候并没有它,是后来Google跟水果平台抄来的一个不伦不类的东西,结果全是坑。在它刚出来的一些年,Google极力的推荐使用Fragment,但是近一两年,又不推荐了。

Fragment本质上就是一个强加了生命周期函数回调的View,因为显示Fragmeng时,都是把它替换一个View或者添加到一个ViewGroup上面,所以它就是一个View,或者说一个View tree中的节点。但是强加了生命周期的回调。光是这两点,其实也没有啥,毕竟生命周期对于View是重要的,一般时候我们要在onResume与onPause之间才让View处于active状态。

Fragment最大的问题在于它的异步机制和状态恢复机制,也就是说用FragmentManager#commit了以后,具体啥时候Fragment会真正显示出来,我们是无法控制的,这是相当的坑;它的状态恢复机制就更加的坑,状态恢复这个东西如果全让程序员来负责也还好,就像Activity的设计一样,但是如果框架帮你做了一些事情,但又不完整,这就坑了,关于状态恢复的坑可以参考这篇文章来详细的了解。

DialogFragment

这个本质上是Dialog,但是被包了一层Fragment,所以它会有Fragment的特性,但是Window和View tree则是属于Dialog的。

**注意:**FragmentTransaction#add(Fragment fragment, String tag)有一个方法是不需要提供父布局,这是为没有常规布局准备的,因为无法把布局添加到Activity的现有View tree之中。一般情况下,我们是不会使用这个方法的,目前看仅在DialogFramgment中使用这个方法,那是因为Dialog本身有Window和view tree。

不在Activity view tree里面的窗口控件

一般来讲,我们想要显示的页面都会放进布局里面,也就是说大部分时候我们的页面都由Activity的view tree来实现。但是有些特殊的场景,却不是在view tree里面,比如弹窗,像Dialog,PopupWindow以及Toast,这些东西一般是用于弹出式的页面,由特定的逻辑触发,它与常规页面最为显著的区别就是,它们与Activity的Window和View tree是独立开来的,它们并不是添加在当前Activity的view tree上面的。它们自己有独立的view tree,或者换句话说,它们是独立的Window。

我们这里重点探讨它们与Window和当前Activity之间的关系,至于它们的基本使用方法,可以参阅其他文章。

Dialog

这里不说基本使用方法。

通过查阅源码,可以发现Dialog与Activity的实现相当类似,它内部也有一个独立的Window,也是通过WindowManager#addView把其ContentView(我们提供的布局)加到屏幕上去的。因此,它与Activity也是相互独立的,是两个Window,两棵View tree。Dialog类里面还有getActionBar,OptionsMenu等相关的方法,但似乎在实际使用当中比较少用到。

Dialog最为核心的两个方法一个是其构造方法,这其中会创建Window对象,另外一个就是#show,里面可以看到,它是通过WindowManager#addView()方法,来把它的mDecorView添加到窗口体系当中的,这与Activity其实是一样的。

为啥显示Dialog一定需要Activity,一般Context却不可以

使用过Dialog的人都知道,创建Dialog时一定要传递Activity为其参数,尽管构造方法里面声明的是Context。前面提到,Dialog有自己的Window和View tree,理论上它跟Activity是没有关系的。

如果,用一个非Activity作为Context传给Dialog,报错,是WindowManager抛出来的异常,说:

android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
        at android.view.ViewRootImpl.setView(ViewRootImpl.java:1093)
        at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:409)
        at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:110)
        at android.app.Dialog.show(Dialog.java:342)

而Dialog#setOwnerActivity(Activity)方法在创建Dialog之后再把相关Activity塞过去,也是不行的,必须传入的Context参数要是一个Activity实例才可以。

最初以为,可以从它的构造方法中看出为啥一定需要Activity,就是因为需要theme.但其实并不是,因为theme是可以通过resource id传进去的。

关键点仍在于ViewRootImpl对象,因为这个异常是ViewRootImpl在其setView方法中抛出的,前面讲过,向一个Window添加布局最终会走到WindowManagerGlobal#addView,而它又是通过ViewRootImpl#setView来做具体事情 的,这个方法里面,会先获取当前的WindowSession,然后再把当前的Viewtree转化为窗口对象,添加给wms。所以最核心的地方还得看WindowManagerService#addWindow()这个方法,这个方法也相当之复杂,但是还是能大概看懂它的意思。

通俗的来理解这是安卓系统本身加的限制,也就是说窗口本身也是有逻辑关系的,可以简单理解 为树状关系,一个Activity是主Window,而由此Activity衍生出来的属于此Window的子Window,因此在添加子Window的时候,必须 要知道它从属于哪个父Window,因此,你必须 传Activity实例给Dialog的构造方法,因为只有Activity才是有主Window的。但是这个具体的逻辑连接却比较奇怪,从上面的过程描述来看,WindowManager#addView到ViewRootImpl#setView,其实,都没有明确的把父Window,也就是Activity的Window传进来,那么WindowManagerService又是从哪里去找这个父Window呢?

WindowManagerService#addWindow方法,并没有传递父Window参数 进来,那就只能是它从传进来的参数获得的。这里一个很重要的东西就是token,它是一个IBinder对象,它是一个Window的标识,它存在Window的attris对象里面,这个就是WindowManager#LayoutParams对象,它的作用就是存储Window的特征参数,比如你要改变Window的一些特性(通俗来说就是定制一下Window),那么通过改变LayoutParams,就可以了。这个其实不难理解,我们对View不就是通过其LayoutParams来改变View的特征参数 么。都 是一样的。

Dialog对象在show()时会把其mDecor添加到WindowManagerService中去,其并未传父Window,只传了一个LayoutParams过去,其实玄机也就在LayoutParams之中,窗口的token,父token(标识着父窗口)以及像窗口的type都是在LayoutParams中。那么这个LayoutParams是哪里创建的呢?它是来自于Window对象的,而Dialog的mWindow成员实例是在构造时创建的,创建的是一个PhoneWindow对象,并且把构造Dialog传进来的Context对象传给了PhoneWindow的对象,LayoutParams对象则是通过mWindow.getAttributes()得来的。因此啊,可以断定,PhoneWindow在生成LayoutParams时,会从传给其构造的上下文对象mContext中获取一些信息,如窗口的类型或者父窗口信息,而只有Activity对象才有窗口信息,并且可以作为父窗口,而普通 的Context对象是没有窗口的,由此可以解答我们的疑惑了。

也可以显示独立于任何Activity的Dialog

窗口是有很类型的,WindowManagerService为了方便管理,所以针对Activity及其从属于子窗口(Dialog和PopWindow)做了类似tree结构的逻辑上的整理,所以普通 的Dialog必须要能找到其主窗口(或者叫父窗口)。

但其实,我们经常能见到一些非常牛逼的Dialog,可以显示 在任何Activity之上,如电源没了,或者音量调节,等等。这些是叫作system dialog,需要特殊权限 才能显示出来的。管理来理解,系统级别的组件 才有权限 显示system dialog。

其实,想一想也合理,作为一个应用程序,你在自己的生命周期内,显示内容给用户足够的信息就可以了。当用户离开了你的应用,你也没有必要再显示Dialog了。

:应用在后台时,想在前台显示信息有其他的方式,如Notification等,这属于另外的话题,不做过多讨论。

可以弄个全屏的Dialog吗?

一般来讲呢,Actiivty都是全屏的,Dialog一般是非全屏的,可以把一个Activity弄成非全屏的,长的像Dialog一样,当成Dialog来使用,就在设置Activity的Theme时,用Theme.Dialog就可以了。

那么,反过来搞可不可呢,就是可不可以把常规的Dialog弄成一个全屏的呢?

从Dialog的实现上来看,它有Window对象,甚至连Actionbar和OptionsMenu都有,所以从实现上来看,Dialog并不一定非要像我们平常所使用的那样是一个对话框,它能做的事情 不比Activity少。默认Dialog的style就是一个平常的对话框,但其实,设置不同的style,就可以得到全屏的dialog。

     private void showFullscreenDialog() {
        // Theme_Material_NoActionBar_Fullscreen is real full screen, i.e. hide the status bar.
        Dialog dialog = new Dialog(this, android.R.style.Theme_Material_NoActionBar);
        dialog.setContentView(R.layout.fullscreen_dialog);
        dialog.findViewById(R.id.okay).setOnClickListener(view -> {
            dialog.dismiss();
        });
        dialog.show();
    }

:这里有点歧义,全屏意思是指铺满整个父Activity,严格意义上的全屏是要把状态栏也要隐藏掉。

PopupWindow

PopupWindow是一个独立的类,并不是View的子类,因此,它跟常规的widget不一样,无法直接添加到现有的View tree之中,这也导致它的实现方式比较复杂。

PopupWindow它并没有创建Window对象,但是它有一个类似于Window对象的DecorView的东西,它的根节点是一个叫做PopupDectorView的东西,其实是一个FrameLayout,我们让PopupWindow显示的布局就是加在这个PopupDectorView下面。最重要的两个方法一个是preparePopup() 这个方法会创建根节点PopupDecorView,然后把我们需要显示的mContentView以及还有一个PopupBackgroundView(也是一个FrameLayout,包裹在要显示的ContentView外面),放在PopupDecorView的下面,所以真实的结构是根节点是PoupDecorView,包了PopupBackgroundView,再包上要显示的mContentView,一共三层。

另外,一个方法就是invokePopup,核心逻辑是调用WindowManager#addView,把mDecorView添加到窗口系统中以显示出来,后面的过程跟上面提到的Dialog的显示过程是一样的。那么PopupWindow又是如何找到Activity的主Window的呢?答案还是在LayoutParams中,方法preparePopup()的参数 是LayoutParams,如前面所述LayoutParams是最终会传递给WindowManagerService的,而这里面就包含了主窗口的信息。而这个LayoutParams对象是通过方法createPopupLayoutParams()得来的,而这个方法的参数 是一个IBinder对象,我们知道这个IBinder对象就标识着一个主窗口。那么PopupWindow的IBinder对象又从何而来呢?是通过View.getWindowToken()得来的,PopupWindow的显示 方法都要提供一个View如showAsDropDown,里面的参数是一个View,而这个View必须 是已显示的View tree中的一个节点,现在应该知道一个窗口有一颗View tree,那么此View tree中的节点肯定 知道自己属于哪个窗口啊,由此便找到了主窗口。

另注意,PopupMenu,也是基于PopupWindow的,只不过弄成了Menu的样子(其实就是一个ListView)。

可以弄个全屏的PopupWindow吗?

当然 可以,只需要在构造PopupWindow时传入MATCH_PARENT作为其宽和高就可以了,不过这样做以后后面再选择哪种show方式就不影响了,都是铺满Activity来显示。

     private void showFullscreenPopup() {
        final View content = LayoutInflater.from(this).inflate(R.layout.fullscreen_dialog, null, false);
        PopupWindow popup = new PopupWindow(content, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        final View anchor = findViewById(R.id.fullscreen_popup);
        // Key is the width and height passed to constructor, show does not affect anything.
//        popup.showAtLocation(anchor, Gravity.NO_GRAVITY, 0, 0);
        popup.showAsDropDown(anchor, 100, 200);
        content.findViewById(R.id.okay).setOnClickListener(view -> {
            popup.dismiss();
        });
    }

Toast又是个啥

这个大家都非常熟悉了,每天都用到,用以给出一些非常弱的提示。

它其实也是有独立Window的。Toast类本身比较简单,但它也是有一个专门的Server的叫NotificationManager,Toast也是一个客户端,直接做工作的是另一端的服务,这也是为何即使我们的应用退到了后台依然可以show一个Toast。我们用的最多的就是让其显示一段文字,但其实那只是它的一个非常基础的用法。从Toast的方法就可以看出来,它是可以接受一个View的,所以把一个布局的根节点传进去,那这个布局不就可以显示了么?

Toast可以显示复杂布局吗?

虽然,通常我们都是使用Toast.makeText方法,但这并意味着它只能显示纯文字,它是可发接收一个View作为其Content的,就通过其setView方法:

     private void showComplexToast() {
        Toast toast = new Toast(this);
        final View dialog = LayoutInflater.from(this).inflate(R.layout.fullscreen_dialog, null, false);
        toast.setDuration(Toast.LENGTH_LONG);
        toast.setView(dialog);
        // This does not work, Toast cannot receive focus, i.e. it won't receive events from WMS
        dialog.findViewById(R.id.okay).setOnClickListener(view -> {
            toast.cancel();
        });
        toast.show();
    }

不过呢,虽然Toast可以展示更为复杂的布局,但是它是无法接收用户事件,也就是说它是无法处理点击事件的,你想有用户交互的话,是不可以的。

如此,假如你想显示一个类似Toast的,但是可以交互 的,那只能用PopupWindow或者Dialog来模拟,但这又只能是在应用在前台时显示;假如在后台时,又想要有交互行为,那只能用Notification和PendingIntent了。

综合结论

说了这么多,希望还没有看晕,总结一下:

  1. Window也是有结构 关系的,类似于View一样,像一样tree
  2. 每一个Window都有一颗View tree,DecorView是其根节点
  3. ViewRootImpl是用来管理View tree的
  4. Dialog和PopupWindow可以用以显示铺满Activity,甚至全屏的View
  5. Toast也可以展示复杂布局

实战建议

Activity应该只用于显示一个页面内的主要的,逻辑上都可以触达的布局,比如一上来用户就可见的所有东西,以及常规操作可以触发的(如折叠展开等)。

Activity的View tree要尽可能的小,这样才能保证最好的渲染性能,其余的,很多一次性的,即插即用的,鲜有逻辑才会有触发的,这种布局,要尽可能的独立于Activity的View tree之外,以保证其布局和逻辑上的独立,也更方便维护,更能减少Activity的view tree的体积。因为Dialog和PopupWindow也可以铺满整个Activity,所以,像一些用户引导,新人引导,运营活动,分享,等等一些常规逻辑走不到的页面,都可以考虑用Dialog和PopupWindow来实现。

原创不易,打赏点赞在看收藏分享 总要有一个吧

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
书名:《Android编程入门很简单》(清华大学出版社.王勇)。 压缩打包成2部分,这是第1部分。 本书是一本与众不同的Android学习读物,是一本化繁为简,把抽象问题具体化,把复杂问题简单化的书。本书避免出现云山雾罩、晦涩难懂的讲解,代之以轻松活泼、由浅入深的剖析。这必将使得阅读本书的读者少走弯路,快速上手,从而建立学习Android开发的信心。本书配带1张光盘,收录了重点内容的教学视频(8.7小时多媒体教学视频)和本书涉及的所有源代码。 目录: 第1篇入门必备 第1章初识Android 1.1手机发展简史 1.1.1手机发展的里程碑 1.1.2Android的各个版本 1.2开放手机联盟 1.2.1开放手机联盟的目的 1.2.2分工合作 1.3Android中的个人英雄义 1.3.1第一届挑战赛冠军介绍 1.3.2第二届挑战赛冠军介绍 1.3.3Androidmarket 1.4Android平台 1.4.1Android体系结构 1.4.2熟悉的开发工具 1.4.3合理的学习曲线 1.5小结 第2章搭建你的开发环境 2.1配置前的准备工作 2.1.1 Android支持的操作系统 2.1.2准备“四大法宝” 2.2安装并配置JDK 2.2.1 安装JDK 2.2.2配置JDK 2.3安装并配置Eclipse 2.3.1 运行Eclipse 2.3.2 了解Eclipse 2.4安装并配置Android SDK 2.4.1 下载Android SDK 2.4.2配置SDK 2.5下载ADT 2.5.1 下载ADT 2.5.2 为Eclipse设置SDK路径 2.6新建模拟器 2.6.1 新建AVD 2.6.2运行模拟器 2.7真机测试 2.7.1安装手机驱动 2.7.2设置手机 2.8 小结 第3章创建第一个程序——helloworld 3.1新建第一个程序 3.1.1新建工程 3.1.2运行程序 3.2认识HelloWodd 3.2.1 首识Android工程 3.2.2认识布局文件 3.2.3认识值文件 3.2.4认识R文件 3.2.5认识注册文件 3.3调试程序 3.3.1 增加断点 3.3.2开始调试 3.3.3单步调试 3.4更多示例程序 3.4.1 导入Samples 3.4.2经典范例 3.5 小结 第4章使用Android工具 4.1使用DDMS 4.1.1 认识DDMS 4.1.2使用进程 4.1.3使用文件浏览器 4.1.4使用模拟器控制 4.1.5 使用日志 4.1.6使用Screen Capture捕捉设备屏幕 4.2 使用Android调试桥 4.2.1使用ADB 4.2.2显示连接到计算机的设备 4.2.3针对特定设备操作 4.2.4启动和停止ADB 4.2.5使用ADB操作文件和apk 4.2.6使用ADB shell 4.3 使用AAPT 4.3.1使用ADT导出签名程序 4.3.2使用命令行生成签名apk文件 4.4小结 第2篇界面开发 第5章探索界面ui元素 5.1认识Android视图、Widget以及布局 5.2必须了解的Widget组件 5.2.1 使用可滚动的文本控件——TextView 5.2.2 TextView中的一些功能 5.2.3 使用可滚动的视图——ScrollView 5.2.4文字的编辑 5.2.5 使用按钮——Button 5.2.6实例——计算器 5.2.7 使用图片按钮——ImageButton 5.2.8 使用复选框——CheckBox 5.2.9实例——请同意本协议 5.2.10 使用单选框——RadioGroup 5.2.11 实例——请选择性别 5.2.12使用下拉列表框——Spinner 5.2.13实例——请选择工作年限 5.2.14实例——动态修改Spinner项 5.2.15 使用进度条——ProgressBar 5.2.16实例——动态修改进度条 5.2.17使用拖动条——SeekBar 5.2.1 8实例——简单使用SeekBar 5.2.19使用图片视图——ImageView 5.2.20实例——ImageView的重叠效果 5.2.21 使用网格视图——GridView 5.2.22实例——通过宫格视图展示相应的应用 5.2.23 使用消息提醒——Toast 5.2.24实例——Toast的4种实现 5.3使用列表视图(ListView&ExpandableListView) 5.3.1 使用列表——ListView 5.3.2通过实例学习列表 5.3.3 使用可扩展列表——EXpalldableListView 5.3.4实例——简单使用ExpandableListView 5.3.5实例——深入使用可扩展列表 5.4使用菜单——Menu 5.4.1 Menu的使用 5.4.2通过实例学习使用Menu 5.5小结 第6章使用程序资源 6.1资源的意义 6.1.1什么是资源 6.1.2怎样存储资源 6.I.3怎样添加资源 6.1.4资源的种类 6.1.5怎样访问资源 6.2使用资源 6.2.1 使用资源管理器 6.2.2使用String资源 6.2.3实例——彩虹和太极 6.2.4使用String数组资源 6.2.5使用Color资源 6.2.6使用Dimension资源 6.2.7使用Drawble资源 6.2.8使用样式 6.2.9使用题 6.3 小结 第7章设计界面布局 7.1创建界面 7.1.1 使用xml资源创建布局 7.1.2使用代码创建布局 7.2使用布局类 7.2.1使用绝对布局 7.2.2使用线性布局 7.2.3使用框架布局 7.2.4使用表格布局 7.2.5使用关系布局 7.3使用其他布局容器 7.3.1 使用TabActivity 7.3.2 自定义TabHost 7.3.3 使用对话框 7.3.4使用滑动抽屉 7.4 小结 第3篇功能实现 第8章Android应用程序组成 8.1深入理解Activity 8.1.1使用Intent连接Activity 8.1.2 Activity的生命周期 …… 第9章Android中的数据存储 第10章绚丽的多媒体技术 第11章Android网上冲浪 第12章Android地图服务 第4篇项目案例开发 第13章联系人助手 第14章个人轨迹跟踪器
内容简介   《Android开发入门与实战》内容上涵盖了用Android开发的大部分场景,从Android基础介绍、环境搭建、SDK介绍、Market使用,到应用剖析、组件介绍、实例演示等方面。从技术实现上,讲解了5个Android平台下的完整综合实例及源代码分析,分别是RSS阅读器、基于Google Map的个人GPS、豆瓣网(Web 2.0)客户端、在线音乐播放器、手机信息查看助手。《Android开发入门与实战》注重对实际动手能力的指导,在遵循技术研发知识体系的严密性同时,在容易产生错误、不易理解的环节配以了翔实的开发情景截图,并将重要的知识点和开发技巧以“小实验”、“小提醒”、“小知识”、“注意”等的活泼形式呈现给读者。在程序实例的讲解方面,要将实例安插在Android开发的精髓知识章节,这为初学者学习与实践结合提供了很好的指导。《Android开发入门与实战》配套有400多分钟的全程开发视频光盘,指导读者快速、无障碍地学通Android实战开发技术。《Android开发入门与实战》适合具备一定软件开发经验,想快速进入Android开发领域的程序员;具备一些手机开发经验的开发者和Android开发爱好者学习用书;也适合作为相关培训学校的Android培训教材。 目录 第1章 掀起你的盖头来——初识Android 1.1 认识Android 1.2 Android的背景 1.2.1 Android的历史 1.2.2 Android的发展 1.3 我的Android我做 1.3.1 开发基于Android平台的应用 1.3.2 参加Android开发者大赛 1.3.3 个人英雄义再现——得到更多人的认可和尊重 1.3.4 获得应有的收益——AndroidMarket 1.4 真实体验——Android模拟器 1.4.1 模拟器概述 1.4.2 模拟器和真机的区别 1.4.3 模拟器使用注意事项 1.5 更上一层楼——加入Android开发社区 1.6 本章小结 第2章 工欲善其事 必先利其器——搭建Android开发环境 2.1 开发Android应用前的准备 2.1.1 Android开发系统要求 2.1.2 Android软件开发包 2.1.3 其他注意事项 2.2 Windows开发环境搭建 2.2.1 JDK、Eclipse、AndroidSDK软件安装 2.2.2 SDK的家在哪里——设定AndroidSDKHome 2.2.3 真的准备好了吗——开发环境验证 2.2.4 创建Android虚拟设备(AVD) 2.3 Linux一族——Ubuntu开发环境搭建 2.3.1 Java、Eclipse和ADT插件安装 2.3.2 设定AndroidSDKHome 2.4 MacOS一族——苹果开发环境搭建 2.5 本章小结 第3章 清点可用资本——AndroidSDK介绍 3.1 AndroidSDK基础 3.2 深入探寻AndroidSDK的密码 3.2.1 AndroidSDK目录结构 3.2.2 android.jar及内部结构 3.2.3 SDK文档及阅读技巧 3.2.4 先来热热身——AndroidSDK例子解析 3.2.5 SDK提供的工具介绍 3.3 Android典型包分析 3.3.1 开发的基石——AndroidAPI核心开发包介绍 3.3.2 拓展开发外延——Android可选API介绍 3.4 本章小结 第4章 赚钱的市场——AndroidMarket及应用发布 4.1 GoogleMarket产生背景与目的 4.2 体验“选货”的乐趣——在G1上体验Market的使用 4.3 Android开发活动及特色应用 4.3.1 开发应用的领域 4.3.2 AndroidMarket特色应用一览 4.4 你也可以做东家——申请Market账号 4.4.1 卖东西要先入伙——准备工作 4.4.2 入伙过程——申请 4.5 开张了——在Market上发布应用 4.5.1 发布时可能遇到的错误 4.5.2 卖东西也要签名——生成签名文件 4.5.3 打包、签名、发布应用 4.6 本章小结 第5章 千里之行始于足下——第一个应用HelloWorld 5.1 HelloWorld应用分析 5.1.1 新建一个Android工程 5.1.2 填写工程的信息 5.1.3 编程实现 5.1.4 运行项目 5.2 调试项目 5.2.1 设置断点 5.2.2 Debug项目 5.2.3 断点调试 5.3 本章小结 第6章 磨刀不误砍柴工——Android应用程序结构介绍 6.1 Android体系结构介绍 6.1.1 应用程序(Application) 6.1.2 应用程序框架(ApplicationFramework) 6.1.3 库(Libraries)和运行环境(RunTime) 6.2 Android应用程序组成 6.2.1 Activity介绍 6.2.2 BroadcastIntentReceiver介绍 6.2.3 Service介绍 6.2.4 ContentProvider介绍 6.3 Android应用工程文件组成 6.4 本章小结 第7章 良好的学习开端——Android基本组件介绍 7.1 第一印象很重要——界面UI元素介绍 7.1.1 视图组件(View) 7.1.2 视图容器组件(Viewgroup) 7.1.3 布局组件(Layout) 7.1.4 布局参数(LayoutParams) 7.2 我的美丽我做——Android中应用界面布局 7.2.1 实例操作演示 7.2.2 实例编程实现 7.3 不积跬步无以至千里——常用widget组件介绍 7.3.1 创建widget组件实例 7.3.2 按钮(Button)介绍与应用 7.3.3 文本框(TextView)介绍与应用 7.3.4 编辑框(EditText)介绍与应用 7.3.5 多项选择(CheckBox)介绍与应用 7.3.6 单项选择(RadioGroup)介绍与应用 7.3.7 下拉列表(Spinner)介绍与应用 7.3.8 自动完成文本(AutoCompleteTextView) 7.3.9 日期选择器(DatePicker)介绍与应用 7.3.10 时间选择器(TimePicker)介绍与应用 7.3.11 滚动视图(ScrollView)介绍与应用 7.3.12 进度条(ProgressBar)介绍与应用 7.3.13 拖动条(SeekBar)介绍与应用 7.3.14 评分组件(RatingBar)介绍与应用 7.3.15 图片视图(ImageView)介绍与应用 7.3.16 图片按钮(ImageButton)介绍与应用 7.3.17 切换图片(ImageSwitcher&Gallery) 7.3.18 网格视图(GridView)介绍与应用 7.3.19 标签(Tab)介绍与应用 7.4 友好的菜单——menu介绍与实例 7.4.1 实例操作演示 7.4.2 实例编程实现 7.5 Android应用的灵魂——Intent和Activity介绍与实例 7.5.1 实例操作演示 7.5.2 实例编程实现 7.6 用好列表,做好程序——列表(ListView)介绍与实例 7.6.1 实例程序演示 7.6.2 实例编程实现 7.7 友好地互动交流——对话框(Dialog)介绍与实例 7.8 温馨的提醒——Toast和Notification应用 7.8.1 实例操作演示 7.8.2 实例编程实现 7.9 本章小结 第8章 移动信息仓库——Android的数据存储操作 8.1 Android数据存储概述 8.2 轻轻地我保护——SharedPreferences存储 8.3 谁的文件,谁宰——文件存储 8.4 打造自己的数据库存储——SQLite存储方式 8.4.1 Android中对数据库操作 8.4.2 完整地操作数据库——日记本实例 8.5 我的数据你来用——ContentProvider介绍 8.5.1 初识ContentProvider 8.5.2 使用ContentProvider读取系统数据 8.5.3 使用ContentProvider操作数据日记本实例 8.6 再学一招——网络存储 8.7 本章小结 第9章 我来“广播”你的“意图”——Intent和Broadcast面对面 9.1 Android应用程序的核心——Intent 9.1.1 Intent基础 9.1.2 用Intent启动一个新的Activity 9.1.3 Intent详细讲解 9.1.4 Android解析Intent实现 9.2 用广播告诉你——利用Intent来广播(BroadCast)事件 9.2.1 实现Android中的广播事件 9.2.2 BroadCastReceiver介绍 9.3 应用实例详解 9.3.1 程序操作演示 9.3.2 实例编程实现 9.4 本章小结 第10章 一切为用户服务——Service应用实例 10.1 认识Service 10.2 使用Service 10.3 Service的生命周期 10.4 实例学习Service 10.4.1 精彩实例一——定时提醒 10.4.2 精彩实例二——音乐播放器 10.5 本章小结 第11章 循序渐进——开发Android应用的基本步骤 11.1 兵马未动粮草先行——应用规划及架构设计 11.2 应用开发步骤 11.2.1 界面设计始终是第一位——实现UI 11.2.2 必备的动力源泉——数据操作和存储 11.2.3 华丽转身——实现多页面跳转 11.2.4 始终为用户做好服务——增加Service 11.2.5 细节决定成败——完善应用细节 11.3 成功就在眼前——应用测试和发布 11.3.1只欠东风——应用测试 11.3.2 可以赚钱了——发布到AndroidMarket 11.4 本章小结 第12章 Android综合案例一——RSS阅读器实例 12.1 RSS介绍 12.1.1 RSS基础 12.1.2 RSS的历史 12.1.3 RSS语法介绍 12.2 SAX介绍 12.2.1 SAX基础 12.2.2 使用SAX的作用 12.2.3 怎样使用SAX 12.3 RSS阅读器设计 12.3.1 RSS阅读器功能设计 12.3.2 RSS阅读器UI和交互流程设计 12.4 RSS阅读器的实现 12.4.1 程序实体解析 12.4.2 实现一个自己的ContentHandler 12.4.3 Activity的实现 12.5 本章小结 第13章 Android综合案例二——基于GoogleMap开发个人移动地图 13.1 项目UI规划 13.2 数据存储实现 13.2.1 设计数据库及表结构 13.2.2 设计SharePreference存储 13.3 项目实现流程 13.3.1 创建项目工程 13.3.2 项目各功能及界面实现 13.3.3 实现数据存取 13.3.4 实现Service 13.3.5 应用流程整体实现 13.3.6 后续开发完善 13.4 项目程序演示 13.5 项目程序签名、打包和发布 13.6 本章小结 第14章 Android综合案例三——基于Android的豆瓣网(Web2.0)移动客户端开发 14.1 关于豆瓣网和豆瓣网API 14.1.1 豆瓣网介绍 14.1.2 豆瓣网API介绍 14.1.3 豆瓣网API认证 14.1.4 豆瓣网API快速入门 14.1.5 豆瓣网APIJava库介绍 14.2 豆瓣网(Web2.0)客户端设计 14.2.1 客户端功能规划设计 14.2.2 UI和交互流程设计 14.2.3 数据存储设计 14.3 豆瓣网(Web2.0)客户端实现 14.3.1 申请APIKey 14.3.2 Activity实现 14.4 本章小结 第15章 Android综合案例四——在线音乐播放器 15.1 关于YOBO和YOBOAPI 15.1.1 YOBO简介 15.1.2 YOBO功能特点 15.1.3 YOBOAPI介绍 15.2 在线播放器架构设计 15.2.1 在线播放器功能规划设计 15.2.2 在线播放器UI设计 15.2.3 在线播放器数据存储设计 15.3 在线播放器的编程实现 15.3.1 申请APIKey 15.3.2 基础功能实现 15.3.3 实现Activity 15.3.4 实现Service 15.3.5 后续开发展望 15.4 在线音乐播放器应用演示 15.5 在线音乐播放器应用打包、签名和发布 15.6 本章小结 第16章 Android综合案例五——手机信息查看助手 16.1 手机信息查看助手功能规划和可行性分析 16.1.1 手机信息查看助手功能规划 16.1.2 手机信息查看助手可行性分析 16.2 手机信息查看助手功能实现 16.2.1 手机信息查看助手界面 16.2.2 查看系统信息实现 16.2.3 查看硬件信息 16.2.4 查看软件信息 16.2.5 获取运行时信息 16.2.6 文件浏览器 16.2.7 项目的细节完善 16.3 手机信息查看助手功能展望 16.4 项目的打包、签名和发布 16.5 本章小结 第17章 芝麻开门——Android底层开发和移植概述 17.1 Android原始码下载 17.2 实机测试 17.2.1 NeoFreeRunner介绍 17.2.2 烧录androidfs.jffs2 17.3 Android移植技术概论 17.3.1 Android底层技术的重要性 17.3.2 Android移植项目介绍 17.3.3 Android的技术优点 ·收起全部<< 前言   随着3G的到来,无线带宽越来越高,使得更多内容丰富的应用程序布置在手机上成为可能,如视频通话、视频点播、移动互联网冲浪、在线看书/听歌、内容分享等。为了承载这些数据应用及快速部署,手机功能将会越来越智能,越来越开放,为了实现这些需求,必须有一个好的开发平台来支持,在此由Google公司发起的OHA联盟走在了业界的前列,2007年11月推出了开放的Android平台,任何公司及个人都可以免费获取到源代码及开发SDK。由于其开放性和优异性,Android平台得到了业界广泛的支持,其中包括各大手机厂商和著名的移动运营商等。继2008年9月第一款基于Android平台的手机G1发布之后,预计三星、摩托罗拉、索爱、LG、华为等公司都将推出自Gflg~Android平台的手机,中国移动也将联合各手机厂商共同推出基于Android平台的OPhone。按目前的发展态势,我们有理由相信,Android平台能够在短时间内跻身智能手机开发平台的前列。   由于Android平台被推出的时间才一年左右,了解Android平台软件开发技术的程序员还不多,如何迅速地推广和普及Android平台软件开发技术,让越来越多的人参与到Android应用的开发中,是整个产业链都在关注的一个话题。本书作者较早就从事Android的研究与开发工作,为了帮助开发者更快地进入Android开发行列,他们不辞辛劳地编写了Android开发教程-《Google Android开发入门与实战》。本书系统讲解了Android软件开发的基础知识,图文并茂地帮助读者学习和掌握SDK、开发流程以及常用的API等。书中以讲述实战实例为导向,用一个个典型应用生动地引领读者进行项目开发实践。作为一本既及时、又翔实、理论实践相结合的教程,《Google Android开发入门与实战》一书很值得入门者阅读。   值得一提的是,书中的开发实例很有创意,将传统互联网的内容/服务与移动平台紧密结合起来,如书中的豆瓣网客户端、在线音乐播放器等应用,都体现了移动互联网应用所需的创新精神及良好的用户体验理念,这个设计思路很值得大家去思考和学习。   最后,祝广大开发者的技术日益精进,早日开始Android开发之旅,赶上移动互联网的第一班车,共赢中国3G未来!
内容简介   本书内容上涵盖了用android开发的大部分场景,从android基础介绍、环境搭建、sdk介绍、market使用,到应用剖析、组件介绍、实例演示等方面。从技术实现上,讲解了5个android平台下的完整综合实例及源代码分析,分别是rss阅读器、基于google map的个人gps、豆瓣网(web 2.0)客户端、在线音乐播放器、手机信息查看助手。本书注重对实际动手能力的指导,在遵循技术研发知识体系的严密性同时,在容易产生错误、不易理解的环节配以了翔实的开发情景截图,并将重要的知识点和开发技巧以“小实验”、“小提醒”、“小知识”、“注意”等的活泼形式呈现给读者。在程序实例的讲解方面,要将实例安插在android开发的精髓知识章节,这为初学者学习与实践结合提供了很好的指导。.    本书配套有400多分钟的全程开发视频光盘,指导读者快速、无障碍地学通android实战开发技术。..    本书适合具备一定软件开发经验,想快速进入android开发领域的程序员;具备一些手机开发经验的开发者和android开发爱好者学习用书;也适合作为相关培训学校的android培训教材。... 目录 第1章 掀起你的盖头来——初识android. 1 1.1 认识android 1 1.2 android的背景 2 1.2.1 android的历史 2 1.2.2 android的发展 2 1.3 我的android我做 2 1.3.1 开发基于android平台的应用 3 1.3.2 参加android开发者大赛 3 1.3.3 个人英雄义再现——得到更多人的认可和尊重 3 1.3.4 获得应有的收益——android market 3 1.4 真实体验——android模拟器 4 1.4.1 模拟器概述 4 1.4.2 模拟器和真机的区别 4 1.4.3 模拟器使用注意事项 4 1.5 更上一层楼——加入android开发社区 5 1.6 本章小结 6 第2章 工欲善其事 必先利其器——搭建android开发环境 7 2.1 开发android应用前的准备 7 2.1.1 android开发系统要求 7 2.1.2 android软件开发包 7 .2.1.3 其他注意事项 8 2.2 windows开发环境搭建 8 2.2.1 jdk、eclipse、android sdk软件安装 8 2.2.2 sdk的家在哪里——设定android sdk home 14 2.2.3 真的准备好了吗——开发环境验证 14 2.2.4 创建android 虚拟设备(avd) 15 2.3 linux一族——ubuntu开发环境搭建 17 2.3.1 java、eclipse和adt插件安装 17 2.3.2 设定android sdk home 23 2.4 mac os一族——苹果开发环境搭建 24 2.5 本章小结 24 第3章 清点可用资本——android sdk介绍 25 3.1 android sdk 基础 25 3.2 深入探寻android sdk的密码 25 3.2.1 android sdk目录结构 25 3.2.2 android.jar及内部结构 27 3.2.3 sdk文档及阅读技巧 27 3.2.4 先来热热身——android sdk例子解析 28 3.2.5 sdk提供的工具介绍 31 3.3 android典型包分析 33 3.3.1 开发的基石——android api核心开发包介绍 33 3.3.2 拓展开发外延——android可选api介绍 34 3.4 本章小结 34 第4章 赚钱的市场——android market及应用发布 35 4.1 google market产生背景与目的 35 4.2 体验“选货”的乐趣——在g1上体验market的使用 35 4.3 android开发活动及特色应用 37 4.3.1 开发应用的领域 37 4.3.2 android market特色应用一览 38 4.4 你也可以做东家——申请market账号 43 4.4.1 卖东西要先入伙——准备工作 43 4.4.2 入伙过程——申请 44 4.5 开张了——在market上发布应用 45 4.5.1 发布时可能遇到的错误 45 4.5.2 卖东西也要签名——生成签名文件 46 4.5.3 打包、签名、发布应用 48 4.6 本章小结 51 第5章 千里之行 始于足下——第一个应用helloworld 52 5.1 helloworld应用分析 52 5.1.1 新建一个andr

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值