第二篇 界面开发 (Android学习笔记)

第二篇 界面开发

第5章 探索界面UI元素

The Android View Class

 

 

●△Widget设计步骤

需要修改三个XML,以及一个class

1)第一个xml是布局XML文件(如:main.xml),是这个widget的。一般来说如果用这个部件显示时间,那就只在这个布局XML中声明一个textviewOK了。

2)第二个xmlwidget_provider.xml,主要是用于声明一个appwidget的。其中,Layout就是指定上面那个main.xml

3)第三个xmlAndroidManifest.xml,注册broadcastReceiver信息。

4)最后那个class用于做一些业务逻辑操作。让其继承类AppWidgetProviderAppWidgetProvider中有许多方法,一般情况下我们只是覆写onUpdate(Context,AppWidgetManager,int[])方法。

 

●颜色表达

RGB颜色查询:http://www.atool.org/colorpicker.php

 

 

 

●几个概念的关系

1.widget并不是实际存在的类,它是一个包,而VIew等就是实际存在的类,所以首字母大写。在引用时,通常:

import android.view.View;

import android.widget.TextView;

因为widget是包,所以首字母小写

 

2.在该包内放的是UI Elements, 包括TextView,ListView,但是这些元素都继承自ViewViewGroup。如下图所示:

 

其中各种layout继承自ViewGroup

 

Direct: extend directly from the super class.

Indirect: extend from a super class that directly extends the class in question.

※ 注意ViewGroup的派生类中有几个类和View的几个类重名.

 

 

View对象是Android平台中用户界面体现的基础单位。

This class represents the basic building block for user interface components. A View occupies a rectangular area on the screen and is responsible for drawing and event handling. View is the base class for widgets, which are used to create interactive UI components (buttons, text fields, etc.). The ViewGroup subclass is the base class for layouts, which are invisible containers that hold other Views (or other ViewGroups) and define their layout properties.

 

View派生了TextView, EditText, ScrollView一部分UI组件类, widget(窗口小部件, widget不是类的名称).

View还派生了ViewGroup, ViewGroup类下面AbsoluteLayout, GridLayout, LinearLayout等子类, 它们是容纳、布局各种widget的容器; ViewGroup类下面还有 另一部分UI组件类, ListView这一UI组件:

java.lang.Object

    android.view.View

          android.view.ViewGroup

               android.widget.AdapterView<T extends android.widget.Adapter>

                    android.widget.AbsListView

                         android.widget.ListView

 

android.view和android.widget是两个包;

android.view包 包括View类和ViewGroup(但不包括ViewGroup类的AbsoluteLayout等子类);

android.widget包 包括TextView, EditText, ScrollView, ListViewUI组件类, 以及ViewGroup类的AbsoluteLayout等子类.

 

android.view: Provides classes that expose basic user interface classes that handle screen layout and interaction with the user.

android.widget: The widget package contains (mostly visual) UI elements to use on your Application screen. You can also design your own.

 

●预知 Activity

一个Activity通常就是一个单独的屏幕.

 

Android项目里的proguard.cfg的作用

这是代码混淆用的

代码混淆是为了防止你的apk被反编译而代码全部暴露.不过目前的代码混淆只是把命名修改了一下而已,真正反编译时还是可以想办法还原出来的,所以不能真正的混淆.

 

AndroidMVC模式

MVC模式-- "模型-视图-控制器"模式:

MVC是一种"架构模式"architectural pattern),不是设计模式(design pattern),属于编程的方法论。

1)最上面的一层--"视图层"View--负责给用户提供操作界面,即程序的外壳。

2)最底下的一层--"模型层"Model--负责提供数据(data),或者业务逻辑(business logic)

3)中间的一层--"控制层"Controller--负责根据用户从"视图层"输入的指令,选取"数据层"中的数据,然后对其进行相应的操作,产生最终结果,从而控制用户界面数据显示和更新Model层对象的状态。    

 

A model stores data that is retrieved according to commands from the controller and displayed in the view; also, a model contains business logic.

Business Logic is comprised of Business Rules(业务规则) and Workflow(工作流程).

A view generates new output to the user based on changes in the model.

A controller can send commands to the model to update the model's state (e.g. editing a document). It can also send commands to its associated view to change the view's presentation of the model (e.g. by scrolling through a document).

 

A typical collaboration of the MVC components:

 

MVC的作用:

1、从开发者的角度来说:

MVC 模式不仅实现了功能模块和显示模块的分离,也就是说, 界面设计人员可以直接参与界面开发,程序员就可以把精力集中放在逻辑层和控制层上。

同时它还提高了应用系统的可维护性、可扩展性、可移植性和组件的可复用性

2、从用户的角度来说:

用户可以根据自己的需求,选择自己合适的浏览数据的方式。比如说,对于一篇在线文档,用户可以选择以HTML网页的方式阅读,也可以选择以pdf的方式阅读。

 

Android中界面部分也采用了当前比较流行的MVC框架,在Android中:

