1.框架:
1)Linux kernel
2)Libraries (C/C++编写) : 为 GUI , Android系统服务提供实现。
有 Surface Manager (不需要GUI干涉的视图), OpenGL, SQLLite, WebKit, libc
3)Android Runtime : java虚拟机Dalvik , 核心类库
4)Application Framework: java编写的Android框架和GUI.
有Activity Manager(应用程序最小单元), Windows Manager, Package Manager, Telephone Manager(应用处理器[即界面内容]和调制解调器), View System(每个控件都是View), Resource Manager,Locaton Manager(GPS),Notification Manager, XMPP Service(应用层通信协议).
5)Application : 应用程序。
2. 开发分类:
Linux kernel(驱动 并且要与 Library协同工作), Library(调用驱动), Application Framework(对Framework扩展:调用Library), Application.
3.开发应用程序:
Eclipse插件ADT : ... 及 AVD ...
Android SDK : 设置SDK路径.
4. Hello word
Create > Android Application
Project Name : 项目名称
Application Name : 应用程序名称
5.基础
Android的4种程序片段:
Activity: 有图形界面的最小执行单元,用户可与之交互。
Service: 无图形界面的最小执行单元, 一般在后台执行一些任务(如下载、播放音乐)。
Receiver: 响应系统广播消息的独立执行单元。
Provider: 应用程序内部定义一个Provider服务, 其它应用程序可以访问这个Provider, 从而读写相关的文件或数据。
一个Activity有且只有一个Window, 每个Window有且只有一个ViewGroup, 每个ViewGroup 可有多个View或ViewGroup.
消息流程:
Window和View管理器是GUI的核心,GUI内部消息传递流程:当系统检测到用户消息后(如触摸), 系统会把此消息传递
给当前Activity, Activity 再把此消息传递给Window, Window管理着ViewGroup的界面位置信息, 因此知道把消息发
送给哪个View或ViewGroup, 对应的View或ViewGroup会响应并处理不同的用户消息。
Android程序可从任意一个Component处启动。
Activity的启动方式有多种 , 如startActivity(Intent intent)
启动顺序:onCreate(); onStart(); onResume(); onPause(); onStop();
注意,Activity启动是异步的,当调用startActivity后, 系统不是立即执行新的Activity, 而是由Activity Manager调度, 在startAcitvity返回后, 先中止正在运行的Activity, 再启动新的Activity.
Activity 的 onCreate() : setContentView( R.layout.main ), 用来把一个ViewGroup设置为该Activity所用的界面。
@: 表示引用, 如 @string/hello 表示引用 value中的string.xml 中的hello.
@+:表示引用和添加。
颜色: "#ARGB" , A表示通光度。
Manifest.xml : manifest(货单,清单的意思), 展示程序片断及启动条件,命名,或本程序许可权。
其中包括:
<activity />, <service />, <provider />, <receiver />
Android片断运行的可能实现:每个Application可能对应了多个可执行程序。
Android 与 Windows程序区别: 片断运行, 每个application使用不同linux user id.
5.Java 语法在 Android中使用.
1) interface: 用于接口(服务端调用, 客户端实现)。
abstract class: 用于继承(继承,重写)。
2) for : fro( int age: ages )
3) 其它工具类: map
4) synchronize : 同上,用于函数,对象。( chronic慢性的, sync 同步)( asychronize异步)
5)new : 没用new分类的数据都是从栈中分配,用new的都是从堆中分配。
6. 用户接口:
1)布局: Activity( Window( ViewGroup( View, ..., ViewGroup ) ) )
LinearLayout,RelativeLayout,FrameLayout,TableLayout 都是ViewGroup的子类。
TextView, EditView, Button, ImageView, ImageButton, CheckBox, ToggleButton(开关), RadioButton,RadioGroup(有orientation属性,有checkButton属性), RatingBar(带评选的进度条), ScrollView( 内部只能有一个View ),
其它视图: android.widget.*
为View指定属性:可用 style="@style/style_name"
视图大小与位置:
margin 与 padding ...
对于ViewGroup是layout的根结点时, marginLeft与marginTop分别等同于marginRight, marginBottom. 即Android对页面的布局总是从左上角(0,0)处开始的, 也就是根节点必须从(0,0)开始绘制。注意, 根ViewGroup既有marginLeft和marginRight时, 两者取其大,且与顺序无关。
对齐方式:gravity, 对View来讲,用于指定其包含内容的对齐方式; 对ViewGroup来讲,用于指定其包含的View, ViewGroup的对齐方式。
动态创建View和ViewGroup:
a. View不支持addView()方法, ViewGroup可以用来添加ViewGroup或View. Activity有setContentView(R.layout.main)方法, 也有findViewById()方法,且findViewById只从其当前的ContentView中寻找该id的View.
LinearLayout ll=new LinearLayout( this [即当前Activity] );
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LayoutParam.Fill_PARANT,xx.FILL_PARANT);
ll.setLayoutParams( params );
b. 利用LayoutInflater(布局泵)来添加一个xml文件(如layout_2.xml)描述的ViewGroup.
LayoutInflater inflater = this.getLayoutInflater();
ViewGroup v = (ViewGrooup)findViewById( R.id.main_sub_layout );
inflater.inflate( R.layout.layout_2, v);
Activity的setContentView方法: 该方法是设置Activity的内部ContentView的方法,Activity任何时刻只有一个ContentView。
常用的ViewGroup( layout ):
LinearLayout : 其另一个属性 weight, 用于指定其占用剩余空间的权重。(????)
RelativeLayout : 按照父兄位置来布局,不存在orientation属性。 layout_below, layout_toLeftOf, ... ...( 可参见RelativeLayout.LayoutParams)
TableLayout : <TableRow>, android:stretchColums(合并单元格), android:collapseColums(消除指定的列)
FrameLayout : 所有View位置总是从屏幕左方开始的。 (android:visibility可控制各个view的可见性。)
WebView : 网页视图, 内嵌浏览器。
AssetManager am;
am = getAssets();
String webcode="";
try {
InputStream is = am.open("a.html");
int size = is.available();
byte[]buf = new byte[size];
is.read(buffer);
webcode = buf.toString();
webcode=new String(buf, "gb2312");
is.close();
}catch(IOException e){
Log.e("fillread", "read html error!");
}
WebView web = (WebView)findViewById( R.id.webView );
web.loadDataWithBaseURL(null, webcode, "text/html", "utf-8", null);
2)事件响应
内部类可以使用外部类的成员变量。
内部接口...
View内部的数据处理:(根据用户消息进行运算), (调用接口), 绘图。
OnClickListerner l = new OnClickListener(){
public void onClick( View v ){
TextView tv=(TextView)findViewById(
}
}
3)菜单
a.选项菜单(OptionMenu)
Activity有onCreateOptionMenu(Menu)和onSelectOptionItem(Item)
程序创建、文件创建.
b.上下文菜单(ContextMenu)
当长屏幕时, 会发生onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)方法调用(注意它是Activity的方法,只能通过v.getId()来区分当前是长按在哪个View上面, 从而生成相应的上下文菜单)。
当关闭时, 会有onCloseContextMenu发生调用。
当选择时, 会有onContextItemSelected(MenuItem item).
另外要注意的是,当同一位置父子View都有ContextMenu时( 即 case ID1: menu.add(); break; case ID2: menu.add(); break;), 由于它们共用同一个ContextMenu, 所以两个add()都会执行,从而不是我们想要的结果。为了处理这种情况, 可以在添加menuItem之前,执行menu.hasVisibleItems()作一个检测。
c.子菜单(SubMenu).
d.单选与复选菜单.
单选菜单, 要把需要互斥的菜单项放在一个组中(组id相同), 其次,使用setGroupCheckable来设置其选择状态与是否互斥。
e.使用xml文件来描述菜单.
<menu>, <item>, <group>
4)各种对话框( 稍后 )
Dialog是由Dialog Manager管理。
showDialog(int id), dismissDialog(int id), removeDialog(int id);
onCreateDialog(int id), onPrepareDialog( int id , Dialog dialog)[对话框存在的话,在显示之前可对其内容进行处理];
a. 提示对话框 AlertDialog
AlertDialog.Builder builder = new ...;
builder.setSositiveButton( ... ).setNegativeButton( ... ).setTitle( ... ).setMessage( ... );
AlertDialog alert = builer.create();
builder.setItems( ... );
b. 进度对话框 ProgressDialog
c. 日期时间对话框: DatePickerDialog, TimePickerDialog
d. 自定义对话框:
方法一: 基于AlertDialog, 调用SetView来添加任意视图。
方法二:基于Dialog, 设置其 contentView, 并且自定义事件处理。
public final View findViewById (int id) : 可以在ViewGroup内部寻找对应ID的view.
5)绑定视图与数据(复杂的视图如List, Grid, Tab)
Adapter View(View利用Adapter来操作显示的内容) 与 Adapter(提供操作数据的接口)
a. 下拉列表Spinner :
b. 格子视图GridView:
c. 相册Gallery:
d. 标签页TabWidget:
e. 列表视图ListView:
6)自定义View
( ??? ????)
7. Intent 与 Intent Filter
四种程序片断: Activity, Service, Brocast Receiver, ContentProvider.
除了ContentProvider之外, 其它四种都是通过Intent启动的。
Intent 是一种数据结构, 包含了想要启动的程序片断的相关信息,由Application Framework来接收Intent, 并判断其属于哪种片断, 并用相应的 Activity[Service|Receiver] Manager 来启动对应的片段。
启动程序片段的方式:显示(指明程序片断) 或 隐式(Intent 仅指明需要的功能, 一般AndroidManifest.xml的Intent Filter就是告诉系统自己的功能)。
Intent数据结构:(片断名称Component Name),Action,Data,Category,Exras,Flags
Action测试: intent.setAction( <action android:name = "xxx.xxx.xxx" /> );
在<intent-filter>中, 有android:icon, android:lable, android:priority, <action>指定action名字,<category>指定类别(?????什么用???)。
Data测试。。。
8.使用Activity
1) 应用程序只有一个Context对象,
一个Activity只有一个Window,可以在Activity中使用setContentView()来给Window设置一个具体的视图。
Window win = getWindow();
win.setTitle("通过程序设置边框.");
requestWindowFeature(Window.FEATURE_NO_TITLE);
win.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); //设置成全屏方式,则上方状态栏也会隐藏。
若旧Activity部分可见,则它会被调用onPause(), 然后返回时调用onResume().
若旧Activity不可见,则它会被调用onStop(), 在返回时,它的onRestart()会被调用,并从onStart()开始执行。
注意上述说明中, 还会有特例。
启动Activit:
直接;
使用菜单: 在onCreateOptionsMenu()中使用 m_item.setIntent(this, Xxx.class)), 在onOptionsItemSelected()中使用super.onOptionsItemSelected(item);
注意:两个方法, 一个是先调用 super.onCreateOptionsMenu()再加MenuItem, 一个是先判断ID再调用super.onOptionsItemSelected(item);
2) 使用小工具Widget
用途:a通知与提醒: 网络类,本地类; b.作为快速入口。
原理:Widget管理器定期向Widget发送消息。
Widget对象的组成:a.界面描述。b.响应特征(如多长时间收到一次)。c.实现对数据处理, 即AppWidgetProvider类,实际上是基于Broadcast Receiver程序片断的。也就是说AppWidgetManager是一个发送广播的服务,AppWidgetProvider都可以收听该广播消息。
结构:在Manifest.xml中声明程序提供的Widget, 并指向 WidgetInfo.xml, 在Widget layout.xml中定义界面。
创建Widget:
a.在Manifest.xml中创建一个 <receiver>标签,action为 andorid:name="....
action.APPWIDGET_UPDATE"
android:resource指定info文件。
b.res/xml下创建 info.xml, 定义其最小宽高,更新时间,初始布局文件layout/mymusic_widget.
c.在layout下创建mymusic_widget.xml, 描述其布局。
d. 在src 目录下创建Widget实现文件, MyMusicWidget extends AppWidgetProvider{ opUpdate(Contextcontext, AppWidgetManager manager, int [] appWidgetIds){ ... } }
Widget的函数调用情况:
onUpdate() : 每次添加到桌面时,及通知周期来临。
onEnable() : 每一次添加时。
onDisable(): 最后一个实例被删除。
onDelete() : 每删除一个时。
在Widget中启动Activity:
在onUpdate()中有如下代码:
ComponentName serviceName = new ComponentName( context, MusicPlayer.class ); //组件名。
RemoteViews views = new RemoteViews( context.getPackageName(), R.layout.mymusic_widget );
// RemoteViews 是创建一个外部程序可以访问的视图对象, 因为Widget本身是在桌面中。
Intent intent = new Intent();
intent.setComponent( serviceName );
PendingIntent pendingIntent; //挂起的Intent.
pendingIntent = PendingIntent.getActivity( context, 0, intent, 0);
// 获取一个启动Activity的PendingIntent对象.
views.setOnclickPendingIntent( R.id.widget_button, pendingIntent);
// 当此事件发生时, 把挂起的事件执行。
appWidgetManager.updateAppWidget(appWidgetIds, views);
// 让WidgetManager来管理属于桌面的View.
问题:Widget是在桌面面上显示,由WidgetManager对其管理(消息处理等等 ) ??
另外,RemoteViews对象不能获取Widget视图中的值,故,想用Widget做一个桌面上的快速搜索的工具都不能完成
。。。
4)使用Notification
Notification Manager .... 可以通过 getSystemService()来获得该管理器对象。
创建一个通知:获取NotificationManager对象, 创建一个Notification对象, 获取应用程序的上下文getApplicationContext(), 创建一个PendingIntent, 设置Notifi的参数, 然后用NotificationManager的notify方法来生成一个通知。
可在notification.setLatestEventInfo()中设置可在通知窗口中启动的Activity.
5)保存存活状态
Activity的onCreate(Bundle )及onRestoreInstanceState(Bundle )可用于在启动和销毁Activity时恢复和保存程序的数据。注意,系统一般都会保存界面元素的值,故只需要保存程序的各种数据值。
6)Activity之间数据传送:
使用 startACtivityForResult():
a.旧Activity使用startActivityForResult()来启动新Activity, 并且在onActivityResult中获取新
Activity返回的数据。
b.新Activity可以使用intent.getExtras()来获取旧Activity传送过来的数据, 并且,可以setResult()返回数据及返回码。
7) Activity 与 Task
任务Task是一个栈,默认情况下,当应用程序X调用X或Y的Activity时,它们会在同一个Task内,即在同一个Stack内。按返回键时,是返回到上一个Activity.
设置某个Activity在一个新栈中:a.可以通过intnet.setFlag()的方法, b.可以在Activity中使用android:launchMode="singleTask"属性。
9.使用Service
Service 启动方式:startService() 与 bindService().
如果Service与Client同在一个应用程序内, 默认情况下, 它们在同一个进程、同一个线程内运行。
创建Service:
使用AIDL(接口定义语言), 定义服务接口。
( ???? ????)
10.使用Broadcast Receiver
发送接收.
Receiver 没有界面,并且周期非常短,只有在执行onReceive()方法中才有效,故在其中不能执行具有回调功能的异步函数。因为当异步函数调用时,Receiver已经结束。
广播消息分类:系统已经定义的 与 自定义的广播消息。
接收消息分类:静态接收,即在安装时,就声明其可以接收的消息; 动态接收,在接收前,使用registerReceiver()方法向系统注册一个Receiver.
异步广播sendOrderedBroadCast() 与 异步广播sendBroadCast()。
1) 静态创建Receiver
manifest.xml中:
<receiver android:name=".bootDisplayReceiver"> //系统启动后的Receiver
<intent-filter>
<action android:name = "android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
src目录下:
public class bootDisplayReceiver extends BroadcastReceiver}
public void onRecevie(Context context, Intent intent){
//可以启动一个Activity.或进行其它其它的操作。
}
}
2)动态创建Recevier
一般在onResume()中进行registerReceiver(), 在onPause()中unregisterReceiver(); 注意的是,如果程序结束后没有Receiver, 那么该Recevier会一直处理接收广播消息,直到该程序的Context被销毁
例:a.在继承自BroadcastRecevier的类中,重写onReceive()。
b.Activtity中,在onCreate()里面创建一个IntentFilter并增加Action, 并且创建一个Receiver 在onResume()里注册,在onPause()里注销。
注意:这里的注册是使用实例(...一般的注册都是使用例),而不是类名(...在Intent里使用类名).
另一个用途:Service与Activtiy通信,Service中建一个Receiver, 接收Activity的广播消息,当接收到消息时,执行Service的相应方法。
11.使用Content Provider
两方面:一是使用别人的Provider, 二是提供一个Provider供别人使用。
Provider类似于Windows系统中的服务。
1) 使用另人的Provider.
方法1.使用 getContentResolver()返回的 ContentResolver对象的query()来操作Provider。
方法2.使用 Activity的manageQuery()来使用Provider, 它更灵活,可以在onpause(),onStart()中自动释放或重新获取cursor指针。
query( Uri uri, String[]projection, String selection, String[]selectionArgs, String sortOrder);
其中, uri指: Content://+包名+Provider名+/表名+/id值, projection 指返回的列名, selection指 where 语句,selectionArgs指 where中的点位符?代表的值, sortOrder指order by 后面的列。
在返回的Crusor对象中,可以使用 mCursor.moveToFirst(), mCursor.getColumIndex(People.NAME), mCursor.getString( index );
注意:在urss-permission中加上 andorid.persmission.READ_CONTEACTS.
修改Provider...
2) 定义自己的Provider
a.设计存储:一般情况下使用数据库存储,可以直接利用返回的Cursor对象。
b.创建Provider类,该类必须基于 Content Provider类。
c.在Manifest.xml 文件中声明该Provider, 声明权限。
12.资源文件
assets(资产)目录下文件以字节流形式使用。
res 目录下的目录命名都是固定的。
资源类型:编译前(使用xml描述), 编译后(使用R.xxx.yy 描述).
颜色资源(values),字符串资源(values)
点阵图资源(drawable),单色图资源(drawable),动画(anim),菜单(menu),布局(layout)
自定义视图(values)
元数据文件(raw)
样式( values)
主题( values)
assets管理器: AssetManager am = getAssets();
Android环境参数表:屏幕方向,键盘,方向键类型,屏幕分辨率??。
13.存储
系统文件夹: data( ./app第三方程序,./data/所有程序的私有数据), sdcard(文件。。。), system( ./app系统内置的应用程序)。
Android本地存储有3种方式: 文件存储,数据库,参数化存储(存储在.xml中). 它们都是私有的.
故为了使不同应用程序间共享数据, 只能通过Provider来提供。
文件路径:Uri格式为 file:///xxx/xxx/xxx.xxx; String格式为 /xxx/xxx.xxx
程序的私有文件: 在 data/data/xxx.yyy/ 下,一般有3个私有目录: files(保存创建的文件, 可以用标准java IO访问), shared_prefs( xml文件 ), database, 同时也可建立其它目录。
1) 文件存储
读取私有文件夹files下的文件: context.openFileInput()和openFileOutput().
读取其它文件夹下的文件:使用标准的 java IO.
遍历文件夹:File flist = new File("/sdcard/"); mFileList = flist.list();
读写文件:context.openFileInput() 与 context.openFileOutput()
2) 数据库存储
SQWLiteOpenHelper, SQLiteDatabase
数据库的存储:a.设计数据表; b.为每个表设计一个Java类(适配层); c.为每个Java类定义一个基于SQLiteOpenHelper的内部类,提供onCreate()和onUpdate()两个方法。d.在每个Java类内部添加一些应用层使用的函数, 或者直接使用SQLiteDatabase包含的方法; e.在每个Java类中, 把数据更的名称定义为常量,便于访问。
3) 参数存储
SharedPreferences
14.多线程
Android的多线程是基于Linux本身的多线程机制,而多线程之间的同步又是通过Java本身的线程同步。
线程在系统中占用不同的地址段。
Android系统中,是循环取消息(Looper)、接着处理消息(Handler)。
Android中,一个Activity就是一个线程,多个Activity之间的切换是在同一个线程中。
新建一个Thread对象一般需要实现两个函数: a.构造函数(传递context); b.run(), 停止线程,不能用
destroy()或stop(), 可用一个变量,通过判断自行结束。
1) Thread 与 Runable : Runable 只是一个接口,不含线程实现,故只能使用Thread的静态方法,它一般只作为一个参数传递。
2)Thread 与 Service的区别:
3) Handler 与 Looper
Handler 用于处理线程中的消息队列, 它与线程相关联,有 handler.handleMessage() 及
handler.sendMessage() , postXXXX()[用于把一个Runnable对象发送到消息队列]。
注意:只要有handler句柄,就可以跟它所属的线程发送消息。
Looper: 相当于 run()方法中的一个大循环, 接收消息,并使用handler进行处理。
run(){
Looper.prepare(); //新建一个looper对象。
Handler handler = new Handler(){ };
Looper.loop(); //大循环,在其中接收消息,并且使用本线程的handler来处理。
}
4) 线程同步
synchronize; 对于方法或代码段。
wait(),notify(), notifyAll(); //对于对象。
join()/interrupt(); //对于线程。
15.系统安全
程序签名: 程序签名使用 <公匙,私匙>, 并且使用私匙加密程序,并且只能使用对应的公匙来解密程序。
安全调用, 分为5种:
a.系统功能调用:电话,短信,蓝牙,网络。
b.启动Activity: 设置允许其它程序启动。。
c.Broadcast Receiver发送与接收:sendBroadcast()时可指定谁才可以接收我发出的消息,对Receiver来讲指定"谁才能给我发送消息".
d.读写Content Provider. "只有拥有许可权的程序才能访问我所提供的内容。"
e. 启动Service. 设置可以启动该Service的程序。
16.Manifest.xml
包含的内容:
程序包名。
程序片断。
许可权限。
最小API版本。
外部库文件。
17.多媒体与网络
音乐:MediaPalyer
视频:MediaPlayer + Surface
录音:MediaRecorder
Surface原理: GUI通过SurfaceView操作Surface, 应用程序可以通过SurfaceHolder来操作Surface。
Activity中:
//设置全屏
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
//显示自定义的SurfaceView视图
setContentView(new MySurfaceView(this));
setContentView(new MySurfaceView(this));
MySurfaceView中:
MySurfaceView extends SurfaceView implements Callback, Runnable
在surfaceCreated(SurfaceHolder holder)中创建一个线程。
public void run() {
while (flag) {
long start = System.currentTimeMillis();
myDraw(); // 在cavas中绘图。
logic();
long end = System.currentTimeMillis();
try {
if (end - start < 50) {
Thread.sleep(50 - (end - start));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
游戏开发:surface, 多线程.
网络:Socket, Http, 电话/短信开发。
18.调试
DDMS: 用于与虚拟机进行数据交换。
ADB :
DDMS <> Device Monitor Service <> ADB.
DDMS <> VM Monitor <> VM.
真实设备与虚拟器上有( App/VM, VM Debugger, adb daemon ).
emulator -avd my_avd1
emulator -avd my_avd2
// 可启动多个模拟器。
ddms : 单步调试,文件夹濒临,截屏,制件Emulator(包括地理位置,短信,电话模拟).
adb : 安装应用程序。 也可使用 adb kill-server 停止adb服务,并关闭Emulator.
Logcat : 类似于printf(), Log.i(info), .d(debug), .w(warning) .e(error)
为工程添加jar包:
若jar包不捆到apk中,则需要把 jar包放在设备固定文件夹中,否则Dalvik VM找不到,而这种方法只有手机出厂时完成。
所以jar包都一般都捆绑到apk中。
AddLibrary 与 AddJar : 添加库在打包时不会打包进 apk中, 而添加jar时,会打包进apk中。
19.应用开发实例
(android: QQ服务端、客户端实现)
20.游戏开发实例
(andorid: 小型单机或网络游戏)
Eclipse 快捷键:???
帮助文档:
android-sdk-windows\docs