Android系统架构
Android大致可分为四层架构,五块区域。
1. Linux内核层:Android系统基于Linux2.6内核,Linux内核层为Android设备的各种硬件提供底层驱动,如显示驱动、音频驱动、照相机驱动、蓝牙驱动、Wi-Fi驱动、电源管理等。
2. 系统运行库层:通过一些C/C++库为Android系统提供主要的特性支持,如SQLite库提供数据库支持,OpenGL|ES库提供3D绘图支持,Webkit库提供浏览器内核支持等。
3. 应用框架层:提供构件应用程序时可能用到的各种API,如完成Android自带的一些核心应用或开发者构建自己的应用程序所需用到的API。
4. 应用层
包括所有安装在手机上的应用程序,如系统自带的联系人、短信程序、从Google Play上下载的程序和自己开发的程序。
Android系统提供的应用开发特色
1. 四大组件——活动(Activity)、服务(Service)、广播接收器(Broadcast Receiver)和内容提供器(Content Provider)。
2. 丰富的系统控件。
3. 自带轻量级、运算速度极快的嵌入式关系型数据库SQLite。
4. 地理位置定位功能
5. 丰富的多媒体服务。
6. 内置多种传感器。
AndroidManifest.xml中有如下代码,表示对活动MainActivity进行注册:
<activity android:name=".MainActivity" android:label="@string/app_name" android:theme="@style/AppTheme.NoActionBar"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
<intent-filter>中的语句表示MainActivity是项目的主活动,在手机上点击应用图标,首先启动的就是这个活动。
活动(Activity):一种可以包含用户界面的组件,主要用于和用户进行交互,是Android应用程序的门面,凡是在应用中可见的东西都放在活动中。一个应用程序中可以包含零个或多个活动。
Activity是Android系统提供的活动基类。
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } }
onCreateOptionMenu()用于创建菜单。
onCreate():活动被创建时必须执行的方法。
Android程序设计遵从逻辑与视图分离,通常在布局文件中编写界面,然后在活动中引入。onCreate()中setContentView()方法给当前活动引入了一个布局。
布局.xml文件定义在/res/layout/目录下。
手动创建活动的步骤
1)手动创建活动.java后,为当前活动加载布局:
1. 在/res/layout/下创建布局first_layout.xml;
2. 调用R.layout.first_layout得到first_layout.xml的布局id;
3. 在活动中调用setContentView(),将布局id传入,给当前活动加载布局。
2)在AndroidManifest.xml中为活动注册
<activity android:name=".FirstActivity" android:label="This is FirstActivity"> </activity>
android:name指定具体注册的活动,因为最外层
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.lily.activitytest">
package属性指定程序包名,因此前面部分可省略,直接填写.FirstActivity即可指定活动。
android:label指定活动中的标题栏内容,显示在活动顶部,也是启动器(Launcher)中应用程序显示的名称。
在<activity>标签内部加入声明
<intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter>
使该活动成为程序主活动(点击桌面应用程序图标时首先打开该活动)。
隐藏标题栏的方法
在活动的onCreate()中调用requestWindowFeature(Window, FEATURE_NO_TITLE),
注意一定要在setContentView()之前执行。
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.first_layout); }
在活动中可以使用Toast,将一些短小的信息通知给用户,在一段时间后自动消失,并且不会占用任何屏幕空间。
例:使点击按钮button1作为Toast触发点。在onCreate()中加入:
Button button1 = (Button)findViewById(R.id.button_1); button1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(FirstActivity.this, "You clicked Button 1", Toast.LENGTH_SHORT).show(); } });
传入R.id.button_1(由layout.xml中按钮的android:id属性指定),通过findeViewById()获取在布局文件中定义的元素返回View对象,向下转型得到按钮实例。
调用setOnClickListener为按钮注册监听器,在onClick()方法中编写弹出Toast的功能。
Toast使用方法:通过makeText()创建Toast对象,调用show()显示Toast。
makeText()的参数:Context对象,直接传入FirstActivity.this;Toast显示的文本内容;Toast显示时长(可选内置常量Toast.LENGTH_SHORT和Toast.LENGTH_LONG。
在活动中使用Menu,点击Menu可以展示菜单。
在res目录下创建menu文件夹,新建main.xml,添加代码:
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/add_item" android:title="Add" /> <item android:id="@+id/remove_item" android:title="Remove"/> </menu>
<item>创建具体菜单项,android:id指定唯一标识符,android:title指定菜单项名称。
在活动代码中重写onCreateOptionMenu()方法:
public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; }
getMenuInflater()得到MenuInflater对象,调用inflate()方法给当前活动创建菜单。
Inflate()第一个参数指定通过哪个资源文件创建菜单,传入R.menu.main,第二个参数指定菜单项将添加到哪个Menu对象中,传入onCreateOptionMenu中传入的menu参数。
返回true表示允许创建的菜单显示出来。
在活动中重写onOptionsItemSelected()定义菜单响应事件:
public boolean onOptionsItemSelected(MenuItem item) { switch(item.getItemId()) { case R.id.add_item: Toast.makeText(this, "You clicked Add", Toast.LENGTH_SHORT).show(); break; case R.id.remove_item: Toast.makeText(this,"You clicked Remove", Toast.LENGTH_SHORT).show(); break; default: } return true; }
调用item.getItemId()判断点击的是哪个菜单项,给每个菜单项加入逻辑处理。
销毁活动:在活动中调用finish()方法。
Intent:Android程序中各组件之间进行交互的一种方式,可指明当前组件想要执行的动作、在不同组件之间传递数据。一般用于启动活动、启动服务、发送广播等场景。
1. 使用显示Intent启动另一活动
新建布局second_layout.xml和活动SecondActivity并重写onCreate()方法;
在AndroidManifest.xml中为SecondActivity注册;
<activity android:name=".SecondActivity"> </activity>
由于SecondActivity不是主活动,不需要配置<intent-filter>标签的内容
修改FirstActivity中button1的点击事件:
button1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(FirstActivity.this, SecondActivity.class); startActivity(intent); } });
Intent构造函数Intent(Context packageContext, Class<?> cls)接收参数为启动活动的上下文和想要启动的目标活动
这里传入FirstActivity.this作为上下文,传入SecondActivity.class作为目标活动构建一个Intent,通过startActivity()方法执行Intent。
2. 使用隐式Intent
隐式Intent指定一系列更为抽象的action和category等信息,交由系统分析Intent找出响应该隐式Intent的活动来启动。
在AndroidManifest.xml中为SecondActivity配置<intent-filter>的内容:
<activity android:name=".SecondActivity"> <intent-filter> <action android:name="com.example.lily.activitytest.ACTION_START" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
指定当前活动能够响应的action和category,只有<action>和<category>中的内容能够同时匹配上Intent中指定的action和category时,活动才能响应该Intent。
修改FirstActivity中按钮点击事件:
button1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent("com.example.lily.activitytest.ACTION_START"); startActivity(intent); } });
传入action的字符串构造一个Intent,表明想要启动能够响应该action的活动;
而android.intent.category.DEFAULT是一种默认的category,在调用startActivity()时自动将该category添加到intent中;
运行程序后点击按钮,因为<action>和<category>同时匹配,成功通过隐式Intent启动SecondActivity。
每个Intent只能指定一个action,但能指定多个category,在FirstActivity中添加新的category:
intent.addCategory("com.example.lily.activitytest.MY_CATEGORY");
要使活动响应该intent,需要在AndroidManifest.xml中SecondActivity的<intent-filter>标签里为新增的category添加声明:
<category android:name="com.example.lily.activitytest.MY_CATEGORY" />
运行程序后点击按钮,<action>和<category>同时匹配,成功通过隐式Intent启动SecondActivity。
通过Intent调用系统浏览器打开网页
修改FirstActivity中的按钮点击事件:
button1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse("http://www.baidu.com")); startActivity(intent); } });
指定Intent的action为Intent.ACTION_VIEW,是Andorid系统内置动作,常量值为android.intent.action.VIEW;
通过Uri.parse()将传入的网址字符串解析为一个Uri对象,Uri对象指定当前Intent正在操作的数据;
调用Intent的setData()方法,将Uri对象传入;
运行程序在FirstActivity点击按钮可调用系统浏览器打开网页。
可在<intent-filter>标签中配置<data>标签,用于精确指定当前活动能够响应的数据类型,只有<data>标签中指定的内容和Intent标签中携带的Data完全一致时活动才能响应该Intent。<data>标签主要可配置以下内容:
android:scheme 用于指定数据协议部分,如http
android:host 用于指定数据的主机名部分,如www.baidu.com
android:port用于指定数据的端口部分,一般紧随主机名后
android:path 用于指定主机名和端口之后的部分,如一段网址中跟在域名之后的内容
android:mimeType 用于指定可以处理的数据类型,允许使用通配符的方式指定
建立能相应打开网页的Intent的活动
添加third_layout.xml,活动ThirdActivity.java;
在AndroidManifest.xml中为ThirdActivity注册:
<activity android:name=".ThirdActivity"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="http" /> </intent-filter> </activity>
在ThirdActivity的<intent-filter>中配置当前活动能够响应的action是Intent.ACTION_VIEW的常量值,配置category为指定的默认值,<data>通过android:scheme指定数据协议为http协议,这样ThirdActivity就和浏览器一样能够响应一个打开网页的Intent。
运行程序:
系统弹出列表显示可响应该Intent的所有程序,点击Browser打开浏览器并显示百度主页,点击ActivityTest启动ThirdActivity。
指定tel协议在程序中调用系统拨号界面
修改FirstActivity中按钮点击事件:
button1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent(Intent.ACTION_DIAL); intent.setData(Uri.parse("tel:10086")); startActivity(intent); } });
指定action为Intent.ACTION_DIAL(安卓内置动作)
修改AndroidManifest.xml中FirstActivity<intent-filter>中的data标签,指定tel协议:
<data android:scheme="tel" />
运行程序点击button1可启动拨号10086
通过Intent向下一个活动传递数据
修改FirstActivity中按钮点击事件:
button1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { String data = "Hello SecondActivity"; Intent intent = new Intent(FirstActivity.this, SecondActivity.class); intent.putExtra("extra_data", data); startActivity(intent); } });
使用显示Itent启动SecondActivity,调用putExtra方法在Intent中暂存字符串数据,接收参数1为键(用于后面从Intent中取值),参数2为需要传递的数据;
在SecondActivity中将传递的数据取出并打印:
Intent intent = getIntent(); String data = intent.getStringExtra("extra_data"); Log.d("SecondActivity", data);
调用getIntent()获取启动SecondActivity的Intent,再调用getStringExtra()获取传递的字符串数据(整形数据用getIntExtra(),布尔型用getBooleanExtra());
运行程序点击button1跳转到SecondActivity,Logcat打印字符串信息。
通过Intent返回数据给上一个活动
修改FirstActivity中的按钮点击事件:
button1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(FirstActivity.this, SecondActivity.class); startActivityForResult(intent, 1); } });
调用startActivityForResult启动SecondActivity,startActivity()传入参数1为Intent,参数2为唯一值的请求码(用于回调中判断数据来源);
为SecondActivity注册按钮点击事件并添加返回数据逻辑:
Button button2 = (Button) findViewById(R.id.button_2); button2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.putExtra("data_return", "Hello FirstActivity"); setResult(RESULT_OK, intent); finish(); } });
构建Intent用于传递数据;
调用setResult()用于向上一个活动返回数据,setResult()传入参数1为返回处理结果(一般为RESULT_OK或RESULT_CANCELED),参数2为带有数据的intent;
调用finish()销毁当前活动,回调到启动该活动的上一个活动的onActivityResult();
在FirstActivity中重写onActivityResult(),得到返回的数据:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch(requestCode) { case 1: if(resultCode == RESULT_OK) { String returnedData = data.getStringExtra("data_return"); Log.d("FirstActivity",returnedData); } break; default: } }
onActivityResult传入参数1为启动活动时传入的请求码,参数2为返回的处理结果,参数3为携带返回数据的Intent;
各种活动返回的数据都会回调onActivityResult,所以首先要检查requestCode判断数据来源;
确定数据来源后通过resultCode判断处理结果;
如果处理成功,从data中取出数据并打印。
运行程序,在FirstActivity点击button1会打开SecondActiity,点击button2回到FirstActivity,LogCat打印字符串信息。
如果用户通过Back键回到FirstActiviy
重写SecondActivity的onBackPressed方法:
@Override public void onBackPressed() { Intent intent= new Intent(); intent.putExtra("data_return", "Hello FirstActiviy"); setResult(RESULT_OK, intent); finish(); }
运行程序,在FirstActivity点击button1打开SecondActivity,点击Back键回到FirstActivity,LogCat打印字符串信息。