1) 模型层(Model--数据和业务逻辑--程序员负责

对数据库的操作、对网络等的操作都应该在Model里面处理,对业务计算等操作也是必须放在的该层的。

2) 视图层(View--UI --界面设计人员负责

一般采用XML文件进行界面的描述。使用的时候可以非常方便的引入。当然,如何你对Android了解的比较的多了话,就一定可以想到在Android中也可以使用JavaScript+HTML等的方式作为View层,当然这里需要进行JavaJavaScript之间的通信,幸运的是,Android提供了它们之间非常方便的通信实现。

3) 控制层(Controller--Activity--让模型层和视图层相分离--程序员负责

Android的控制层的重任通常落在了众多的Acitvity的肩上,这句话也就暗含了不要在Acitivity中写代码,要通过Activity交割Model业务逻辑层处理,这样做的另外一个原因是Android中的Acitivity的响应时间是5s,如果耗时的操作放在这里,程序就很容易被回收掉。

 

AndroidM就是应用程序中二进制的数据,V就是用户界面,CActivity, Activity负责控件的事件绑定以及业务流的程控制。Activity可以有多个界面,只需要将视图的ID传递到setContentView(),就指定了以哪个视图显示模型层中的数据。

 

参考阅读:

MVC (Model-View-Controller):M是指逻辑模型,V是指视图模型,C则是控制器。

一个逻辑模型可以对于多种视图模型,比如一批统计数据你可以分别用柱状图、饼图来表示。

一种视图模型也可以对于多种逻辑模型。使用MVC的目的是将MV的实现代码分离,从而使同一个程序可以使用不同的表现形式。

C存在的目的则是确保MV的同步,一旦M改变,V应该同步更新,这与《设计模式》中的观察者模式是完全一样。

 

Android SDK中的数据绑定,也都是采用了与MVC框架类似的方法来显示数据。在控制层上将数据按照视图模型的要求(也就是Android SDK中的Adapter)封装就可以直接在视图模型上显示了,从而实现了数据绑定。比如显示Cursor中所有数据的ListActivity,其视图层就是一个ListView,将数据封装为ListAdapter,并传递给ListView,数据就在ListView中现实。

 

Android UI开发的三种方法: XML; Java代码; XMLJava代码混合

XML: 比较方便、快捷,但是该方法有失灵活;

Java代码: 虽然比较灵活,但是开发过程比较烦琐;

XMLJava代码混合: 习惯上把变化小、行为比较固定的组件放在XML布局文件中,把变化较多、行为控制比较复杂的组件交给Java代码来管理。

 

●详细理解如下代码

package com.wes.helloworld;

 

import android.app.Activity;

import android.os.Bundle;

 

public class mainActivity extends Activity {

    //重写继承与父类Activity的函数onCreate()

    @Override

    public void onCreate(Bundle savedInstanceState) {

    // Android系统用一个Activity来初始化一个程序

    //这个Activity始于一个onCreate()回调方法

    //Bundle型的savedInstanceState保存了当前Activity的状态信息

    //Bundle类是一个key-value对,类似于Map

 

        super.onCreate(savedInstanceState);

        //调用父类的onCreate()函数

        //之所以要写super,是因为上面有个被重写的父类的onCreate()方法

        //这一条语句用来初始化Activity,即生成一个空白的Activity

        setContentView(R.layout.main);

        //这句话的意思是 设置 这一条语句所在的Activity 采用 R.layout下的main布局文件进行布局

        //对于R.layout.mainlayoutR.java里面的public static final class layout

        //mainlayout类里面的public static final int 类数据成员

    }

}

各种图片, raw资源→布局→代码

一个Activity的基本代码布局

    派生一个Activity{

        声明已经在.xml文件中定义的控件;

        声明本Activity自带的数据(可以从项目的res目录中获得);

        声明用于更新UI界面的Handler;

        protected void onCreate(Bundle savedInstanceState){

            super.onCreate(savedInsatanceState);

            setContentView(R.layout.*);

 

            情况1://如果要下面的代码要操作相关数据, 将获取数据的代码写在这儿

            //不同于第②步中声明的本Activity自带的数据, 这里的数据一般是从其它Activity获得, 或者                是用户自己在本Activity内输入的

            //例如, 要获取其它Activity传来的数据, 可在此获取Inten类对象, 例如:

            Intent intent=getIntent();

            情况2://如果要使用bindService()方法启动Service, 需要在此声明一个ServiceConnection对象

            并将ServiceConnection()这一构造方法里的onServiceDisconnected()onServiceConnected()这两            个回调方法完成

 

            情况1:获取布局中设置的控件(要先在layout里为相关控件赋予R文件里的id, 否则文件源文件                一直出错), 并赋值给第②步中获取的控件;    

            情况2:获取ContentResolver对象

            .(接着, 在获取Uri, 注册ContentObserver,

            并在onCreate()方法之外的区域实现自定义的ContentResolver)

 

            //如果这里获取了一个ListView控件, mListView, 接着创建一个自定义的Adapter类的实例,

             //mAdapter, 然后设置Adapter, 例如mListView.setAdapter(mAdapter);

            //自定义的Adapter类的实现在第⑤步

            //注意, 我们也可能是在某个onCreate()的一个新定义的方法内操作这一步

 

            //如果这里有个initView()方式, 那么事件监听的相关代码、以及对获取并赋值控件的代码在

            onCreate()方法之外的区域里的

            //initView()方法里实现

 

            //最后一般是使用BroadbandcastReceiver4个步骤中的前三步:

            1. 新建一个Intent过滤器

            2. 新建一个BroadcastReceiver

            3. 注册广播接收器

 

            编写与控件相关的监听器内的各种回调函数(onClick())代码;

            //startService(), stopService(), bindService(), unbindService()等服务组件的回调方法在onClick

            //回调函数内实现

        }

        

        //下面都是onCreate()方法之外的区域

        //如果onCreate()onClick()等回调函数的函数体内如果调用了自定义的方法, 可在此具体实现;

        //其它任何具体具体的函数都在此定义

        //使用BroadbandcastReceiver的最后一步: 4. 注销广播接收器

}

//另外注意:

1. ContentResolver可能出现在子线程的某个自定的方法里, 也可能出现在主线程的onClick()等回调方法里;

2. 每启动一个应用进程,都会创建与之对应的ActivityThread类的实例,它是应用程序的UI线程,Android进程启动时会建立消息循环;

3. 子线程一般在onCreate()方法内, 或者是onCreate()里面嵌套的其它方法内创建

4. 一般来说, Activity类不用具体实现构造方法

一个ContentProvider的基本代码布局:

1. 新建一个类,继承自ContentProvider

2. 重写onCreate(), delete(), getType(), insert(), query(), update()等方法, 可增加自定义的方法

  • 在开发中通常使用常量来定义URI,如下面的CONTENT_URI

public static final String AUTHORITY = "com.alexzhou.provider.NoteProvider";

public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/notes");

一个BroadcastReceiver基本代码布局:

1. 新建一个类,继承自BroadcastReceiver类

2. 重写onReceive()方法; 可增加自定义的方法

一个Service基本代码布局:

1. 新建一个类,继承自Service

2. 重写Service的几个重要方法;可增加自定义的方法

 

 

●回调函数()

A callback function is a function which is:

passed as an argument to another function, and,

is invoked after some kind of event.

 

 

当程序跑起来时,一般情况下,应用程序(application program)时常会 通过API 调用库里所预先备好的函数。但是有些库函数(library function)却要求应用先传给它一个函数,好在合适的时候调用,以完成目标任务。这个被传入的、后又被调用的函数就称为回调函数(callback function)。

对于C/C++而言,函数名就是函数的地址,就是函数的指针,不需要在进行取地址操作函数名就是函数的地址,就是函数的指针,不需要在进行取地址操作.

回调函数就是一个通过函数指针调用的函数。

如果你把一个函数指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这个被指向的函数是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

例如:

你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。

上面整个案例是一个主程序(Main program

"通知到货"这个商店提供的服务是库函数(Library function

你的电话号码是回调函数(Callback function这个回调函数的函数体就是让"你"去商店取货

你把电话留给店员就叫登记回调函数(我们还可以登记其它回调函数, 例如微信号,QQ号等)

店里后来有货了叫做触发了回调关联的事件

店员(店员是回调函数的调用者 Caller)给你打电话叫做调用回调函数(不一定要通话)

("你"是事件监听器 Event Listener)到店里去取货叫做响应回调事件

至于我怎么去取货,即我怎么完成电话号码这个回调函数,我可以骑自行车去取,坐出租车去取,或者叫别人去取,这叫重写回调函数

 

店员是调用者他不用在意被调用者(即回调函数)到底是什么, 可以是电话号码, 可以是微信号, QQ号等。如果使用电话号码这个回调函数, 我们就不用老是去问到没到货, 等电话就行了。

可以看到,回调函数通常和应用处于同一抽象层(因为传入什么样的回调函数是在应用级别决定的)。而回调就成了一个高层调用底层,底层再回过头来调用高层的过程。(我认为)这应该是回调最早的应用之处,也是其得名如此的原因。

回调函数不是由程序员主动在程序中指定函数名来调用, 而是由系统根据某些特定条件的触发(例如点击). Android系统决定调用对应的回调函数, 实行对应的功能.

typedef void (*CALLBACK)(int a,int b)

定义一个函数指针CALLBACK,它返回void类型,有两个参数,分别为,a,b.

callback的几种解释:

A "callback" is any function that is called by another function which takes the first function as a parameter. A lot of the time, a "callback" is a function that is called when something happens. That something can be called an "event" in programmer-speak(程序员说的"事件").

 

A callback is a piece of executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at some convenient time. The invocation may be immediate as in a synchronous callback, or it might happen at a later time as in an asynchronous callback.

//请看下面的伪代码

// The callback method

function meaningOfLife() 

{

log("The meaning of life is: 42");

}

 

 

// A method which accepts a callback method as an argument

// takes a function reference to be executed when printANumber completes

function printANumber(int number, function callbackFunction)

{

print("The number you provided is: " + number);

}

 

// Driver method

function event() //例如在Android, 由于触摸(Touch)而触发的事件会使回调函数被调用

{

printANumber(6, meaningOfLife);    

    //C语言中, A函数做B函数的参数的方法是定义A函数的函数指针

}

 

●为什么要用回调函数?

因为可以把调用者与被调用者分开。调用者不关心谁是被调用者,所有它需知道的,只是存在一个具有某种特定原型、某些限制条件(如返回值为int)的被调用函数。

如果想知道回调函数在实际中有什么作用,先假设有这样一种情况,我们要编写一个库,它提供了某些排序算法的实现,如冒泡排序、快速排序、shell排序、shake排序等等,但为使库更加通用,不想在函数中嵌入排序逻辑,而让使用者来实现相应的逻辑;或者,想让库可用于多种数据类型(intfloatstring),此时,该怎么办呢?可以使用函数指针,并进行回调。

回调可用于通知机制,例如,有时要在程序中设置一个计时器,每到一定时间,程序会得到相应的通知,但通知机制的实现者对我们的程序一无所知。而此时,就需有一个特定原型的函数指针,用这个指针来进行回调,来通知我们的程序事件已经发生。实际上,SetTimer()API使用了一个回调函数来通知计时器,而且,万一没有提供回调函数,它还会把一个消息发往程序的消息队列。

另一个使用回调机制的API函数是EnumWindow(),它枚举屏幕上所有的顶层窗口,为每个窗口调用一个程序提供的函数,并传递窗口的处理程序。如果被调用者返回一个值,就继续进行迭代,否则,退出。EnumWindow()并不关心被调用者在何处,也不关心被调用者用它传递的处理程序做了什么,它只关心返回值,因为基于返回值,它将继续执行或退出。

 

  • 更接近问题本质的答案:

根据面向对象设计的封装性要求,模块间要解耦,模块内要内聚.

 

  • Android, 回调函数实际上就起到了消息循环的作用,因为在SDK中只有通过回调函数来发送各自的处理消息.

 

Callback最本质的特征包括两点:注册和触发

Callback函数是你提供给系统调用的函数。很多情况下,系统某个情况下,定义需要执行某个操作,而操作本身由有用户的程序来提供,这时,就要用到回调函数了。所以,简单地说。回调函数,就是你写一个函数,在系统定义的地点提供给系统调用。

 

C语言回调函数案例

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

/* callback.c */

#include<stdio.h>

#include"reg_callback.h"

   

/* callback function definition goes here */

void my_callback(void)

{

printf("inside my_callback\n");

}

   

int main(void)

{

/* initialize function pointer to

my_callback */

callback ptr_my_callback=my_callback;

printf("This is a program demonstrating function callback\n");

/* register our callback function */

register_callback(ptr_my_callback);

printf("back inside main program\n");

return 0;

}

1

2

3

/* reg_callback.h */

typedef void (*callback)(void);

void register_callback(callback ptr_reg_callback);

1

2

3

4

5

6

7

8

9

10

11

/* reg_callback.c */

#include<stdio.h>

#include"reg_callback.h"

   

/* registration goes here */

void register_callback(callback ptr_reg_callback)

{

printf("inside register_callback\n");

/* calling our callback function my_callback */

(*ptr_reg_callback)();

}

This is a program demonstrating function callback

inside register_callback

inside my_callback

back inside main program

 

JAVA中不允许直接操作指针,那它的回调是如何实现的呢?

答案:它是通过接口或者内部类来实现的。

 

JAVA方法回调是功能定义和功能实现分享的一种手段,是一种耦合设计思想。作为一种架构,必须有自己的运行环境,并且提供用户的实现接口。

1. 定义接口 Callback ,包含回调方法 callback()
2.
在一个类Caller 中声明一个Callback类型的引用变量(不是接口对象) mCallback
3.
在程序中赋予 Caller对象的接口成员(mCallback) 一个内部类对象如
interface Callback(){
    callback
(){
    //
函数的具体实现
    }
}

 

Class Caller{

    Callback mCallback;

}

 

这样,在需要的时候,可用Caller对象的mCallback接口成员 调用callback()方法,完成回调。

接口是不能实例化,但是,接口可以声明引用变量。

接口的引用可以指向凡是实现了该接口的类的实例(多态)。

下面的语句并非直接实例化接口, 因为new Runnable(){}中的花括号里面具体实现了接口的方法:

Runnable task = new Runnable() {

    public void run() {

    

    }

};

 

●监听器

A、什么是监听器?

您需要记住以下几点:

1监听器实际上是一个接口,它包含了一个事件触发时系统会去调用的回调函数

2、在实现接口的类中,根据您项目的需要重写这个回调函数

3、派生后的监听器需要绑定到按钮上,就像一个耳机可以发出声音,但您不去戴它,您是听不到它发出的声音的。一般的情况是这个按钮可能需要这个监听器,而另外一个按钮需要另外一个监听器,每个监听器各司其职,但功能相似时,也可以多个按钮共同绑定一个监听器。

4、各种控件,都有常用的事件,如点击按钮,拖动一个滚动条,切换一个ListView的选项等等,它的绑定监听器的函数命名规则是setOn****Listener

 

B、为控件绑定监听器主要分为以下步骤:

① 获取代表控件的对象

② 定义一个类,实现监听器接口

③ 生成监听器对象

④ 为控件绑定监听器对象

 

Android程序中,设置View点击事件监听共有四种

1)在布局文件中为控件设置onClick属性指定点击方法;

2)创建一个内部类实现OnClickListener接口并重写onClick()方法,

之后需要为控件设置setOnClickListener(Listener listener)

3)主类中实现OnclickListener接口,然后重写onClick()方法;

4)创建匿名内部类,即在为控件设置监听时直接创建一个

