Android基础第七篇
Posted _gaogao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android基础第七篇相关的知识,希望对你有一定的参考价值。
转载请标明出处:
http://blog.csdn.net/gj782128729/article/details/52424876;
本文出自:【高境的博客】
1. 清单文件androidManifest.xml
1.1. 清单文件的作用
每个Android应用都需要一个名为AndroidManifest.xml的程序清单文件,这个清单文件名是固定的并且放在每个Android应用的根目录下。它定义了该应用对于Android系统来说一些非常重要的信息,Android系统需要这些信息才能正常运行该应用。Android程序清单文件主要具有下面作用:
(a)它给应用程序Java包命名,这个包名作为应用程序唯一标识符。
(b)它描述了应用程序中的每个程序组件—Activity,Service,Broadcast Receivers和Content Provider。它描述了实现每个应用程序组件的类名称和组件能力(比如组件能够处理哪种类型的Intent消息)。这些描述帮助Andoid操作系统了解这些程序组件和在何种条件下可以启动这些程序组件。
(c)它决定哪些进程用来运行应用程序组件。
(d)它描述了应用程序使用某些受保护的程序API或和其它应用程序交互所需的权限。
(e)它描述了其它应用程序和该应用交互时应拥有的权限。
(f)它列出了Instrumentation类用于提供应用程序运行时一些性能统计和其它信息。这些生命只在测试或开发应用时使用。在发布应用时应该删除。
(g)它给出了应用运行所需AndroidAPI版本的最低要求。
(h)它列出了应用程序需要调用的开发库定义。
1.2. 清单文件的一些细节
(a)一个应用程序可以创建多个桌面图标;
(b)创建快捷图标的方法(程序多个启动入口):
<activity
android:name="com.itheima.receiverice.MainActivity"
android:label="@string/app_name" >
<intent-filter>
//应用程序的入口
<action android:name="android.intent.action.MAIN" />
//启动器
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
(c)activity的label标签中的值是这个activity界面的标题名称;
(d)activity的label标签中的值也是它的桌面快捷图标的名称;
(e)application中的label标签和activity中的label标签不是一个概念,application中的label表示应用程序的名称,activity中的label标签表示的是它的界面的名称;
(f)action:表示动作,可以自定义,也可以使用系统定义的action;
(g)category:表示类型
类型 | 含义 |
---|---|
android.intent.category.LAUNCHER | 启动器 |
android.intent.category.DEFAULT | 默认类型,一般使用这个默认类型 |
android.intent.category.CAR_DOCK | 指定手机被插入汽车底座(硬件)时运行该Activity |
android.intent.category.CAR_MODE | 设置该Activity可在车载环境下使用 |
2. 使用意图开启界面
Intent 意图:做一件事情的想法,如:吃饭,打人,喝茶。
Intent包含动作:action,数据:data
Intent的作用:激活组件和携带参数。
2.1. 设计Intent 的目的
意图设计的目的:解耦,实现应用程序的高内聚、低耦合。保证应用程序之间能够相互独立运行,又能彼此相互调用。
2.2. 显式意图
显式意图通过指定应用的包名和类名开启界面。应用场景:开启自己的应用界面。
首先我们编写下面两个界面,点击按钮计算跳转到第二个页面:
点击按钮跳转到第二个界面:
public void click(View view){
//创建意图对象,参数1是上下文,参数2是需要跳转的Activity
Intent intent = new Intent(MainActivity.this,ResultActivity.class);
//下面两行注释的代码是另一种创建意图对象的方法,首先创建意图对象,然后给意图对象设置类名,参数1代表包名,参数2代表需要开启的Activity的全路径名
//Intent intent = new Intent();
//intent.setClassName("com.itheima.rpcalc","com.itheima.rpcalc.ResultActivity");
//开启意图
startActivity(intent);
}
2.3. 隐式意图
通过指定一组动作或者数据开启一个activity。应用场景:开启别的应用的界面,不是自己应用的界面。
首先我们编写下面两个界面:
点击计算,跳转到第二个页面:
我们需要给第二个页面的Activity配置intent-filter:
<activity
android:name="com.itheima.rpcalc.ResultActivity"
android:label="@string/app_name" >
<intent-filter>
//配置Activity的action
<action android:name="com.itheima.result" />
//配置Activity的类型,一般默认android.intent.category.DEFAULT
<category android:name="android.intent.category.DEFAULT" />
//配置data,其中有mineType,scheme等
<data android:scheme="itheima" />
</intent-filter>
</activity>
对于mineType类型,我们可以查看tomcat中的config目录下的web.xml文件,其中extension标签表示的是该类型的扩展名:
点击“计算”按钮,跳转到第二个页面:
//创建意图对象
Intent intent = new Intent();
//设置意图的action
intent.setAction("com.itheima.result");
//设置意图携带的数据
intent.setData(Uri.parse("itheima:"+"nihao"));
//设置意图的category属性
intent.addCategory("android.intent.category.DEFAULT");
//调用Context的startActivity()开启意图
startActivity(intent);
2.4. 打开浏览器案例
本案例实现在EditText输入网址路径,点击按钮跳转到浏览器打开网页。以下是布局页面:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<EditText
android:id="@+id/et_path"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入您想访问的路径" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:onClick="click"
android:text="浏览" />
</RelativeLayout>
点击按跳转到浏览器:
public void click(View view){
//获取EditText中的数据
String path = et_path.getText().toString().trim();
Intent intent = new Intent();
//设置Action为Intent.ACTION_VIEW
intent.setAction(Intent.ACTION_VIEW);
//设置Data,参数为一个URI类型的数据,利用Uri.parse()方法
intent.setData(Uri.parse(path));
//开启Activity
startActivity(intent);
}
测试结果:
当我们打开模拟器的浏览器应用,查看日志输出打开的activity:
通过分析日志,可以看到浏览器的Activity是BrowserActivity,除了使用隐式意图打开浏览器外还可以通过显式意图来打开浏览器。但是如果使用显式意图打开浏览器,就只能打开系统默认的浏览器应用,这样就限制了意图打开应用的个数,所以使用显式意图就大大增加了应用程序的耦合。
2.5. URI和URL介绍及区别
URI统一资源标识符(Uniform Resource Identifier),用来表示某一互联网资源名称的字符串。
URL统一资源定位符(Uniform Resource Locator),是可以从互联网上得到资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。
就Android平台而言,URI主要分三个部分:scheme,authority,path。其中authority又分为host和port。格式如下:
scheme://host:port/path
URL和URI的区别:URL是URI的子集。
2.6. 人品计算器案例
该案例实现在EditText中输入姓名,选择性别,点击计算按钮,跳转到第二个页面,并且第二个页面根据输入的名字和选择的性别计算生成人品分值并且显式在界面上。那么如何将第一个界面的数据传递给第二个页面呢?通过该案例可以掌握Intent传递数据。
第一个页面布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<EditText
android:id="@+id/et_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入姓名" />
<RadioGroup
android:id="@+id/rg_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<RadioButton
android:id="@+id/rb_male"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="男" />
<RadioButton
android:id="@+id/rb_female"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="40dp"
android:text="女" />
<RadioButton
android:id="@+id/rb_other"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="40dp"
android:text="人妖" />
</RadioGroup>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="click"
android:text="计算" />
</LinearLayout>
第二个页面布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="张三" />
<TextView
android:id="@+id/tv_sex"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="男" />
<TextView
android:id="@+id/tv_result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="人品很好" />
</LinearLayout>
点击按钮实现Intent传递数据,利用数据计算出人品分值:
public void click(View v) {
String name = et_name.getText().toString().trim();
if (TextUtils.isEmpty(name)) {
Toast.makeText(getApplicationContext(), "请输入姓名", 0).show();
return;
}
int id = rg_group.getCheckedRadioButtonId();
int sex = 0;
switch (id) {
case R.id.rb_male: // 选中的男
sex = 1;
break;
case R.id.rb_female: // 选中的女
sex = 2;
break;
case R.id.rb_other: // 选中的人妖
sex = 3;
break;
default:
break;
}
if (sex == 0) {
//性别被选中
Toast.makeText(getApplicationContext(), "请选中性别", 0).show();
return;
}
Intent intent = new Intent(MainActivity.this, ResultActivity.class);
//通过intent的putExtra()方法,向intent中添加数据,将name和sex的值添加到intent中,参数1是数据的名称,参数2是数据的值
intent.putExtra("name", name);
intent.putExtra("sex", sex);
startActivity(intent);
}
结果页面获取第一个页面的数据,生成人品值:
//通过上下文获取到传递过来的意图对象,getIntent()
Intent intent = getIntent();
//调用intent.getString()方法,获取name的值,参数1表示数据的名称,如果获取不到,该方法返回null
String name = intent.getStringExtra("name");
//调用intent.getInt()方法,获取sex的值,参数1表示数据的名称,参数2表示如果获取不到返回的默认值
int sex = intent.getIntExtra("sex", 0);
TextView tv_name = (TextView) findViewById(R.id.tv_name);
TextView tv_sex = (TextView) findViewById(R.id.tv_sex);
TextView tv_result = (TextView) findViewById(R.id.tv_result);
tv_name.setText(name);
byte[] bytes = null;
try {
switch (sex) {
case 1: //男
tv_sex.setText("男");
bytes = name.getBytes("gbk");
break;
case 2: //女
tv_sex.setText("女");
bytes = name.getBytes("utf-8");
break;
case 3: //人妖
tv_sex.setText("人妖");
bytes = name.getBytes("iso-8859-1");
break;
default:
break;
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
int total = 0;
for (byte b : bytes) { // 0001 1111
int number = b&0xff; // 1111 1111
total += number;
}
score = Math.abs(total)%100;
if (score >90 ) {
tv_result.setText("您的人品非常好 .您家的祖坟都冒青烟了.....");
}else if(score >=70){
tv_result.setText("您的人品还可以 !!!");
}else if(score >=60){
tv_result.setText("您的人品刚刚及格");
}else{
tv_result.setText("您的人品太次了 赶快自己想想吧!!!");
}
2.7. 意图传递数据的类型
意图传递的数据类型:
1、8大基本数据类型、数组;
2、Bundle类似于map的数据结构;
3、Parcelable序列化到内存;
4、Serializable序列化到文件;
2.8. 短信大全案例
该案例实现功能有:ListView展示短信模板,通过点击ListView子条目,跳转到系统发送短信页面,并且将模板中的短信显式到系统短信发送页面输入框中。下图是效果图:
点击模拟器中发送短信页面,查看日志:
03-12 04:01:53.472: I/ActivityManager(861): Starting: Intent{dat=content://mms-sms/conversations/2cmp=com.android.mms/.ui.ComposeMessageActivity}from pid 1237
从日志中可以看到我们打开的activity是ComposeMessageActivity。我们到系统上层应用源码中找到这个activity的清单文件,查看该Activity的意图过滤器。如下图:
由于我们发送的短信是文本相关的,所以我们在intent-filter中找mimeType是文本的过滤器。这样我们找到如下过滤器:
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
页面布局:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</RelativeLayout>
Activity页面逻辑代码:
public class MainActivity extends Activity {
//模拟创建出短信内容
String objects[] = { "丫头,生活是你自己的,你哭它就对你哭,你笑它就对你笑。转眼,又是一年,你的生日即将来到。今年,还是少不了我对你的祝福,我忍不住...",
"世界上最动听的声音,是妈妈声声的呼唤;世界上最温暖的笑容,是妈妈温暖的笑
脸。妈妈,原谅生日时我不能陪在您身边,在这个日子里,我...",
"春天的鲜花,夏天的浪花,秋天的繁华,冬天的雪花,不论何时何地都希望你乐开
花,朋友,在这阳光明媚的日子,我为你放飞一群祝福,祝你...",
"我把春风织成一块温暖的毯子送给你,将幸福包住。我把春雨编成一条梦幻的丝带
送给你,把快乐缠住。我把春天挂满祝福送给你,让美好留住..." };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView lv = (ListView) findViewById(R.id.lv);
lv.setAdapter(new ArrayAdapter<String>(getApplicationContext(),R.layout.item, objects));
// 给listview设置点击事件
lv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,int position, long id) {
// 点击item获取我点击条目的内容
String data = objects[position];
// 把data传入到短信应用的发送界面 用隐式意图
Intent intent = new Intent();
// 设置动作
intent.setAction("android.intent.action.SEND");
intent.setType("text/plain");
intent.addCategory("android.intent.category.DEFAULT");
intent.putExtra("sms_body", data);
startActivity(intent);
}
});
}
}
给intent添加数据。那么这个key应该写什么呢?我们需要上层应用短信应用源码中查找。由于短信页面需要通过intent获取到携带过来的短信数据,所以我们可以在源码中搜索getStringExtra()搜索,最终我们搜索到了我们需要的代码如下图:
2.9. 短信发送小案例
主页面:
点击“+”按钮跳转到选择联系人界面:
点击插入短信模板跳转到短信模板页面:
选择短信模板返回到主页面:
点击发送后,将短信发送出去。
本案例最主要需要掌握:
(a)开启Activity,当关闭该Activity后获取返回值;
(b)发送短信。
开启Activity获取返回值步骤:
1 在开启activity时调用以下方法:
startActivityForResult(intent, 200);
2 在目标activity中设置关闭时返回的数据
Intent intent = new Intent();
intent.putExtra("username", username);
setResult(0, intent);
3 关闭目标Activity
finish();
4 重写onActivityResult()方法接收返回的数据。
在MainActivity中点击“+”号跳转到联系人界面:
public void click(View v){
Intent intent = new Intent(MainActivity.this,ContactActivity.class);
//调用startActivityForResult()跳转到联系人界面,并且等待返回数据。参数1是意图对象,参数2是请求码
startActivityForResult(intent, 10);
}
在联系人界面点击联系人条目将数据返回给MainActivity:
lv_contact.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Person person = contactLists.get(position);
String phone = person.getPhone();
Intent intent = new Intent();
intent.putExtra("phone", phone);
//通过调用setResult()方法将数据返回给MainActivity。参数1是结果码,参数2是携带数据的意图对象
setResult(10, intent);
//调用finish()方法用来关闭联系人Activity
finish();
}
});
MainActivity中重写onActivityResult()方法用来接收联系人界面返回的联系人号码:
//requestCode参数是请求码,resultCode参数是结果码。使用requestCode,resultCode来判断是哪个业务逻辑界面返回的数据
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
//requestCode请求码。由于Activity可能会打开多个其他的Activity并且获得返回数据,所以用requestCode请求码来区分获取的是哪个Activity的返回值
if (requestCode == 10) {
//获取Intent中的phone数据
String phone = data.getStringExtra("phone");
et_phone.setText(phone);
}else if(requestCode == 20){
String smsContent = data.getStringExtra("smscontent");
et_sms_body.setText(smsContent);
}
super.onActivityResult(requestCode, resultCode, data);
}
由于插入短信模板功能和选择联系人功能类似,所以这边不再阐述。
点击发送发送短信:
public void send(View v){
String phone = et_phone.getText().toString().trim();
String smsBody = et_sms_body.getText().toString().trim();
//通过SmsManager.getDefault()方法创建SmsManager管理类
SmsManager smsManager = SmsManager.getDefault();
//调用smsManager.divideMessage()方法将短信分割
ArrayList<String> divideMessages = smsManager.divideMessage(smsBody);
//遍历分割的短信集合,通过smsManager的sendTextMessage()方法发送短信。参数1是电话号码,参数2是服务中心地址,参数3是发送的内容,参数4是发送成功的广播,参数5是消息发送给接受者的广播
for (String smsContent : divideMessages) {
smsManager.sendTextMessage(phone, null, smsContent, null, null);
}
}
3. Activity生命周期
3.1. 生命周期的概念
举例:人被生下来,经历幼年、童年、青年、中年、老年。
从被创建到销毁经历几个阶段,每个阶段就表示一个方法,这些方法就是生命周期的回调。
3.2. Activity的生命周期
生命周期方法 | 调用时间 |
---|---|
onCreate() | 当Activity第一次创建的时候调用 |
onDestory() | 当Activity销毁的时候调用 |
onStart() | 当Activity变成可见的时候调用 |
onStop() | 当Activity不可见的时候调用 |
onResume() | 当Activity可以和用户交互的时候调用 |
onPause() | 当Activity不可和用户交互的时候调用 |
onRestart() | 当Activity停止了,但是没有销毁,从停止到启动时调用 |
下图是Activity生命周期图:
从图解可知一个Activity有三个生命循环,如下图所示:
从上图api文档中可以知道Activity的生命周期有三个循环:
(1)完整生命周期:从onCreate(Bundle)开始到onDestory()结束。Activity在onCreate()设置的所有“全局“状态,onDestory()释放所有的资源。
(2)可见生命周期:从onStart()开始到onStop()结束。在这段时间,可以看到Activity在屏幕上,尽管可能不在前台,不能和用户交互。在两个接口之间,需要保持显式给用户UI的数据和资源等。
(3)前台生命周期:从onResume()开始到onPause()结束,在这段时间里,该Activity处于所有Activity的最前面,和用户进行交互。
Activity的整个生命周期都定义在对应的接口方法中,所有方法都可以被重载。所有的Activity都需要实现 onCreate(Bundle)去初始化设置,大部分Activity需要实现onPause()去提交更改过的数据。
3.3. 横竖屏切换的生命周期变化
模拟器中,按快捷键Ctrl+F11进行横竖屏切换。生命周期变化如下:
onPause()-onStop()-onDestory()-onCreate()-onStart()-onResume()
从上面横竖屏切换的生命周期变化可以知道:当横竖屏切换时先销毁当前的Activity实例,再创建一个新Activity实例。
3.4. 横竖屏配置
我们知道:在横竖屏切换时,Activity会销毁,然后再重新创建。那么,如何操作才能使在切屏之后数据显式保持原来而不变呢? 解决方案如下:
(a)在AndroidManifest.xml中配置横竖屏:
android:screenOrientation=”portrait” 竖屏
android:screenOrientation=”landspace” 横屏
<activity
android:screenOrientation="portrait"
android:name=".MainActivity"
android:label="@string/app_name" >
</activity>
上述配置,在清单文件中指定了屏幕的方向,即为“portrait”竖直方向。同理,我们也可以写死为横屏,即android:screenOrientation=”landscape”。若不指定该属性的值,默认情况下该值为“sensor”,即根据传感器来自动设置屏幕的方向。
(b)设置系统的环境,使其不再敏感横竖屏的切换。让系统不再敏感横竖屏切换可以在activity中设置:
android:configChanges=”orientation|keyboardHidden|screenSize”
以下是configChanges中各个值的含义:
参数 | 含义 |
---|---|
configChanges=”orientation” | 屏幕方向改变:不让屏幕在切换时重新创建activity。 |
sreensize | 屏幕大小 |
keyboardHidden | 软键盘,如果切换屏幕,软键盘会去判断屏幕大小是否合适显式软键盘,在判断过程中会重启activity |
4. 任务栈
4.1. 栈的概念
栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据。栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针。栈可以用下图表示:
4.2. 队列的概念
队列也是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。通过对栈和队列的比较,我们知道:栈是先进后出,后进先出;队列是先进先出,后进后出。队列可以用下图表示:
4.3. 任务栈的概念
任务栈:任务栈是用来提升用户体验而设计的,记录打开界面和关闭界面的信息。每开启一个应用程序,android操作系统就会给这个应用程序分配一个任务栈。
一般情况下每个应用程序一开启就会创建一个任务栈,任务栈的id是自动增长的。
最小化的时候,应用程序实际上是后台运行,任务栈是保留的,当Activity退出了实际上就是任务栈清空了。
通过调用getTaskId()方法,可以获取当前任务栈的Id。
5. Activity的启动模式
在AndroidManifest.xml中,可以配置每个activity的启动模式:例如:
android:launchMode="standard"
(a)standard 标准模式
此模式,不管有没有已存在的实例,都生成新的实例。每次调用startActivity()启动Activity时都会创建一个新的Activity放在栈顶,每次返回都会销毁实例并出栈,可以重复创建。
(b)singletop 单一顶部模式
如果任务栈的栈顶存在这个要开启的activity,不会重新创建新的activity,而是复用已存在的activity。保证栈顶如果存在,则不会重复创建,但如果不在栈顶,那么还是会创建新的实例。
应用场景:浏览器的书签
(c)singletask 单一任务模式
是一个比较严格的模式,在当前任务栈里面只能有一个实例存在,当开启activity的时候,就去检查在任务栈里面是否有实例已经存在,如果有实例存在就复用这个已经存在的activity,并且把这个activity上面的所有的别的activity都清空,复用这个已经存在的activity。
应用场景:BrowserActivity浏览器界面,播放器的播放Activity
如果一个activity的创建需要占用大量的系统资源(cpu,内存)一般配置这个activity为singletask的启动模式。webkit内核(c) 初始化需要大量内存如js解析引擎、html渲染引擎、http解析、下载…如果使用singletask模式,可以减少内存开销,cpu占用。
(d)singleInstance
这种启动模式比较特殊,它会启用一个新的任务栈,activity会运行在自己的任务栈里,这个任务栈里面只有一个实例存在并且保证不再有其他Activity实例进入。在整个手机操作系统里面只有一个实例存在。
应用场景:来电页面。InCallScreenActivity
以上是关于Android基础第七篇的主要内容,如果未能解决你的问题,请参考以下文章