第一行代码读书笔记
基础
创建活动
- 包->New->Acitivity->Empty Activity
- Generate Layout File:自动创建对应的布局文件
Laucher Activity:自动将该活动设置为当前项目的主活动
Backwards Compatibility:启用向下兼容的模式 - 任何活动都应该重写onCreate()方法
- AppCompatActivity:一种向下兼容的Activity
创建布局
- res->New->Directory(layout)
layout->Layout resource file - Design/Code
- 添加按钮
<Button android:id="@+id/button_1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button 1" />- id:唯一标识符 引用id:@id/id_name 定义id:@+id/id_name
- layout_width/layout_height:宽度/高度
- match_patrent:与父元素相同 wrap_content:宽/高刚好包含里面的内容
- text:元素中显示的文字内容
- 加载布局:在
onCreate()方法中加入setContentView(R.layout.first_layout); - 资源调用:
R.(string/drawable/mipmap/layout).resource_name@(string/drawable/mipmap/layout)/resource_name
注册活动
- 在
AndroidManifest文件中注册(新建活动时Android Studio自动添加<activity>标签) - 配置主活动:在
<activity>标签中加入<intent-filter>标签<activity android:name=".FirstActivity" android:label="This is FirstActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>- label:活动中标签栏的内容/(启动器中)应用显示的名称
- 主活动:点击桌面应用程序图标时首先打开的活动
在活动中使用Toast
- 弹出信息通知,一段时间后自动消失,不占用屏幕空间
- 定义触发点:在
onCreate()方法中添加Button button1 = (Button) findViewById(R.id.button_1); button1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(FirstActivity.this, "You click Button 1", Toast.LENGTH_SHORT).show(); } });findViewById():获取在布局文件中定义的元素
返回View对象,向下转型成ButtonsetOnClickListener:注册监听器- 静态方法
makeText创建Toast对象
第一个参数:上下文Context,活动本身Activity.this就是一个Context对象
第二个参数:Toast显示的文本内容
第三个参数:Toast显示的时长(内置常量Toast.LENGTH_SHORT和Toast.LENGTH_LONG)
记得Import包或设置自动导入
在活动中使用Menu
- res->New->Directory(menu)
menu->Menu resource file - 在
main.xml中添加<item android:id="@+id/add_item" android:title="Add" /> <item android:id="@+id/remove_item" android:title="Remove" />- 创建具体的菜单项
- id:指定标识符
- title:指定名称
- 在
activity.java中重写onCreateOptionsMenu()(重写快捷键Ctrl+O)@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; }getMenuInflater():得到MenuInflater对象inflate():为当前活动创建菜单
第一个参数:通过哪个资源文件创建菜单
第二个参数:指定创建的菜单项添加到哪一个Menu对象中
返回true:显示菜单(false不显示)
- 在
activity.java中重写OnOptionsItemSeletected()@Override 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():判断点击的是哪一个菜单项
给每一个菜单项加入逻辑处理
销毁活动
- 按
Back键 - 调用
finish()button1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } });
Intent
显式Intent
Intel(Context packageContext, Class<?> cls)
Context:启动活动的上下文
Classs:启动的活动目标
构建Intent的意图StartActivity(Intent intent)- 在
FirstActivity的基础上SecondActivityIntent intent = new Intent(FirstActivity.this, SecondActivity.class); StartActivity(intent);
隐式Intent
- 不明确指出启动哪个活动
指定抽象的action和category等信息
由系统分析并找到合适的活动去启动 - 通过配置
<action>标签中的<intent-filter>指定活动可以响应的action和category -
<intent-filter> <action android:name="com.example.activitytest.ACTION_START" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> - 只有
anction和category中的内容同时匹配Intent,这个活动才能响应 -
Intent intent = new Intent("com.example.activitytest.ACTION_START"); StartActivity(intent); - 每个
Intent只能指定一个action
但能指定多个category Intent增加categoryintent.addCategory("com.example.activitytest.MY_CATEGORY");- 隐式
Intent可以启动其他程序的活动->多个应用程序间的功能共享
E.g.Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse("http://www.baidu.com"));- Intent.ACTION_VIEW:Android系统内置动作 常量值为android.intent.action.VIEW
- Uri.parse():将网址字符串解析成Uri对象
- setData():用于指定Intent当前操作的数据
<intent-filter>中配置<data>标签android:scheme:指定数据的协议部分android:host:指定数据的主机名部分android:port:指定数据的端口部分android:path:指定主机名和端口之后的部分android:mimeType:指定可以处理的数据类型 只有<data>标签中指定的内容和Intent中携带的Data完全一致时,当前活动才能响应该Intent 一般<data>标签中不会指定过多内容
- 调用
tel协议拨号Intent intent = new Intent(Intent.ACTION_DIAL); intent.setData(Uri.parse("tel:10086"));
向下个活动传递数据
- 重载
putExtra() - 传递字符串给SecondActivity
String data = "Hello SecondActivity"; Intent intent = new Intent("com.example.activitytest.ACTION_START"); intent.putExtra("extra_data", data); startActivity(intent);- 第一个参数:key,用于取值
- 第二个参数:传递的值
- 在SecondActivity中取出数据
Intent intent = getIntent(); String data = intent.getStringExtra("extra_data");- getIntent():获取用于启动当前活动的Intent
- getStringExtra():获取传递的字符串数据
getIntExtra():获取传递的整型数据
getBooleanExtra():获取传递的布尔型数据
etc.
返回数据给上一个活动
startActivityForResult()启动活动并期望活动销毁时返回结果给上一个活动
第一个参数:Intent
第二个参数:请求码,用于在之后的回调中判断数据的来源- In FirstActivity:
Intent intent = new Intent(FirstActivity.this, SecondActivity.class); startActivityForResult(intent, 1); - In 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(); } });- setResult():向上一个活动返回数据
第一个参数:返回处理结果,一般只用RESULT_OK或RESULT_CANCELED第二个参数:把带有数据的Intent传回去
- setResult():向上一个活动返回数据
- 使用
startActivityForResult()启动的活动,销毁时会回调上一个活动的onActivityResult()
在FirstAcitivity中重写这个方法来得到返回的数据@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("FirstAcitivity", returnedData); } break; default: } }- requestCode:启动活动时传入的请求代码
resultCode:返回数据时传入的处理结果
data:携带着返回数据的Intent - 一个活动中可能调用
startActivityForResult()启动很多不同的活动
每个被启动的活动返回的数据都会回调onActivityResult()
先检查requestCode判断数据来源
再检查resultCode判断处理结果是否成功 最后从data中取值
- requestCode:启动活动时传入的请求代码
- 通过Back键返回的活动:重写
onBackPressed()@Override public void onBackPressed() { Intent intent = new Intent(); intent.putExtra("data_return", "Hello FirstActivity"); setResult(RESULT_OK, intent); finish(); }
- In FirstActivity:
活动的生命周期
返回栈
- 一个任务就是一组存放在栈里的活动的集合
活动状态
- 运行状态
- 位于返回栈的栈顶
- 系统最不愿意回收的
- 暂停状态
- 不再处于栈顶但仍然可见
- 系统不愿意回收的(只有内存极低时)
- 停止状态
- 不再处于栈顶并完全不可见
- 系统会为其保存相应的状态和成员变量,但又可能会被回收(其他地方需要内存时)
- 销毁状态
- 从返回栈中移除后
- 最倾向于回收的
活动的生存期
- 7个回调方法
onCreate()
- 在活动第一次被创建时调用
- 活动初始化(加载布局、绑定事件)
onStart()
- 由不可见变为可见时调用
- 资源加载
onResume()
- 在活动准备好和用户进行交互时调用
- 此时活动一定位于返回栈的栈顶,并处于运行状态
onPause()
- 在系统准备启动或恢复另外一个活动时调用
- 一般在这个方法中释放一些CPU资源,并保存一些关键数据
- 执行速度一定要快
- 启动对话框式的活动时会执行
onStop()
- 在活动完全不可见时调用
- 启动对话框式的活动时不会执行
- 释放资源(不占用过多内存)
onDestroy()
- 在活动被销毁钱调用
- 释放内存
onRestart()
- 在活动由停止状态变为运行状态钱被调用(重新启动)
- 3种生存期
- 完整生存期
onCreate()和onDestroy()之间
- 可见生存期
onStart()和onStop()之间- 可见的,又可能无法和用户交互
- 前台生存期
onResume()和onPause()之间- 总是处于运行状态,可以和用户交互
将活动设置为对话框:在<activity>标签中添加属性
android:theme="@android:style/Theme.Dialog"
活动被系统回收
- 在活动A的基础上启动了活动B,活动A被系统回收,用户按Back键返回活动A:
不执行onRestart()而是执行OnCreate()->临时数据和状态消失 onSaveInstanceState()可以保证在活动被回收前一定会被调用
携带一个Bundle类型的参数可以保存数据- putInt(), putString()...
- 第一个参数是key,用于从Bundle中取值 第二个参数是要保存的内容
onCreate()有一个Bundle类型的参数(带有之前保存的数据)Intent也可以用Bundle传递数据
活动的启动模式
standard
- 默认
- 每启动一个新的活动,都会在返回栈中入栈并处于栈顶
- 系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新实例
singleTop
- 启动活动时如果已经存在于栈顶,则直接使用它
- 不在栈顶则创建一个新的实例
singleTask
- 启动活动时检查返回栈中是否存在该活动的实例
- 如果存在则直接使用该实例(不在栈顶会调用onRestart()),并把这个活动之上的所有活动全部出栈
- 没有发现存在的实例则创建新实例
- (如果指定了不同的taskAffinity,也会启动一个新的返回栈)
singleInstance
- 启用一个新的返回栈来管理这个活动
- 不管哪个应用程序来访问这个活动,共用同一个返回栈
其他
定位当前界面的活动
getCalss().getSimpleNAme()
随时注销/退出程序
- 用一个专门的集合类(e.g. List)对所有活动进行管理
killProcesss():接收一个进程id参数,杀掉一个进程(只能用于杀掉当前程序的进程)
myPid():获得当前程序的进程id