OnClickListener实例,不为该实例指定名称。

 

以"用户触碰(touch)"这一动作來說,当组件要处理用户触碰的事件时,组件作为事件源要注册一个事件监听器对象,即:

void setOnClickListener(View.OnClickListener l) //注册单击事件

再如:

void setOnLongClickListener(View.OnLongClickListener l)    //注册长按事件

void setOnKeyListener(View.OnKeyListener l)    //注册键盘事件

void setOnFocusChangeListener(View.OnFocusChangeListener l)    //注册焦点改变事件

void setOnTouchListener(View.OnTouchListener l)        //注册触摸事件

void setOnCreateContextMenuListener(View.OnCreateContextMenuListener l)    //注册上下文菜单事件当这样当"touch"事件发生时,Android框架便回调事件监听器里的回调函數。

 

View.OnClickListener是click listener,即UI控件的Click动作监听器;当用户对View进行Click操作时(即触控上的UI组件),Android框架便会回调这个View.OnClickListener的回调函數,即onClick()

  • 另外一种UI事件的机制为事件处理器(event handler),event handler与event listener是不一样的处理机制,下文会讲到。

 

●View与ViewGroup触摸事件传递机制

触摸事件有:ACTION_DOWN, ACTION_MOVE, ACTION_UP 。一个简单的触摸动作触发了一系列Touch事件,如:

 

