第01讲 Android开发系列---Activity
一. Android系统版本及详细信息
最新数据 https://developer.android.com/about/dashboards/
二. Android项目初探
1. 使用android studio创建一个工程
Application Name:“My First App”
Company Domain:“example.com”
Project和module联系和区别
一个 Project 可以有多个 Module。目前主流的大型项目是多Module结构的,模块之间彼此可以相互依赖。他们之间应该都是处于同一个项目业务情况下的模块,彼此之间是有不可分割的业务关系的。
Android studio中,一个Project代表一个完整的APP,Module表示APP中的一些依赖库或独立开发的模块。比如可以新建一个library做为module,然后在主APP上点右键 open module setting的Dependencies中添加一个模块依赖。然后主APP中就可以使用module中的类了。
2. 目录结构
Android视图
Project视图
关于gradle.build文件参考: https://developer.android.google.cn/studio/build/index.html
3. Logcat的使用
日志打印工具
方法 |
级别 |
Log.v() |
verbose |
Log.d() |
debug |
Log.i() |
info |
Log.w() |
warn |
Log.e() |
error |
注意:在android studio中创建一个activity 为我们完成了三步:(继承自AppCompatActivity是为了向后兼容)
创建activity、在menifest中注册activity、创建activity对应的layout文件
4. 隐藏标题栏
方法一:
继承自AppCompatActivity:
if (getSupportActionBar() != null){
getSupportActionBar().hide();
}
方法二: 在style中加入如下代码: <item name="windowNoTitle">true</item>
5.
在活动中使用Toast
Toast.makeText(this,"you
clicked",Toast.LENGTH_SHORT).show();
6.
在活动中添加菜单
(1)添加菜单xml文件:
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/add_item"
android:title="add"/>
<item
android:id="@+id/delete_item"
android:title="delete"/>
</menu>
(2)重写onCreateOptionsMenu方法
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main,menu);
return
true; //返回true表示显示该菜单
}
(3)重写onOptionsItemSelected
public boolean onOptionsItemSelected(MenuItem item){
switch(item.getItemId()){
case R.id.add_item:
Toast.makeText(this,"add clicked",Toast.LENGTH_SHORT).show();
break;
case R.id.delete_item:
Toast.makeText(this,"delete
clicked",Toast.LENGTH_SHORT).show();
break;
}
return true;
}
更多详情参见考:https://developer.android.google.cn/guide/topics/ui/menus
7.
销毁活动
finish(); //第一讲到此+java预备知识
三. Android事件处理
Android提供了两套事件处理机制:监听、回调
1.
基于监听的事件处理
事件监听的处理模型中,主要涉及三类对象:
Event Source(事件源) 通常是各个组件,如按钮、窗口、菜单等;
Event(事件):事件封装了界面组件上发生的特定事情。
Event Listener(事件监听器):负责监听事件源所发生的事件,并对各种事件作出相应的相应。
事件监听涉及的三个问题:
事件源:
任何组件都可作为事件源。
事件监听器:由程序员实现,关键是实现处理方法。
注册监听器:调用事件源的setXxxListener方法即可。
另外:对于键盘事件、触摸屏事件等,此时程序需要获取事件发生的详细信息。如,键盘事件获取是哪个键触发的,触摸屏事件需要获取事件发生的位置的,Android会将事件信息封装成XxxEvent对象,并将该对象作为参数传递给事件处理器。
所谓事件监听器,其实就是实现了特定接口的java类的实例。实现事件监听器,通常有如下几种形式:
l 内部类
l 匿名内部类
l 外部类
l Activity本身作为事件监听器
l 直接绑定到标签
其他事件如下表所示:
|
setOnClickListener Register a callback to be invoked when this view is |
|
setOnContextClickListener Register a callback to be invoked when this view is |
|
setOnCreateContextMenuListener Register a callback to be invoked when the context |
|
setOnDragListener Register a drag event listener callback object for |
|
setOnFocusChangeListener Register a callback to be invoked when focus of |
|
setOnGenericMotionListener Register a callback to be invoked when a generic |
|
setOnHoverListener Register a callback to be invoked when a hover |
|
setOnKeyListener Register a callback to be invoked when a hardware |
|
setOnLongClickListener Register a callback to be invoked when this view is |
|
setOnScrollChangeListener Register a callback to be invoked when the scroll X |
|
setOnTouchListener Register a callback to be invoked when a touch |
2.
基于回调的事件处理
当用户在GUI组件上激发某事件时,组件自己的特定方法负责处理该事件。方法是自定义控件使其继承GUI组件类,在自定义控件中重写事件处理方法。
Demo
l 基于回调的事件传播
几乎所有基于回调的事件处理方法都有一个boolean类型的返回值,用于标志该处理方法是否已完全处理该事件。
返回true,表明已处理完,不会传播出去。
返回false,表明未处理完,会传播出去。
几种方法调用的先后顺序: 组件的监听器à组件自身的回调方法à组件所在Activity的回调方法。其中任何一个事件处理方法返回了true,那么该事件将不会继续向外传播。
四. 启动活动的方法:
1.
显式Intent demo
//第一个参数Context是启动活动的上下文,第二个参数是制定要启动的目标活动。
Intent intent=new
Intent(MainActivity.this,SecondActivity.class);
startActivity(intent);
2.
隐式Intent demo
不明确指定启动哪一个活动,而是指定一系列action 和category,由系统分析启动哪一个活动。只有<action>和<category>中的内容同时能匹配上Intent中指定的action和category时,这个活动才能响应该Intent。
每个Intent只能指定一个action,但可以指定多个category。如果没有匹配的活动可以启动程序将崩溃;如果有多个匹配的活动,系统将提供列表让用户选择启动哪个活动。
显示引用不能启动其他进程的Activity对象,因为无法获取其他进程的Activity对象的字节码,而隐式启动则可以通过配置Intent Filter启动其他进程的Activity对象,因此在应用内,我们一般都是使用显示启动的方式启动Activity,而如果需要启动其他应用的Activity时,一般使用隐式启动的方式。
l 更多隐式Intent的用法
调用系统的浏览器打开一个网页。
Intent intent=new
Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
Uri.parse() 将字符串解析成一个Uri对象。setData() 方法接收一个Uri对象,指定当前Intent正在操作的数据。
只有<data>标签中指定的内容和Intent中携带的data完全一致时,当前活动才能相应该Intent.
<data> 使用一个或多个指定数据 URI 各个方面(scheme
、host
、port
、path
等)和 MIME 类型的属性,声明接受的数据类型。
https://developer.android.google.cn/guide/components/intents-common#Browser
五. 活动之间传递数据
1.
向下一个活动传递数据
Intent intent=new Intent(MainActivity.this,SecondActivity.class);
intent.putExtra("extraData_Key","I am data");
startActivity(intent);
在下一个活动中将数据取出:
Intent intent=getIntent();
String data=intent.getStringExtra("extraData_Key");
使用Bundle
两个Activity交换数据通过Intent完成,只需将交换的数据放入Intent中即可。
putExtra(String
key, Xxx value) 向Intent中按key-value对的形式存入数据
Xxx getXxxExtra(String
key) 从Intent中按key取出指定类型的数据
putExtras(Bundle
data) 向Intent中存入携带数据的Bundle
Bundle getExtras() 从Intent中取出携带数据的Bundle
向Bundle对象中存取数据:
putXxx(String
key, Xxx data) 向Bundle中放入Xxx类型的数据
Xxx getXxx(String key) 从Bundle中取出Xxx类型的数据
putSerializable(String
key, Serializable data) 向Bundle中放入一个可序列化的对象
Serializable getSerializable(String key) 从Bundle中取出可序列化对象
2.
返回数据给上一个活动
1)
启动活动时使用onActivityResult方法:
startActivityForResult(intent,1);
2)
重写onActivityResult()方法,对返回的数据进行处理:
protected
void onActivityResult(int requestCode, int resultCode, @Nullable Intent data)
{
switch (requestCode){
case 1:
if(resultCode==RESULT_OK) {
String
returnedData=data.getStringExtra("data_return");
Log.d(TAG,
"onActivityResult: "+returnedData);
}
break;
}
}
3)
在第二个活动中返回数据:
setResult(RESULT_OK,intent);
finish();
六. 活动的生命周期
1.
返回栈(Back Stack)
每启动新的活动,就会覆盖在原来的活动上,按Back键会销毁上面的活动,下面的活动就会重新显示出来。
Android使用Task来管理活动,一个Task就是一组存放在栈里的活动的集合,这个栈被称为返回栈(Back Stack)。参见activity返回栈。
2.
活动状态
l 运行状态
l 暂停状态
l 停止状态
l 销毁状态
3.
活动的生存期
4.
体验活动的生命周期 (Demo: ActivityLifeCycle)
5.
活动被回收了怎么办
由于内存不足等原因,处于停止状态的活动有可能被系统回收。当该活动重新可见时,该活动会被重新创建。
onSaveInstanceState()方法在活动被回收之前调用,解决活动被回收时保存临时数据的问题。
1) 活动回收前保存数据
protected
void onSaveInstanceState(Bundle outState) {
outState.putString("data_key","I am data"); //保存数据
super.onSaveInstanceState(outState);//必须调用父类的方法
}
2) 活动恢复时恢复数据
在onCreate方法中恢复:
protected
void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Always call the
superclass first
if (savedInstanceState != null) {
String
str=savedInstanceState.getString("data_key");//得到数据
Log.d("MainActivity", "活动恢复,数据为:"+str);
} else {
Log.d("MainActivity", "这是活动正常启动");
}
//……
}
在onRestoreInstanceState方法中恢复:
protected
void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);//可选
String
str=savedInstanceState.getString("data_key");//得到数据
Log.d("MainActivity", "恢复数据为:"+str);
}
注意:Always call the superclass implementation
of onRestoreInstanceState() so the default implementation can restore the state
of the view hierarchy.
开发者可根据具体情况选择在哪个方法中进行恢复。
3) onSaveInstanceState() 何时被执行
当某个activity变得“容易”被系统回收时,该activity的onSaveInstanceState就会被执行,除非该activity是被用户主动销毁的,例如当用户按BACK键(手机下方的返回键)的时候。(why)分为以下几种情况:
l 从第一个界面跳转到第二个界面,第一个界面就会执行onSaveInstanceState
l 按下home键,运行多个其他程序,这时系统不确定会不会将该activity销毁,所以会执行onSaveInstanceState方法保存值。
l 关闭手机屏幕时
l 屏幕方向切换时,例如从竖屏切换到横屏时。(前提是androidMenifest.xml中对应activity标签没有配置<activity android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize"></activity>)
4) onRestoreInstanceState() 何时被执行
Activity被系统回收后,当重新恢复时会调用onRestoreInstanceState(),并且是在onStart()之后。The
system calls onRestoreInstanceState()
only if there is a saved
state to restore, so you do not need to check whether the Bundle
is
null。
而系统创建一个新的Activity实例或重新创建一个以前的实例时都会调用onCreate(),因此在onCreate()中需要判断Bundle是否为null。
5) 模拟当前应用被系统回收
进入开发者选项,选中不保留活动。
6) 为什么我们的UI界面的值不用我们自己保存也可以自动保存,状态恢复呢?
开发者只需要为这些控件指定一个唯一的ID,剩余的事情就可以自动完成了。如果没有为控件指定ID,则这个控件就不会进行自动的数据保存和恢复操作。
更多参考:https://developer.android.google.cn/guide/components/activities/activity-lifecycle.html#saras
另外,onSavedInstanceState()只适合保存少量可序列化的数据。use
a combination of ViewModel
objects, the onSaveInstanceState()
method,
and/or local storage
to
persist the UI state across such application and activity instance transitions.
6.
活动的加载模式(Launch Mode)
Often, the
way Android manages tasks and the back stack by placing all activities started
in succession in the same task and in a "last in, first out" stack.
You can
interrupt the normal behavior, with attributes in the <activity>
manifest
element and with flags in the intent that you pass to startActivity().
Launch
modes allow you to define how a new instance of an activity is associated with
the current task.
<activity android:name=".SecondActivity" android:launchMode="singleTop"/>
l
standard
(the default mode)
无论当前栈顶是哪一个Activity都会开始一个新的Activity。
l
singleTop
如果需要创建的Activity已经处于任务(Task)栈顶时,复用该Activity。
l
singleTask
需要创建的Activity已经处于任务(Task)栈时,弹出此Activity上的所有其他Activity,复用该Activity。
l
singleInstance
启动一个新的任务(Task)栈,且该任务栈中只有这唯一一个Activity。整个系统中创建了该Activity,将不再重新创建。
当从返回栈回退时,如果当前回退栈为空了,才会显示另一回退栈的活动。
Demo四种启动模式演示
onNewIntent方法的使用
除了standard模式,其他三种方式都可能存在复用Activity的情况。通过Intent启到一个Activity,如果系统已经存在一个实例,系统就会将请求发送到这个实例上,但新的Intent请求可能要处理新的数据,而这时没有机会调用onCreate方法,怎么办呢?系统为我们准备了onNewIntent方法。
一般,通过在onCreate和onNewIntent方法中调用同一个处理数据的方法,使得不管是创建新的Activity实例,还是复用原来的Activity实例,处理数据的方式保持一致。如下所示:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
processExtraData();
}
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);//must store the new intent unless getIntent() will return the old one
processExtraData();
}
private void processExtraData(){
Intent intent = getIntent();
//use the data received here
}
第01讲 Android开发系列---Activity的更多相关文章
- 第01讲- Android背景知识
第01讲Android背景知识 Android是基于Linux系统 Android系统框图 : 第一.操作系统层(OS) 第二.各种库(Libraries)和Android 运行环境(RunTime) ...
- 第02讲- Android开发环境
第02讲Android开发环境 需要下载的软件: JDK(JavaDevelopment Kit) Eclipse AndroidSDK(SoftwareDevelopmentKit) ADT(And ...
- Android 开发系列教程之(一)Android基础知识
什么是Android Android一词最早是出现在法国作家维里耶德利尔·亚当1986年发表的<未来夏娃>这部科幻小说中,作者利尔·亚当将外表像人类的机器起名为Android,这就是And ...
- VS2015下的Android开发系列01——开发环境配置及注意事项
概述 VS自2015把Xamarin集成进去后搞Android开发就爽了,不过这安装VS2015完成的时候却是长了不知道多少.废话少说进正题,VS2015安装时注意把Android相关的组件勾选安装, ...
- Android开发之---Activity启动模式
在Android开发中,启动一个新的activity我们可以使用startActivity或startActivityForResult,Android系统使用栈的方式来管理一个APP的页面显示与保存 ...
- Android开发之---Activity生命周期
Android开发中,有四大组件:Activity.Service.Content Provider.Broadcast Receiver,可以说,activity的使用是最频繁的了,这里来梳理一下与 ...
- Android开发系列之按钮事件的4种写法
经过前两篇blog的铺垫,我们今天热身一下,做个简单的例子. 目录结构还是引用上篇blog的截图. 具体实现代码: public class MainActivity extends Activity ...
- Android开发系列之SQLite
上篇博客提到过SQLite,它是嵌入式数据库,由于其轻巧但功能强大,被广泛的用于嵌入式设备当中.后来在智能手机.平板流行之后,它作为文件型数据库,几乎成为了智能设备单机数据库的必选,可以随着安卓app ...
- Android开发系列之Android项目的目录结构
今天开始正式学习Android开发的种种细节,首先从最基本的概念和操作学起. 首先看一下Android项目的目录结构. 这是我随便建立的一个test项目,我们重点关注一下几个方面的内容: 1.src目 ...
随机推荐
- Java File类常用方法及实例
创建:createNewFile()在指定位置创建一个空文件,成功就返回true,如果已存在就不创建,然后返回false. createTempFile(String prefix, String s ...
- 个人收藏--未整理—C# http/https 上传下载文件
c# HTTP/HTTPS 文件上传. 分类: .net 2015-02-03 08:36 541人阅读 评论(0) 收藏 举报 方法主体 [csharp] view plaincopy public ...
- Rocket框架多文件上传,介绍rocket_upload 使用
不知道你的体会是什么,我从C切换到Rust以来,最大的感受并不是语法方面的---那些方面已经有足够多人抱怨而又享受着了.我最大的感受是终于把Web编程工具,同系统编程工具统一了起来. C/C++其实也 ...
- 程序员的进阶课-架构师之路(9)-平衡二叉树(AVL树)
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/de ...
- CSRF(Cross-site request forgery)跨站请求伪造
CSRF是什么 CSRF(Cross-site request forgery)跨站请求伪造,也被称为"One Click Attack"或者Session Riding,通常缩写 ...
- 负载均衡集群介绍、LVS介绍、LVS调度算法、LVS NAT模式搭建
7月4日任务 18.6 负载均衡集群介绍18.7 LVS介绍18.8 LVS调度算法18.9/18.10 LVS NAT模式搭建 扩展lvs 三种模式详解 http://www.it165.net/a ...
- requests库核心API源码分析
requests库是python爬虫使用频率最高的库,在网络请求中发挥着重要的作用,这边文章浅析requests的API源码. 该库文件结构如图: 提供的核心接口在__init__文件中,如下: fr ...
- KETTLE实现复杂的流程
KETTLE是一款将数据从来源端经过抽取(extract).转换(transform).加载(load)至目的端的非常好用的一款ETL工具.学会它,对于跨数据库的表处理或者定时生成文本,excel等常 ...
- ios 在APP内提示更新
http://www.jianshu.com/p/24daf5147bda ios如何在应用内部提示更新 两颗星 http://www.jianshu.com/p/2ba10a58bb02 ...
- Xcode 10 Error: Multiple commands produce
目录 Xcode 9.4.1运行react-native 可以,但是在Xcode 10运行报错,报错信息如下: 解决方法 1. 选择 File > Project Settings (或者 Fi ...