1ACTION_DOWN -> ACTION_MOVE->..-> ACTION_MOVE-> ACTION_UP

 

2ACTION_DOWN -> ACTION_UP

 

TouchEvent发生时,首先ActivityTouchEvent传递给最顶层的ViewTouchEvent最先到达最顶层ViewdispatchTouchEvent,然后由dispatchTouchEvent方法进行分发,如果dispatchTouchEvent返回TRUE,则交给这个ViewonTouchEvent处理;如果dispatchTouchEvent返回false,则交给这个ViewOninterceptTouchEvent方法来决定是否要拦截这个事件,如果OninterceptTouchEvent返回true,也就拦截了,则交给它的onTouchEvent来处理;如果OninterceptTouchEvent返回false,那就传递给子View,由子ViewdispatchTouchEvent再来开始这个事件的分发,如果事件传递到某一层ViewonTouchEvent了,这个方法返回false,那么这个事件从这个View往上传递,都是onTouchEvent来接收,而如果传递到onTouchEvent返回是false,这个事件"消失",而且接收不到下一次事件。

 

其分发和传递的过程如下:

 

 

 

●There are following three concepts related to Android Event Management

(Android事件管理的3种机制)

  • Event Listeners (事件监听器)− An event listener is an interface in the View class that contains a single callback method. These methods will be called by the Android framework when the View to which the listener has been registered is triggered by user interaction with the item in the UI.
  • Event Listeners Registration (事件监听器注册)− Event Registration is the process by which an Event Handler gets registered with an Event Listener so that the handler is called when the Event Listener fires the event.
  • Event Handlers (事件处理器)− When an event happens and we have registered an event listener for the event, the event listener calls the Event Handlers, which is the method that actually handles the event.

 

(不用掌握, 掌握书上的方法即可)为控件绑定监听器主要分为以下步骤:

1、获取代表控件的对象

2、生成监听器对象

3、为控件绑定监听器对象

4、定义一个类,实现监听器接口

protected void onCreate(Bundle savedInstanceState) {


										super.onCreate(savedInstanceState);

       setContentView(R.layout.activity_main);

       textView =(TextView)findViewById(R.id.textView);

       textView.setText("set text success");


											//1.获取代表控件的对象
										

       button =(Button)findViewById(R.id.button);


											//2.生成监听器对象
										

       ButtonListener buttonListener =new ButtonListener();


											//3.为控件绑定监听器对象
										

       button.setOnClickListener(buttonListener);

    }

 


											//4.定义监听类,实现监听器接口
										

 class ButtonListener implements OnClickListener{ 

 

    @Override


										public void onClick(View arg0) { 


										// TODO Auto-generated method stub
											

         textView.setText("onclick ok");

    }

 

 }

 

●接口与内部匿名类

接口不能实例化,但是接口类型的引用变量可以引用一个实现了接口的类的对象.

 

接口 对象=new 接口的实现类()

 

//这里可以使用匿名内部类实现接口

(new 接口(){

//实现方法

});

//其中, FilenameFilter是一个接口, 上面实现的是FilenameFilter接口的匿名内部类, 并不是FileNameFilter的实例化.

 

该代码等效于

class A implements FileNameFilter{    //这里给上面的匿名内部类起了个名字A

    public void accept(File f,String s)

    {

        //实现了accept()这个回调函数

    }

}

 

dir.list(new A())

 

●问题

设有下面两个赋值语句:

a = Integer.parseInt("123");

b = Integer.valueOf("123").intValue();

下述说法正确的是( d )。

A、a是整数类型变量,b是整数类对象。

B、a是整数类对象,b是整数类型变量。

C、ab都是整数类对象并且值相等。

D、ab都是整数类型变量并且值相等。

注意, 如果b = Integer.valueOf("123").intValue();中没有intValue(), 那么a是基本数据类型int, bInteger包装类类型.

 

Integer.valueOf() 和 String.valueOf()

既有Integer.valueOf()函数, 也有String.valueOf()函数

 

●为什么定义在类头上的控件变量需要是final

因为在安卓中 很多监听器以内部类的形式去访问定义在类头上的控件(如一个Button)变量,这就形成了内部类与外部类变量的访问;注意,这里的控件变量需要加final关键字 。

因为如果不加final,那个变量的生命将在方法结束时结束,但那个匿名内部类的对象仍然存在,它就需要访问一个已经不存在了的变量。加了final后生命周期延长,就不会有这个问题了。

 

GridViewListView

 

MainActivity.this 和直接用 this有区别吗?

MainActivity.this表示的就是MainActivity这个类对象本身,这种写法一般用在内部类里,因为在外部类中直接可以用关键字this表示本类,而内部类中直接写this的话表示的是内部类本身,想表示外部类的话就得加上外部类的类名.this

※ 对于包含内部类的类来说,它就是其内部类的外部类。

 

具体来说, 某个控件 setOnClickListener(); 在括号里面new 一个OnClickListener (这就创建了上面说的内部类),然后在onClick方法里面处理的时候必须要用MainActivity.this 而不能用this

 

※ 下面有关风格和主题的讲述比较杂乱

Android应用开发中的风格和主题(style,themes)

风格和主题都是资源, 存放在res/values 文件夹下,你可以用android提供的一些默认的风格和主题资源,你也可以自定义你自己的主题和风格资源。

如何新建自定义的风格和主题:

1. 在res/values 目录下新建一个名叫style.xml的文件。增加一个<resources>根节点。

2. 对每一个风格和主题,给<style>element增加一个全局唯一的名字,也可以选择增加一个父类属性。在后边我们可以用这个名字来应用风格,而父类属性标识了当前风格是继承于哪个风格。

3. 在<style>元素内部,申明一个或者多个<item>,每一个<item>定义了一个名字属性,并且在元素内部定义了这个风格的值。

4. 你可以应用在其他XML定义的资源。

 

Android提供的默认的主题样式

Android的Style设计就是提升用户体验的关键之一。Android上的Style分为了两个方面:

1,Theme(主题)是针对窗体级别的(Activity),用来改变窗体样式;

2,Style(风格)是针对窗体元素级别的,改变指定控件或者Layout的样式。

 

Android系统的themes.xmlstyle.xml(位于系统源代码frameworks\base\core\res\res\values\)包含了很多系统定义好的style,建议在里面挑个合适的,然后再继承修改。

比如说android:theme="@android:style/Theme.Dialog"可以让你的Activity变成一个窗口风格,

android:theme="@android:style/Theme.Light"则让你的整个Activity具有白色的背景,而不是黑色那么沉闷。

详见:http://www.cnblogs.com/SharkBin/p/3596525.html

 

具体使用方法很简单, Androidmanifest.xml文件中对你的Activity节点上加入些代码,如下图所示:

 

●△引用主题属性:

另外一种资源值允许你引用当前主题中的属性的值。这个属性值只能在样式资源和XML属性中使用;它允许你通过将它们改变为当前主题提供的标准变化来改变UI元素的外观,而不是提供具体的值。

 

android:textColor="?android:textDisabledColor"

 

当你使用这个标记时,你就提供了属性资源的名称,它将会在主题中被查找--因为资源工具知道需要的属性资源,所以你不需要显示声明这个类型(如果声明,其形式就是?android:attr/android:textDisabledColor)。除了使用这个资源的标识符来查询主题中的值代替原始的资源,其命名语法和"@"形式一致:?[namespace:]type/name,这里类型可选。

 

The question mark means it's a reference to a resource value in the currently applied theme.(问号的意思是它是当前被应用的主题中的资源值的引用)

 

●适配器 Adapter

Android适配器是数据和视图之间的桥梁,可以看作是将界面和数据绑定的工具,以便于数据在视图上显示。我们常用的适配器一共有三个:ArrayAdapterSimpleAdapterSimpleCursorAdapter 这三个,他们都是继承于BaseAdapter

 

 

※ 现实中的适配器有很多, 如显卡(Video cardGraphics card/显示适配器。

 

ArrayAdapter的第二个参数还有如下几个参数可以设置

  • 1)android.R.layout.simple_list_item_1:由文字组成的列表项。
  • 2)android.R.layout.simple_list_item_2:由稍大的文字组成的列表项。
  • 3)android.R.layout.simple_list_item_checked:由CheckBox组成的列表项。
  • 4)android.R.layout.simple_list_item_multiple_choice:有多选框组成的列表项
  • 5)android.R.layout.simple_list_item_single_choice:有单选框组成的列表项。

 

●Android系统中提供了两种图片浏览方式

图片浏览器是智能设备中使用非常广泛的组件,Android系统中提供了两种图片浏览方式,

① 最为普通的ImageView浏览,

② 使用GridView实现网格式的图片浏览,

 

 

 

 

 

 

 

第6章 使用程序资源

●资源(

Resources

本质上, 资源是一种共享、反复利用元素、属性的机制(mechanism)

 

●资源的图示

 

资源类型

文件夹名称

文件名

字符串

/res/values/

strings.xml

字符串数组

/res/values/

arrays.xml

颜色

/res/values/

colors.xml

样式

/res/values/

styles.xml

主题

/res/values/

themes.xml

图片

/res/drawable/

*.png*.jpg*.gif

布局

/res/layout/

mylayout.xml

动画

/res/anim/

*_anim.xml

菜单

/res/menu/

menu1.xml

原始文件

/res/raw/

audio.mp3video.mp4

XML文件

/res/xml/

自定义的xml文件

 

 

"@+id/""@type/name""@+android:id/title "

一、引用自定义资源

1.引用自定义资源。格式:@[package:]class/name

例如:

android:text="@string/hello"

android:layout_toRightOf="@id/btnLogin"

注:idR.java里也是一种class

 

@表示对资源的引用,package是包名,如果在相同的包内,则包名可以省略。

"@string/hello"的意思是引用在strings.xml里面定义的字符串,属性(引用变量)为hello,值(引用变量指向的对象)为Hello World

 

2.引用系统资源。格式:@android:type/name

android:textColor="@android:color/opaque_red"

 

二、 新建一个资源id

<EditText

android:id="@+id/edit"

.../>

edit这个id代表EditText这个UI控件,系统会在R.java文件中自动生成int edit = 十六进制的value

我们可以在Java代码中使用edit这个id,例如:

EditText et=(EditText)findViewById(R.id.edit);

//id是R.java文件里的,即public static final class idedit是这个类的成员。

加上android:表示引用android.R.id里面定义的id资源,如果android.R.id里面确实有title这个id资源,就直接使用它,如果没有的话就在当前应用的R.id中产生一个title标识.

 

※ 但是现在我发现apps/settings/res/layout/preferenc_progress.xml中有个"@+android:id/title",怎么理解它?

"@+android:id/title"表示在系统的R.java文件中自定义一个名为titleid

 

再如:

系统布局文件是:android.R.layout.xxx;

而用户自定义布局文件是:R.layout.xxx;

 

id是控件的一个基本属性,这并不代表每个控件的id都不一样,其实控件的id属性是可以相同的

所有的控件被加载到内存以后就会形成一个控件树形结构,当查找控件的时候,只返回第一个id匹配的控件,所以如果一个页面中有相同id的控件,比如ListViewitem,当查找控件的时候要从它最邻近的一个父节点开始查找,这样才会命中.

 

res/rawassets

res/raw和assets的相同点:

两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制。


res/raw和assets的不同点:
1.
 res/raw中的文件会被映射到R.java文件中,访问的时候直接使用资源ID

即R.类名.数据成员名

//类名如:attr, color, drawable, id, layout, raw, string

//(有的类名采用的是文件夹名,如res/layout/, 有的类名采用的是.xml文件里面的标签名,如res/values/.strings.xml文件里的string标签名)

assets文件夹下的文件不会被映射到R.java中,访问的时候需要AssetManager类。
2.res/raw
不可以有目录结构,而assets则可以有目录结构,也就是assets目录下可以再建立文件夹

 

3.读取文件资源的方式

①读取res/raw下的文件资源,通过以下方式获取输入流来进行写操作

  1. InputStream is = getResources().openRawResource(R.类名.数据成员名);

②读取assets下的文件资源,通过以下方式获取输入流来进行写操作

  1. AssetManager am = null;
  2. am = getAssets();
  3. InputStream is = am.open("filename");

 

补充一下:在未知目录下有一些文件,那么该怎么获取这些文件的名称并把文件拷贝到目标目录中呢?(用于内置文件但不知道文件名称,需要筛选出想要的文件然后拷贝到目标目录中,推荐内置在assets文件夹中)
1.res/raw
目录:
通过反射的方式得到R.java
里面raw内部类里面所有的资源ID的名称,然后通过名称获取资源ID的值来读取我们想要的文件。(这个方法我没试过,有用过的同学麻烦发一段代码看看)。
2.assets
目录:
getAssets().list("");
来获取assets目录下所有文件夹和文件的名称,再通过这些名称再读取我们想要的文件。

 

raw目录先放置一个MP3文件

 

R.java文件与res文件的对应关系:

除了string.xml, res/value/文件下可能包含的xml文件:

arrays.xml for resource arrays, and accessed from the R.array class.

integers.xml for resource integers, and accessed from the R.integer class.

bools.xml for resource boolean, and accessed from the R.bool class.

colors.xml for color values, and accessed from the R.color class.

dimens.xml for dimension values, and accessed from the R.dimen class.

strings.xml for string values, and accessed from the R.string class.

styles.xml for styles, and accessed from the R.style class.

没有保存,系统不会知道你已经添加了新控件,新资源,

因此,在每次添加新资源或者更改内容后,ctrl+s保存一下,R.java才会自动生成相关代码

 

Android中度量单位含义

dip: device independent pixels(设备独立像素). 不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGAHVGAQVGA 推荐使用这个,不依赖像素。

dp: 和dip是一样的

px: pixels(像素). 不同设备显示效果相同,一般我们HVGA代表320x480像素,这个用的比较多。

pt: point,是一个标准的长度单位,1pt1/72英寸,用于印刷业,非常简单易用;

sp: scaled pixels(放大像素). 主要用于字体显示best for textsize

in(英寸):长度单位。

mm(毫米):长度单位。

 

分辨率可以从显示分辨率与图像分辨率两个方向来分类。

显示分辨率(屏幕分辨率)是屏幕图像的精密度,是指显示器所能显示的像素有多少。

图像分辨率则是单位英寸中所包含的像素点数,其定义更趋近于分辨率本身的定义。

单位

标记

说明

毫米

mm(milli meters)

实际的物理测量单位,在屏幕上以毫米为单位显示

英寸

in(inch)

实际的物理测量单位,在屏幕上以英寸为单位显示,1英寸约为2.54厘米

像素

px(pixels)

像素是构成数码影像的基本单元,通常以像素每英寸PPI(pixels per inch)为单位来表示影像分辨率的大小。

pt(point)

实际的物理测量单位,1点等于1/72英寸,常用于印刷业

密度独立像素

dp(density independed pixels) 

虚拟像素,也就是说每个设备都有其独立的像素。

1dp=1*像素密度/160=实际像素数

例如:一个手机的像素密度为230dpi(严格来说是ppi),那么1dp=1sp=1*320/160=2px.

刻度独立像素

sp(scale independed pixels)

虚拟像素,实际长度与dp相同,只是常被用于字体的显示,Android字体大小默认单位为sp

 

ppiPixel Per Inch每英寸像素数):指每英寸屏幕的像素密度

 

dpi(Dot Per Inch,每英寸点数):指每英打印的点密度

 

如果你以600dpi打印一张150ppi的照片,那么每个像素包含16个点。(600 dots/150 "pixels" = 4 rows of 4 dots per "pixel").

Android而言,dpi等价于ppidpi最早是用于印刷行业,跟PPI还是有本质不同的,Android应该是误用了DPI这个概念。

 

屏幕尺寸是手机屏幕对角线的长度

 

例如:华为荣耀7的配置如下:

屏幕像素密度=(√1920^2+1080^2)÷5.2424ppi

 

一个像素的尺寸是可变的,屏幕密度有关:

如果像素密度为72ppi,那么每英寸里有72个像素,每像素就是1/72英寸;

如果屏幕精度为300ppi,每像素就是1/300英寸了;

在同样尺寸下,例如都是5厘米,300ppi精度的更清晰

 

分辨率可以从显示分辨率与图像分辨率两个方向来分类。

显示分辨率(屏幕分辨率)是屏幕图像的精密度,是指显示器所能显示的像素有多少。

图像分辨率则是单位英寸中所包含的像素点数,其定义更趋近于分辨率本身的定义。

 

精度/分辨率(resolution)是水平像素数*垂直像素数,常见的Android手机分辨率如下:

VGA(Video Graphics Array,即视频图形阵列):480*640,标准的视频接口分辨率

QVGA(Quarterly~):240*320,只有VGA的四分之一

HVGA(Half~):480*320,只有VGA的二分之一,使用的比较少了,开发使用

WVGA(Wide~):480*800

FWVGA(Full Wide~):480*854

 

※ 像素是Android屏幕显示的默认单位,

 

 

●为什么Androidres文件夹要分别存放mdpildpihdpi文件?

在之前的版本中,只有一个drawable

而从2.1版本以后,res中开始有drawable-mdpidrawable-ldpidrawable-hdpi三个,

这三个主要是为了支持多分辨率。

drawable- hdpi、drawable- mdpidrawable-ldpi的区别:

(1)drawable-hdpi里面存放高分辨率的图片,WVGA (480x800),FWVGA (480x854)分辨率的机型;

(2)drawable-mdpi里面存放中等分辨率的图片,HVGA (320x480) 分辨率的机型;

(3)drawable-ldpi里面存放低分辨率的图片,QVGA (240x320) 分辨率的机型;

系统会根据机器的分辨率来分别到这几个文件夹里面去找对应的图片。

 

 

具体来说:

ldpi 120dpi以下

mdpi 120dpi ~ 160dpi

hdpi 160dpi ~ 240dpi

xhdpi 240dpi ~ 320dpi

xxhdpi 320dpi ~ 480dpi

xxxhdpi 480dpi ~ 640dpi

 

不同分辨率的图片可同名, 例如:

Android系统定义了四种像素密度:低(120dpi)、中(160dpi)、高(240dpi)和超高(320dpi),它们对应的dppx的系数分别为0.7511.52,这个系数乘以dp长度就是像素数。

例如界面上有一个长度为"80dp"的图片,那么它在240dpi的手机上实际显示为80x1.5=120px,在320dpi的手机上实际显示为80x2=160px

如果你拿这两部手机放在一起对比,会发现这个图片的物理尺寸"差不多",这就是使用dp作为单位的效果,见下图:

 

●对于不同像素密度的图片,Android系统给定了其对应比例和倍数如下

分类目录

ldpi

mdpi

hdpi

xhdpi

xxhdpi

xxxhdpi

密度(dpi)

~160

~240

~320

~480

~640

  

图片比例

1.5

2

3

4

6

8

倍数

0.75x

1x

1.5x

2x

3x

4x

 

 

 

●不同分辨率手机的比例调查(201211月数据)

 

ldpi

mdpi

hdpi

xhdpi

  

Pequeña

1,7%

 

1%

 

xxhdpi

xxxhdpi

Normal

0,4%

11%

50,1%

25,1%

~640

 

Grande

0,1%

2,4%

 

3,6%

6

8

Extra grande

 

4,6%

  

3x

4x

 

 

 

Java中方法调用方法

例如: f.getToolkit().getScreenSize()

f.getToolkit()得到一个Toolkit对象

f.getToolkit().getScreenSize() 是Toolkit对象调用getScreenSize(),这个方法是有返回值的。

 

 

 

 

 

 

 

第7章 设计界面布局

The ViewGroup is the base class for layouts and views containers.

我们经常编写Layout文件,通过Layout文件我们可以看到所有的View在界面上均占有一矩形区域,而我们可以把这种矩形区域(View)大致分为两类,即:

① 单一的矩形区域(View),

② 包含有小矩形区域的大矩形区域(ViewGroup)

这种大小矩形相套的格局自顶向下形成一种树形结构,我们可以将其称为View.

下图是简略的View树:

 

 

The standard Layouts (标准布局类):

Layout

Description

LinearLayout

(Horizontal)

(Vertical)

LinearLayout is a view group that aligns all children in a single direction, vertically or horizontally.

RelativeLayout

RelativeLayout is a view group that displays child views in relative positions.

相对布局通常有两种形式,一种是相对于容器而言的,一种是相对于控件而言的。

TableLayout

TableLayout is a view that groups views into rows and columns.

GridLayout

GridLayout uses a grid of infinitely-thin lines to separate its drawing area into: rows, columns, and cells. It supports both row and column spanning, which together allow a widget to occupy a rectangular range of cells that are next to each other.

FrameLayout

The FrameLayout is a placeholder on screen that you can use to display a single view.

AbsoluteLayout

AbsoluteLayout enables you to specify the exact location of its children. Arrange the children views according coordinates x, y.

 

relative layout

 

TableLayout GridLayout

有了TableLayout又搞个GridLayout的原因如下:

1. TableLayout不能同时向水平和垂直方向做控件的对齐

TableLayout继承了LinearLayout,因此只能向一个方向做控件的对齐。

 

2.不能跨行跨列

因为TableLayout,不明确指定包含多少行,多少列,而是通过向TableRow里面添加其他组件,每添加一个组件该表格就增加一列。

如果向TableLayout里面添加组件,那么该组件就直接占用一行。所以这种方式造成控件不能跨行跨列。

GridLayout,则用columnCount设置列数后,增加的控件在超过列数后自动换行进行排列。

 

The standard Views Containers(视图容器):

A container is a view used to contain other views.

Container

 

RadioGroup

ListView

GridView

ExpandableListView

ScrollView

HorizontalScrollView

SearchView

TabHost

VideoView

DialerFilter

 

●注意事项

由于GridLayoutAndroid4.0之后有的新功能,如果要在项目中使用这种布局,需要把SDK的最低版本指定为Android4.0API14—)以上。

AndroidManifest.xml中,配置SDK兼容的最低版本和最高版本示例代码如下:

<uses-sdk

android:minSdkVersion="14"

android:targetSdkVersion="17" />

绝对布局多用于游戏开发中,由于多分辨率兼容麻烦,绝对布局在Android1.5后被Google弃用,因此应用开发一般情况下不推荐使用绝对布局。

 

setContentView( )方法

setContentView(R.layout.main)在Android里面,这句话是什么意思?

R.layout.main是个布局文件即控件都是如何摆放如何显示的,setContentView就是设置一个Activity的显示界面,这句话的意思是 设置 这一条语句所在的Activity 采用 R.layout下的main布局文件进行布局

 

LayoutParams(布局参数类)

LayoutParams类的 继承关系 为:

Android.View.ViewGroup.LayoutParams.

LayoutParams类相当于一个Layout的信息包,它封装了Layout的位置、高、宽等信息。假设在屏幕上一块区域是由一个Layout占领的,如果将一个View添加到一个Layout中,最好告诉Layout用户期望的布局方式,也就是将一个认可的layoutParams传递进去。

可以这样去形容LayoutParams,在象棋的棋盘上,每个棋子都占据一个位置,也就是每个棋子都有一个位置的信息,如这个棋子在44列,这里的"44列"就是棋子的LayoutParams

//创建一个线性布局

    private LinearLayout mLayout;

    mLayout = (LinearLayout) findViewById(R.id.layout);

//现在我要往mLayout里边添加一个TextView

//你可能会想直接在布局文件里边配置不就O 了 那是 但是这里为了说明问题我们用代码实现

    TextView textView = new TextView(Activity01.this);

    textView.setText("Text View " );

//这里请不要困惑这里是设置 这个textView的布局 FILL_PARENT WRAP_CONTENT 和在xml文件里边设置是一样的如

/**<TextView

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    android:text="Text View"/>*/

//xml里边怎么配置高宽大家都会的。

//第一个参数为宽的设置,第二个参数为高的设置。

    LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(

    LinearLayout.LayoutParams.FILL_PARENT,

    LinearLayout.LayoutParams.WRAP_CONTENT

    );

//调用addView()方法增加一个TextView到线性布局中

    mLayout.addView(textView, p);

//比较简单的一个例子

 

●书中169面的main.xml文件编写完成后, 需要在源文件中进行如下设置:

 

FrameLayout(框架布局)

框架布局是最简单的布局形式。所有添加到这个布局中的视图都以层叠的方式显示。第一个添加的控件被放在最底层,最后一个添加到框架布局中的视图显示在最顶层,上一层的控件会覆盖下一层的控件。这种显示方式有些类似于堆栈。

 

一般很少使用,所以只是作为一个知识点列出来。借鉴于前人的样例

 

TabActivity实现多页显示效果

http://158067568.iteye.com/blog/941338

 

●探讨一下TabActivity

做个假定先: 比如我们最外面的ActivityMainActivity, 第一个tabFirstActivty, 第二个tabSecondActivity .

相信大家都用过TabActivity, 它是一个特殊的Activity,它特殊的地方在哪里?有以下几点为证:

a. 它看起来违反了Activity的单一窗口的原则。因为它可以同时加载几个Activity 当用户点击它上面的tab时,就会跳到相应的Activity上面去。

b. 用户首先进去FirstActivity,然后进去SecondActivity,再点击返回键的时候。它返回的界面不是FirstActivity,而是退出我们的应用程序。

c. 当用户在FirstActivity按返回键的时候,如果MainActivityFirstActivity通过重写onKeyDown()方法,那么收到事件回调的只有FirstActivity

 

(二)TabActivity存在必要性以及google当时的困扰

a. 首先我们要明白一点,android系统是单窗口系统,不像windows是多窗口的(比如在windows系统上,我们可以一边聊QQ,一边斗地主等等)。也就是说,在一个时刻,android里面只有一个activity可以显示给用户。这样就大大降低了操作系统设计的复杂性(包括事件派发等等).

b. 但是像TabActivity那种效果又非常必要,因为用户体验也比较好。所以我觉得当时google开发人员肯定很纠结。。 于是,一个畸形的想法产生了,就是在单窗口系统下加载多个activity,它就是TabActivity

 

TabActivity已经过时,Android4.0 以后直接使用fragment 即可,而最新版的安卓sdk ,通常已经将兼容包配置好了,不过,需要注意的是Eelipse 提醒的时候import 依然会提示老版本的 fragment v4Fragment(version 4 fragment)

一部小心,会选到第一个,程序运行不出来

 

TabActivity图示

- TabActivity - This is a specialized view that acts as a container for a TabHost (described below).

- TabHost - This is a container for the tabbed UI, hosting two children: a list of tab labels (选项卡标签) (i.e., tab widget) and a FrameLayout displaying the contents of the Activities or Views - When a tab (选项卡) is selected, it displays either an Activity or a View in the FrameLayout .

 

TabWidget - This control displays a list of tab labels, one for each tab in the TabHost . Each tab in a TabHost is represented by a TabHost.TabSpec object. This object contains the meta-data for each tab. When the user selects a tab, the TabHost responds to the selection by displaying the appropriate tab.

FrameLayout - A tabbed UI must have a FrameLayout contained inside of a TabHost . It is used to display the contents for the tab.

 

TabHost is an old API that has been deprecated by Google. Developers are encouraged to build tabbed applications using the ActionBar.

 

TabSpec(在代码中实现, 不在xml文件中实现, Spec指的是Specify)

代表了选项卡界面, 添加一个TabSpec即可添加到TabHost;

-- 创建选项卡 : newTabSpec(String tag), 创建一个选项卡;

-- 添加选项卡 : addTab(tabSpec);

 

※ 案例

远程音乐列表和本地音乐列表为两个不同的按钮,在TabActivity中它们同属于一个TabWidget,

而下面的两个列表都是在各自的Activity中设置,然后在将每一个Activity添加到TabActivityFrameLayout中。

也就是说在TabActivity的布局文件中必须包含TabWidgetFrameLayout两种控件。

这里值得一提的是,必须为TabActivity的布局文件的根节点设置为:TabHost

<?xml version="1.0" encoding="utf-8" ?>

<TabHost xmlns:android="http://schemas.android.com/apk/res/android"

    android:id="@android:id/tabhost"

android:layout_width="fill_parent"

android:layout_height="fill_parent">

<LinearLayout

     android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:padding="5dp">

    <TabWidget android:id="@android:id/tabs"

    android:layout_width="fill_parent"

android:layout_height="wrap_content" />

    <FrameLayout

android:id="@android:id/tabcontent"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:padding="5dp" />

</LinearLayout>

</TabHost>

 

参考阅读:

我们在ActionBar中进行Fragment之间的切换:

http://blog.csdn.net/xiaodongvtion/article/details/8775142

 

TabActivity & ActivityGroup & Fragment 比较

Android里面Tab分页,常用的方法有两种:

1、采用TabActivityTabHost的结合

2、采用ActivityGroupGridView的结合。

 

※ 如果Tab选项过多,可以采用Gallery+ActivityGroup结合的实现方式。

 

(2012年的说法)ActivityGroup在实际的开发中是十分常见的,在我使用过的Android应用中,十个应用里面有九个应用的主界面都是使用ActivityGroup的。

说起ActivityGroup,在国内好像直接使用它开发的并不多,基本都是使用TabActivity,它是ActivityGroup唯一的一个子类。

Android端新浪微博的主界面就是用TabActivity来实现的,还有其它的一些应用也几乎都用TabActivity来实现。在我眼里,TabActivityGoogle提供的一个非常失败的API(至少我现在这么认为,下文我会说它失败在哪里),但中国几乎所有的应用都使用TabActivity,我不禁在思考这是巧合还是复制粘贴的产物。

每个选项卡都可以对应多个子Activity,这个是普通TabActivity做不到的。

TabActivity

ActivityGroup

Fragment

 

LayoutInflater

LayoutInflater这个类的作用类似于findViewById()

不同点是

LayoutInflater是用来找res/layout/下的xml布局文件,并且实例化;

findViewById()是找xml布局文件下的具体widget控件(如ButtonTextView)

LayoutInflater 是一个抽象类,在文档中如下声明:

public abstract class LayoutInflater extends Object

 

LayoutInflater的实例的具体作用:

1、对于一个没有被载入或者想要动态载入的界面,都需要使用LayoutInflater.inflate()来载入;

2、对于一个已经载入的界面,就可以使用Activiyt.findViewById()方法来获得其中的界面元素。

获得 LayoutInflater 实例的三种方式:

LayoutInflater inflater = getLayoutInflater(); //调用ActivitygetLayoutInflater()

 

LayoutInflater localinflater =

(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

 

LayoutInflater inflater = LayoutInflater.from(context);

1 LayoutInflater inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);  

2 View view = inflater.inflate(R.layout.custom, (ViewGroup)findViewById(R.id.test));  

3 

4 //EditText editText = (EditText)findViewById(R.id.content);// error  
												

5 

6 EditText editText = (EditText)view.findViewById(R.id.content);  

 

ListActivity

一个含有一个ListView组件的Activity类。

也就是说,如果我们直接在一个普通的Activity中自己加一个ListView也是完全可以取代这个ListActivity的,只是它更方便而已。

package com.teleca;

 

 

Create Table like this put some space before INTEGER ....

 

"CREATE TABLE "+TABLE_NAME+" ("+KEY_ID+" INTEGER PRIMARY KEY AUTOINCREMENT)";

Sqlite中,一个自增长字段定义为INTEGER PRIMARY KEY AUTOINCREMENT或者INTEGER PRIMARY KEY时 ,那么在插入一个新数据时,只需要将这个字段的值指定为NULL,即可由引擎自动设定其值。

转载于:https://www.cnblogs.com/ArrozZhu/p/8383705.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值