最近在学习安卓开发,觉得需要做下一些记录帮助自己更好地理解掌握,学习书籍《第一行代码》、《Android手机应用开发简明教程》,有一些是书上的内容的总结,有一些是自己的理解,只作为分享,不作商业用途,侵权必删,有兴趣的可以找找这两本书来看看,书上的更加全面。
文章目录
Android入门
一、项目目录结构
创建完第一个项目之后,点击左上角把项目结构模式转换成Project,可以得到
这里对目录结构进行解释
- .gradle和.idea放置的是AS自动生成的文件
- app 放置项目代码、资源
- build 放置编译时自动生成的文件
- gradle 包含了gradle warpper的配置文件
- .gitgnore 用来将制定的目录或文件排除在版本控制之外
- build.gradle 项目全局的gradle配置文件
- gradle.properties 全局的gradle配置文件,这里配置的属性将会影响到项目中所有的gradle编译脚本
- gradlew和gradlew.bat,用来在命令行界面中执行gradle命令的,其中gradlew是在Linux或Max系统中使用的,gradlew.bat是在Windows系统中使用的
- MyApplication2.iml,自动生成的文件,用于标识这是一个IntelliJ IDEA项目
- local.properties,用于指定本机中Android SDK 路径
- settings.gradle 用于 制定项目中引入的模块
接下来app目录下进行进一步的分析
- build 跟前面的build目录类似,也是包含一些在编译时自动生成的文件
- libs 放置第三方jar包
- androidTest 用来编写AndroidTest测试用例的,可以对项目进行一些自动化测试
- java 放置java代码
- res 放置项目中使用的图片、布局、字符串等资源
图片放在drawable下,布局放在layout下,字符串放在values下,mipmap用来放应用图标(兼容各种设备) - AndroidManifest.xml 整个项目的配置文件
- test 用来编写Unit Test 测试用例,对项目进行自动化测试的另一种方式
- .gitgnore 用于将app模块内指定的目录或文件排除在版本控制之外
- app.iml IntelliJ IDEA项目自动生成的文件
- build.gradle app模块的gradle构建脚本,指定很多项目构建相关的配置
- proguard-rules.pro 用于制定项目代码的混淆规则,当代码开发完成后打包成安装包文件,不易被阅读
二、AndroidManifest.xml解析
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.lenovo.helloworld">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
其中
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
这段代码表示对MainActivity这个活动进行注册
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
这段代码代表这个活动是这个项目的主活动,也就是点开这个应用的时候第一个访问的活动
三、MainActivity.java
package com.example.lenovo.helloworld;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
重写onCreate()方法,这个方法是一个活动被创建时一定要执行的方法
setContentView(R.layout.activity_main);
这个方法就是给当前的方法引入一个布局
四、布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.lenovo.helloworld.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</RelativeLayout>
五、build.gradle
(一)外层目录的build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
jcenter是一个代码托管仓库,声明了这行配置之后,就可以使用jcenter上的开源项目了
classpath 'com.android.tools.build:gradle:2.2.0'
声明了一个Gradle插件,要使用Gradle插件来构建Android项目,需要声明Gradle插件。
(二)app目录下的build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 24//项目的编译版本
buildToolsVersion "24.0.2"//项目构建工具的版本
defaultConfig {
applicationId "com.example.lenovo.helloworld"//包名
minSdkVersion 15//最低兼容的Android系统版本
targetSdkVersion 24//
versionCode 1//项目的版本号
versionName "1.0"//项目的版本名
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {//用于指定生成安装文件的相关配置
release {//release用于指定生成测试版安装文件的配置,如果是debug,则是指定声明正式版安装文件的配置
minifyEnabled false//指定是否对项目的代码进行混淆
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//指定混淆时使用的规则文件,'proguard-android.txt'是在Android SDK目录下的,里面是所有项目通用的混淆规则。proguard-rules.pro'是当前项目的根目录下的,里面可以编写当前项目特有的混淆规则
}
}
}
dependencies {//指定当前项目所有的依赖关系
compile fileTree(dir: 'libs', include: ['*.jar'])//
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:24.2.1'
testCompile 'junit:junit:4.12'
}
apply plugin: 'com.android.application'
应用了一个插件,表示这是一个应用程序模块,可以直接运行
apply plugin: 'com.android.library'
表示这是一个库模块,只能作为代码库依附于其他应用程序模块来运行
defaultConfig {
applicationId "com.example.lenovo.helloworld"//包名
minSdkVersion 15//最低兼容的Android系统版本
targetSdkVersion 24//
versionCode 1//项目的版本号
versionName "1.0"//项目的版本名
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {//用于指定生成安装文件的相关配置
release {//release用于指定生成测试版安装文件的配置,如果是debug,则是指定声明正式版安装文件的配置
minifyEnabled false//指定是否对项目的代码进行混淆
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//指定混淆时使用的规则文件,'proguard-android.txt'是在Android SDK目录下的,里面是所有项目通用的混淆规则。proguard-rules.pro'是当前项目的根目录下的,里面可以编写当前项目特有的混淆规则
}
}
Android Studio项目有三种依赖,本地依赖、库依赖和远程依赖
- 本地依赖可以对本地的jar包或目录添加依赖关系
- 库依赖可以对项目中的库模块添加依赖关系
compile project(‘:库名称’) - 远程依赖可以对jcenter库上的开源项目添加依赖关系
dependencies {//指定当前项目所有的依赖关系
compile fileTree(dir: 'libs', include: ['*.jar'])//本地依赖,将libs目录下所有.jar文件都添加到项目的构建路径中
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:24.2.1'//远程依赖
testCompile 'junit:junit:4.12'//声明测试用例库
}
六、日志工具Log
Android中的日志工具类是android.util.Log
- Log.v() 用来打印意义最小的日志信息。级别最低
- Log.d() 用来打印一些调试信息,级别比v高
- Log.i() 用来打印一些比较重要的数据 级别比d高
- Log.w()用来打印一些警告信息,级别比i高
- Log.e() 用来打印程序中的错误信息。级别比w高
七、活动Activity
活动是一种可以包含用户界面的组件,主要用于和用户进行交互
开发的一般步骤:
- 创建活动
- 创建布局
- 在活动中引入布局
- 在AndroidManifest文件中注册活动
(一)Toast
Toast是Android系统提供的一种提醒方式,可以用来发送一些短小的信息给用户,这些信息在一段时间后会消失
(1)如何使用Toast
举个例子,给button绑定一个监听器,使点击它的时候弹出一个Toast
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout);
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"you clicke Button1",Toast.LENGTH_SHORT).show();
}
});
}
}
调用button1的setOnClickListener方法,传入一个OnClickListener对象,并重写onClick方法,在这个方法中调用Toast的makeText()方法,这是一个静态方法,makeText()有三个参数,第一个是活动本身,第二个是Toast显示的文本内容,第三个是Toast显示的时长,有两个内置常量是Toast.LENGTH_SHORT和Toast.LENGTH_LONG;
(二)Menu
使用Menu,可以在程序的右上角提供一个小菜单
(1)Menu的使用
- 首先在res目录下创建一个menu文件夹,再在文件夹下新建一个Menu resource file
在这个Menu resouce file 的menu标签下添加item标签,菜单需要显示几项就添加几个item标签
<item android:id="@+id/one"
android:title="one"/>
<item android:id="@+id/two"
android:title="two"/>
- 到活动中重写onCreateOptionMenu()
调用getMenuInflater()方法获得一个MenuInflater对,再调用它的inflate方法就可以给这个活动创建菜单了。inflate方法有两个参数,第一个参数指定我们通过哪个资源文件来创建菜单,第二个参数指定将菜单项添加到哪一个Menu对象。然后返回true,表示允许创建的菜单显示出来。
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main,menu);
return true;
}
- 再重写onOptionsItemSelected()方法,来定义菜单相应事件
(三)销毁活动
有两种方式
- 使用Back键销毁
- 调用finish()方法
八、Intent
使用Intent可以在不同活动中进行切换
- 显示Intent
Intent有一个构造函数Intent(Context packageContext,Class<?> cls),第一个参数要求提供一个启动活动的上下文个参数Class指定想要启动的目标活动
创建Intent对象后,在主活动的onCreate()方法中调用startActivity方法,传递一个Intent对象进去,然后就可以启动目标活动了
- 隐式Intent
不明确指出想要启动哪个活动
在AndroidManifest注册活动的时候在activity标签下添加action标签跟category标签
<intent-filter>
<action android:name="com.example.lenovo.myapplication2.ACTION_START"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
再在主活动某个触发事件中,创建一个Intent对象,传递上面的android:name,在调用startActivity方法,把这个intent对象传递进去
例如,定义了一个按钮,当按钮被点击时,触发函数,启动想要启动的另外一个活动
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.lenovo.myapplication2.ACTION_START");
startActivity(intent);
}
});
(一)setData()
- Intent还有一个方法是setData(),接收一个Uri对象,它主要是用来指定当前Intent正在操作的数据,这些数据通常是以字符串的形式传入到Uri.parse()方法中解析产生的
(二)data标签
与setData相对应,我们可以在活动里的<intent-filter>
标签里再配置一个<data>
标签,用于指定当前活动能够响应什么类型的数据
data标签可以配置以下五个属性
- android:scheme,用于指定数据的协议部分
- android:host,用于指定数据的主机名部分
- android:port,用于指定数据的端口部分
- android:path,用于指定主机名和端口之后的部分
- android:mimeType,用于指定可以处理的数据类型
(三)使用intent向下一个活动传递数据
Intent中提供了一些列putExtra()方法,可以把想要传递的数据暂存在Intent中,当启动了另外一个活动后,再把这些数据用从Intent中取出。
(四)给上一个活动返回数据
- 可以使用startActivityForResult()这个方法,这个方法也是用来启动活动的,但是在当前活动结束的时候,会给上一个活动返回数据,这个方法接受两个参数,第一个是intent,第二个是一个请求码,只要是唯一值即可。
- 启动另外一个活动后,在onCreate方法使用putExtra方法向intent中存入数据,再调用setResult方法向上一个活动返回数据,这个方法有两个参数,第一个参数用于向上一个活动返回处理结果,一般只使用RESULT_OK或者RESULT_CANCELED,第二个参数则是intent。这种方法适用于使用finish方法返回上一个活动。
- 如果使用的是Back键回到上一个活动,可以在这个活动中重写onBackPressed方法来将数据返回上一个活动,存数据跟上面一样。
- 返回上一个活动后,会回调上一个活动的onActivityResult()方法,重写这个方法来得到返回的数据,onActivityResult方法有三个参数,第一个参数requestCode,就是我们在启动活动时传入的请求码,第二个参数resultCode,是我们返回数据传入的处理结果,第三个参数是data,就是携带数据返回的Intent。
(五)活动的生命周期
Android是使用任务来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也称为返回栈。每当我们启动了一个活动,它就会在返回栈中入栈,并处于栈顶的位置。每当我们销毁了一个活动,处于栈顶的活动就会出栈,是一种后进先出的结构。
与此对应的,每个活动对应着4种状态
- 运行状态,当一个活动位于栈顶的时候,这个活动就处于运行状态
- 暂停状态,当一个活动不再处于栈顶的时候,但可见时,这个活动就进入了暂停状态
- 停止状态,当一个活动不再处于栈顶的时候,并且不可见的时候,这个活动就进入了停止状态
- 销毁状态,当一个活动从栈中移除后就变成了销毁状态
(六)活动中的几个方法
- onCreate(),完成活动的初始化操作,在活动第一次被创建的时候调用
- onStart(),在活动由不可见变成可见的时候调用
- onResume(),在活动准备好和用户进行交互的时候调用
- onPause(),在系统准备去启动或恢复另一个活动的时候调用
- onStop(),在活动完全不可见的时候调用。
- onDestory(),在活动被销毁前调用
- onRestart(),在活动由停止状态变成运行状态前调用
与这几个方法对应的,可以将活动分为3种生存期
- 完整生存期,活动在onCreate和onDestrory方法之间经历的就是完整生存期。
- 可见生存期,活动在onStart方法和onStop方法之间经历的是可见生存期。
- 前台生存期,活动在onResume方法和onPause方法之间经历的是前台生存期。
这里有一个官方的生命周期图
(七)活动的回收问题
当一个活动被进入到停止状态,在系统内存不足的时候,有可能被系统回收,等到你重新回到了这个活动,它就会被重新创建,执行onCreate()方法。但是活动A被重新创建了,直接在活动A中存在的临时数据和状态都消失不见了。为了应对这种状况,Activity类提供了一个onSaveInstanceState()方法,这个方法会在活动被回收之前调用,这时我们可以利用他把活动A的临时数据存入。这个方法有一个Bundle类型的参数,Bundle类提供了很多方法来保存数据,比如putString,putInt…这些方法都是有两个参数的,一个是键,一个是值。
数据保存下来之后,在重新调用onCreate方法创建活动的时候,可以用onCreate的参数Bundle来获得这些数据,比如getString,getInt…这些方法的参数都是键名称。一般情况下onCreate的参数Bundle是null,但是如果有通过onSaveInstanceState方法进行存数据的话,它就不是null了。
(八)活动的启动模式
在实际项目中,我们需要根据特定的需要为每个活动指定恰当的启动模式。
启动模式分为4种,在AndroidManifest.xml给activity标签指定android:launchMode属性来指定启动模式
- standard:活动默认的启动模式。使用stanard模式的活动,不论在返回栈中是否已经存在这个活动,每次启动都会创建这个活动的一个新的实例
- singleTop:如果活动的启动模式设置为singleTop,那么当启动这个活动的时候,如果这个活动处于返回栈的栈顶的话,那么直接使用这个活动,不会创建新的实例,如果这个活动不处于栈顶的话,会创建一个新的实例
- singleTask:如果活动的启动模式设置为singleTask,那么启动该活动的时候,系统的就会在返回栈中检查是否存在该活动的实例,如果存在则直接使用该实例,并且把这个活动之上的所有活动都出栈,如果不存在的话则创建一个新的实例
- singleInstance:如果活动的启动模式设置为singleInstance,那个这个活动启动时,会启用一个新的返回栈来管理这个活动。这种启动模式可以用来实现不同程序对这个活动的共享。
九、UI设计
(一)常用控件的使用
(1)TxetView
用于在界面显示一段文本信息
属性:
- android:id,给控件定义一个唯一标识符
- android:layout_width,Android每个控件都有的一个属性,用来决定控件的宽度,有三个可选值,match_parent,fill_parent和wrap_parent,match_parent和fill_parent一样,都是由父布局来决定当前控件的大小。wrap_content表示让当前控件的大小能够刚好包含住里面的内容。
- android:layout_height,Android每个控件都有的一个属性,用来决定控件的高度,可选值同上
- android:text,指定显示的文本内容
- android:gravity,指定文本的对齐方式,可选值有top,bottom,left,right,center等,可以用“|”来同时指定多个值,表示垂直方向跟水平方向。
- android:textSize,指定文字的大小,单位为sp
- android:textColor,指定蚊子的颜色
(2)Button
程序用于和用户进行交互的重要控件,在屏幕上显示一个按钮
属性:
- android:id,指定一个唯一标识
- android:layout_width,指定控件宽度
- android:layout_heigth,指定控件高度
- android:text,指定按钮上的文本,默认将文本按大写显示,可以通过android:textAllCaps属性来将这个设置进行更改,可选值有true跟false
①为Button的点击事件注册一个监听器
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//此处定义这个按钮要实现的功能
}
});
(3)EditText
程序用于和用户进行交互的重要控件,允许用户在控件里输入和编辑内容,并可以在程序中对这些内容进行处理。
属性:
- android:id,定义一个唯一标识
- android:layout_width,定义控件的宽度
- android:layout_height,定义控件的高度
- android:hint,可以指定一段提示性的文本
- android:maxLines:指定EditText的最大行数,当输入内容超过这个行数的时候,文本就会向上滚动,EditText不会继续拉伸,如果不定义这个属性的话,EditText会随输入内容的多少而进行拉伸
①通过EditText对象获取用户输入的文本
EditText edittext = (EditText) findViewById(R.id.edittext);
edittext.getText().toString();
(4)ImageView
用于在界面上展示图片的一个控件,图片通常都是放在drawable开头的目录下
属性:
- android:id,用来定义唯一标识
- android:layout_width,定义控件的宽度
- android:layout_height,定义控件的高度
- android:src,用来指定显示的图片,值为对drawable下的图片进行引用,示例:
android:src=“@drawable/xxx”
,在程序中如果需要改变显示的图片的话,可以通过ImageView对象的setImageResource方法来改变显示的图片
(5)ProgressBar
用于在界面上显示一个进度条,表示我们的程序正在加载一些数据
属性:
- android:id,用来定义唯一标识
- android:layout_width,定义控件的宽度
- android:layout_height,定义控件的高度
- android:visibility,Android控件都有的属性,指定控件是否可见,
有三个可选值,visible表示控件可见,invisible表示控件不可见,但是控件只是变成透明,还占据原来的位置,gone表示控件不可见且不占据任何屏幕空间。这个属性可以通过setVisibility方法来设置是否可见,对应的是View.VISIBLE、View.INVISIBLE、View.GONE - style:指定进度条的样式,示例
style="?android:attr/progressBarStyleHorizontal"
- android:max,指定进度条的最大值
(6)AlertDialog
在当前的界面弹出一个对话框,这个对话框是置顶于所有界面元素之上的,能够屏蔽掉其他控件的交互能力
这个控件需要通过AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);
来创建一个实例,然后可以通过setTitle方法来设置对话框标题,setMessage设置对话框内容,setCancelable设置对话框是否可以取消,setPositiveButton设置确定按钮对应的点击事件,setNegativeButton设置取消按钮对应的点击事件,最后调用show方法来将对话框显示出来
(7)ProgressDialog
这个控件跟AlertDialog有点相似,都可以在界面上弹出对话框,都能屏蔽掉其他控件的交互能力,但是ProgressDialog是在对话框中显示一个进度条,用来表示当前操作比较耗时
使用方法跟AlertDialog也很相似,通过ProgressDialog progressDialog = new ProressDialog(MainActivity.this);
来实例化一个对象,也有setTitle,setMessage,setCancelable,show等方法,没有setPositiveButton跟setNegativeButton方法,由于没有这两个方法,要是设置了这个对话框不可取消的话,需要在代码中调用dismiss这个方法才能关闭对话框
(8)ListView
ListView允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚动出屏幕。
①ListView的使用
在布局文件添加ListView控件跟平时一样
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
数据要传递给ListView,需要借助适配器Adapter来完成
这里举个例子,利用ArrayAdapter来传递数据给ListView,ArrayAdapter可以通过构造函数,依次传入当前上下文、ListView子项布局的id(也就是ListView中每一项数据引用的布局样式),以及要适配的数据,然后调用ListView的setAdapter方法来向ListView传递数据
public class MainActivity extends AppCompatActivity {
private String[] data = {"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this,android.R.layout.simple_list_item_1,data);
ListView listView = (ListView) findViewById(R.id.listview);
listView.setAdapter(adapter);
}
}
运行程序结果:
②ListView的点击事件
为ListView中的每一项的设计点击事件,让listView调用setOnItemClickListener方法并实现OnItemClick方法即可
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String num = data[position];
Toast.makeText(MainActivity.this, num, Toast.LENGTH_SHORT).show();
}
运行结果:
③自定义ListView的界面
前面ListView子项使用的布局是内置的,但是内置的样式一般比较单一,可能实现不了我们想要的效果,所以我们可以来自定义ListView的界面,简单起见,只给前面的每一项加上一张图片,为了方便,这里只选择一张图片
新建一个类,作为适配器的适配类型,并且它能携带我们想要的数据,num指定对应的数字,imageId指定对应的图片,这里我们只有一张图片,所以之后的id都会是一样的
public class Num {
private String num;
private int imageId;
public Num(String num, int imageId) {
this.num = num;
this.imageId = imageId;
}
public int getImageId() {
return imageId;
}
public void setImageId(int imageId) {
this.imageId = imageId;
}
public String getNum() {
return num;
}
public void setNum(String num) {
this.num = num;
}
}
我们想要给ListView指定一个我们自己的布局,那么我们就要创建一个我们自己的布局
在layout目录下我们新建一个num.xml布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
/>
</LinearLayout>
接下来创建一个自定义的适配器,继承自ArrayAdapter,泛型指定为我们刚刚创建的Num类,用于将我们的一系列Num类的数据传递给适配器再传递给ListView的每一项,在这里我们要重写ArrayAdapter的构造方法,传入一个上下文,一个布局id,还有要适配的数据,并且重写一个getView方法,在getView方法中获得传入数据的每一项的实例,加载我们自定义的布局并给这个布局传入我们想要传入的数据
public class NumAdapter extends ArrayAdapter<Num> {
private int resourceId;
public NumAdapter(Context context, int textViewResourceId, List<Num> objects) {
super(context, textViewResourceId, objects);
resourceId = textViewResourceId;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Num num = getItem(position);
View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
ImageView img = (ImageView) view.findViewById(R.id.img);
TextView num1 = (TextView)view.findViewById(R.id.num);
img.setImageResource(num.getImageId());
num1.setText(num.getNum());
return super.getView(position, convertView, parent);
}
}
最后就是在主活动中修改代码,准备好数据,创建适配器传入数据,并将适配器传递给ListView
public class MainActivity extends AppCompatActivity {
private List<Num> list = new ArrayList<Num>();
private void init(){
for (int i=0;i<2;i++){
Num num1 = new Num("1", R.drawable.one);
list.add(num1);
Num num2 = new Num("2",R.drawable.one);
list.add(num2);
Num num3 = new Num("3",R.drawable.one);
list.add(num3);
Num num4 = new Num("4",R.drawable.one);
list.add(num4);
Num num5 = new Num("5",R.drawable.one);
list.add(num5);
Num num6 = new Num("6",R.drawable.one);
list.add(num6);
Num num7 = new Num("7",R.drawable.one);
list.add(num7);
Num num8 = new Num("8",R.drawable.one);
list.add(num8);
Num num9 = new Num("9",R.drawable.one);
list.add(num9);
Num num10 = new Num("10",R.drawable.one);
list.add(num10);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
NumAdapter numAdapter = new NumAdapter(MainActivity.this,R.layout.num,list);
ListView listView = (ListView) findViewById(R.id.list_view);
listView.setAdapter(numAdapter);
}
}
运行结果:
(9)RecyclerView
这个控件优化了ListView,是一个新增的控件,需要我们手动引入,在app/build.gradle文件,在dependencies闭包下添加以下代码compile’com.android.support:recyclerview-v7:24.2.1’,由于不是内置在系统内的,所以使用时也需要将完整的包名写出来
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
①RecyclerView的基本使用
为了让RecyclerView实现跟ListView一样的功能,我们先自定义一个适配器NumAdapter,让这个适配器继承RecyclerView.Adapter,并将泛型指定成NumAdapter.ViewHolde。
这里的ViewHolder是我们定义在NumAdapter的一个内部类,它的作用是封装RecylerView每一个子项布局中的控件,ViewHolder的构造函数中要传入一个View参数,这个参数通常就是RecyclerView子项的最外层布局,我们在ViewHolder的构造函数中对子项布局中的控件进行获取。
NumAdapter继承了RecyclerView.Adapter,因此要实现onCreateViewHolder,onBindViewHolder和getItemCount这三个方法。
- onCreateViewHolder方法是用于创建ViewHolder实例的,在这个方法中我们
子项布局加载进来,然后创建一个ViewHolder实例,并把这个实例传入构造函数中 - onBindViewHolder方法是用于对RecyclerView子项的数据进行赋值的,会在每个子项被滚动到屏幕内的时候执行,在这里我们可以对ViewHolder的属性进行赋值,也就是对每一个子项布局的控件进行赋值
- getItemCount方法就是用于告诉RecyclerView一共有多少个子项,我们只需要返回数据源的长度即可
public class NumAdapter extends RecyclerView.Adapter<NumAdapter.ViewHolder>{
private List<Num> list;
static class ViewHolder extends RecyclerView.ViewHolder{
ImageView img;
TextView num;
public ViewHolder(View view){
super(view);
img = (ImageView) view.findViewById(R.id.img);
num = (TextView) view.findViewById(R.id.num);
}
}
public NumAdapter(List<Num> list){
this.list = list;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.num,parent,false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Num num = list.get(position);
holder.img.setImageResource(num.getImageId());
holder.num.setText(num.getNum());
}
@Override
public int getItemCount() {
return list.size();
}
}
准备好RecyclerView每一项的布局文件,这里要主要LinearLayout的布局宽度跟高度要设置为wrap_content不然RecyclerView每一项都会占据一整个屏幕
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
/>
</LinearLayout>
最后修改主活动的代码:准备好所需数据,获取RecyclerView的实例,创建一个LinearLayoutManager对象并将它设置到RecyclerView中,LayoutManager用于指定RecyclerView的布局方式,这里所使用的是线性布局。
public class MainActivity extends AppCompatActivity {
private List<Num> list = new ArrayList<Num>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
NumAdapter numAdapter = new NumAdapter(list);
recyclerView.setAdapter(numAdapter);
}
private void init(){
for (int i = 0 ;i<2;i++){
Num num1 = new Num("1",R.drawable.one);
list.add(num1);
Num num2 = new Num("2",R.drawable.one);
list.add(num2);
Num num3 = new Num("3",R.drawable.one);
list.add(num3);
Num num4 = new Num("4",R.drawable.one);
list.add(num4);
Num num5 = new Num("5",R.drawable.one);
list.add(num5);
Num num6 = new Num("6",R.drawable.one);
list.add(num6);
Num num7 = new Num("7",R.drawable.one);
list.add(num7);
Num num8 = new Num("8",R.drawable.one);
list.add(num8);
Num num9 = new Num("9",R.drawable.one);
list.add(num9);
Num num10 = new Num("10",R.drawable.one);
list.add(num10);
}
}
}
运行程序,效果跟ListView实现的基本一样
②横向滚动布局
如果想将以上RecyclerView的效果改为横向的,我们需要对上述代码进行一点点修改
首先,修改num.xml里面的代码,将子项布局的方向设置为垂直的,再将宽度固定,使得每个子项布局一样大,然后使子项布局中的控件都水平居中
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="100dp"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
/>
<TextView
android:id="@+id/num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
/>
</LinearLayout>
然后修改主活动代码,在原先的基础上加上一行代码 layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
使得RecyclerView控件的方向变为水平
public class MainActivity extends AppCompatActivity {
private List<Num> list = new ArrayList<Num>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(layoutManager);
NumAdapter numAdapter = new NumAdapter(list);
recyclerView.setAdapter(numAdapter);
}
private void init(){
for (int i = 0 ;i<2;i++){
Num num1 = new Num("1",R.drawable.one);
list.add(num1);
Num num2 = new Num("2",R.drawable.one);
list.add(num2);
Num num3 = new Num("3",R.drawable.one);
list.add(num3);
Num num4 = new Num("4",R.drawable.one);
list.add(num4);
Num num5 = new Num("5",R.drawable.one);
list.add(num5);
Num num6 = new Num("6",R.drawable.one);
list.add(num6);
Num num7 = new Num("7",R.drawable.one);
list.add(num7);
Num num8 = new Num("8",R.drawable.one);
list.add(num8);
Num num9 = new Num("9",R.drawable.one);
list.add(num9);
Num num10 = new Num("10",R.drawable.one);
list.add(num10);
}
}
}
这样运行出来的结果就是横向的了
③瀑布流布局
RecyclerView提供了StaggeredGirdLayoutManager和GridLayoutManager两种内置的布局排列方式,StaggeredGridLayoutManager用于实现瀑布流布局,而GridLayoutManager用于实现网格布局
要实现瀑布流布局,我们只需将上述代码进行稍微的修改即可
首先将子项布局的宽度设置为match_parent,因为瀑布流布局的宽度是根据列数来自动适配的,再用 android:layout_margin="5dp"使得子项不会太过于紧凑,再用 android:layout_gravity="left"使文字靠左显示
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
>
<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
/>
<TextView
android:id="@+id/num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginTop="10dp"
/>
</LinearLayout>
然后修改主活动代码,初始化数据设置长度不一的文本,新建一个瀑布流布局方式,指定它的列数跟布局的排列方式,再将其传递给RecyclerView即可
public class MainActivity extends AppCompatActivity {
private List<Num> list = new ArrayList<Num>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
NumAdapter numAdapter = new NumAdapter(list);
recyclerView.setAdapter(numAdapter);
}
private void init(){
for (int i = 0 ;i<2;i++){
Num num1 = new Num("111111111111111111111111",R.drawable.one);
list.add(num1);
Num num2 = new Num("2222222222222222222222",R.drawable.one);
list.add(num2);
Num num3 = new Num("3333333333333333333333333333333333333333333",R.drawable.one);
list.add(num3);
Num num4 = new Num("444444444444444444444444444444444444",R.drawable.one);
list.add(num4);
Num num5 = new Num("55555555555555555555555",R.drawable.one);
list.add(num5);
Num num6 = new Num("6666666666666666666666666",R.drawable.one);
list.add(num6);
Num num7 = new Num("77777777777777777777777777777",R.drawable.one);
list.add(num7);
Num num8 = new Num("88888888888888888888888888888888",R.drawable.one);
list.add(num8);
Num num9 = new Num("99999999999999999999999999999",R.drawable.one);
list.add(num9);
Num num10 = new Num("1010101010101010101010101010101010101010",R.drawable.one);
list.add(num10);
}
结果:
④网格布局
将瀑布流布局主活动的代码稍微进行修改即可,创建网格布局方式
GridLayoutManager layoutManager = new GridLayoutManager(MainActivity.this,4);,传入一个活动本身跟列数
public class MainActivity extends AppCompatActivity {
private List<Num> list = new ArrayList<Num>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
GridLayoutManager layoutManager = new GridLayoutManager(MainActivity.this,4);
recyclerView.setLayoutManager(layoutManager);
NumAdapter numAdapter = new NumAdapter(list);
recyclerView.setAdapter(numAdapter);
}
private void init(){
for (int i = 0 ;i<2;i++){
Num num1 = new Num("111111111111111111111111",R.drawable.one);
list.add(num1);
Num num2 = new Num("2222222222222222222222",R.drawable.one);
list.add(num2);
Num num3 = new Num("3333333333333333333333333333333333333333333",R.drawable.one);
list.add(num3);
Num num4 = new Num("444444444444444444444444444444444444",R.drawable.one);
list.add(num4);
Num num5 = new Num("55555555555555555555555",R.drawable.one);
list.add(num5);
Num num6 = new Num("6666666666666666666666666",R.drawable.one);
list.add(num6);
Num num7 = new Num("77777777777777777777777777777",R.drawable.one);
list.add(num7);
Num num8 = new Num("88888888888888888888888888888888",R.drawable.one);
list.add(num8);
Num num9 = new Num("99999999999999999999999999999",R.drawable.one);
list.add(num9);
Num num10 = new Num("1010101010101010101010101010101010101010",R.drawable.one);
list.add(num10);
}
}
}
运行结果:
网格布局的宽度是由指定的列数来自动适配的,高度则是根据每一行中的子项布局中高度最大的那个来决定的
⑤RecyclerView的点击事件
RecyclerView与ListView不同,没有提供setOnItemClickListener的注册监听器方法,需要我们自己给子项具体的View去注册点击事件,这里有个好处就是我们可以对子项布局里面的具体某个控件设置点击事件,也可以对一整个子项布局设置点击事件,比较灵活
修改适配器的代码,在适配器中的内部类ViewHolder定义多一个View 并通过构造方法将子项布局的view赋值给这个变量view,然后再onCreateViewHolder方法中注册点击事件,在注册点击方法中,获取用户点击的position,再通过position获取相应的实例,再做出对应的反应
public class NumAdapter extends RecyclerView.Adapter<NumAdapter.ViewHolder>{
private List<Num> list;
static class ViewHolder extends RecyclerView.ViewHolder{
ImageView img;
TextView num;
View view;
public ViewHolder(View view){
super(view);
this.view = view;
img = (ImageView) view.findViewById(R.id.img);
num = (TextView) view.findViewById(R.id.num);
}
}
public NumAdapter(List<Num> list){
this.list = list;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.num,parent,false);
final ViewHolder holder = new ViewHolder(view);
holder.view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
Num num = list.get(position);
Toast.makeText(v.getContext(),"you clicked view" + num.getNum(),Toast.LENGTH_SHORT).show();
}
});
holder.img.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
Num num = list.get(position);
Toast.makeText(v.getContext(),"you clicked image" + num.getNum(),Toast.LENGTH_SHORT).show();
}
});
holder.num.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
Num num = list.get(position);
Toast.makeText(v.getContext(),"you clicked textView" + num.getNum(),Toast.LENGTH_SHORT).show();
}
});
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Num num = list.get(position);
holder.img.setImageResource(num.getImageId());
holder.num.setText(num.getNum());
}
@Override
public int getItemCount() {
return list.size();
}
}
运行结果:
(二)4种基本布局
(1)线性布局
LinearLayout,这种布局会把所包含的控件在线性方向上依次排列
属性
- android:orientation,通过这个属性来改变排列的方向,可选的值有horizontal水平的,vertical垂直的
- android:layout_gravity,指定控件在布局中的对齐方式,当orientation指定的方向是horizontal的时候,只有垂直方向上的对齐方式才会生效,因为此时水平方向上的长度是不固定的,随控件的数量而改变,当orientation指定的方向是vertical时,只有水平方向上的对齐方式会生效。
- android:layout_weight,可以使用这个属性在这个布局中的每一个控件按照比例指定控件的大小
(2)相对布局
RelativeLayout,可以通过相对定位的方式让控件出现在布局的任意位置。
属性:
- android:layout_alignParentLeft,相对布局内的控件里都可以使用这个属性,用来表示是否和父布局左对齐
- android:layout_alignParentRight,用来表示是否和父布局右对齐
- android:layout_alignParentTop,用来表示是否和父布局顶端对齐
- android:layout_alignParentBottom,用来表示是否和父布局底端对齐
- android:layout_centerInParent,用来表示是否处于父布局中间
以上的属性取值都为true或false,并且都是相对于父布局进行定位的
相对于控件进行定位的属性有:
- android:layout_above,表示让当前控件处于某个控件的上方
- android:layout_below,表示让当前控件处于某个控件的下方
- android:layout_toLeftOf,表示让当前控件处于某个控件的左方
- android:layout_RightOf,表示让当前控件处于某个控件的右方
以上属性的值都需要为其指定某个控件的id的引用
(3)帧布局
FramLayout,这种布局没有方便的定位方式,所有的控件都会默认摆放在布局的左上角
(4)百分比布局
这种布局属于新增布局,需要我们手动引入,打开app/build.gradle文件,在compile 'com.android.support:appcompat-v7:24.2.1’下添加一行代码 compile’com.android.support:percent:24.2.1’,即可引入百分比布局
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:24.2.1' compile'com.android.support:percent:24.2.1' testCompile 'junit:junit:4.12' }
接下来我们就可以进行使用,由于百分比布局不是内置在系统SDK中的,所以我们要把完整的包路径写出来,还要定义一个app命名空间,这样才能使用百分比布局
<android.support.percent.PercentFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</android.support.percent.PercentFrameLayout>
PercentFrameLayout继承了FrameLayot的特性,所有的控件默认都是摆放在布局的左上角
属性:
- app:layout_widthPercent,可以指定控件的宽度占布局的百分比
- app:layout_heightPercent,可以指定控件的高度占布局的百分比
除了PercentFrameLayout,还有PercentRelativeLayout,它继承了RelativeLayout的特性,也跟PercentFrameLayout一样能使用上述的属性用百分比来指定控件的大小
(三)自定义控件
我们所用的控件都是直接或间接继承View的,View是Android中最基本的一中UI组件,它可以在屏幕上绘制一块矩形区域,并能响应这块区域的各种事件。我们使用的各种控件就是在View的基础上添加了各自的功能。由此我们可以自定义控件。
我们可以在layout目录下新建一个布局文件xxx.xml,然后在活动包下创建一个类继承LinearLayout类,然后重写LinearLayout的构造函数,再在构造函数中调用LayoutInflater的from方法构建除一个LayoutInflater对象,然后调用inflate方法动态加载一个布局文件
public class XXX extends LinearLayout {
public TitleLayout(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.xxx,this);
}
}
此时自定义控件就创建好了,在需要使用这个控件的布局文件中引入这个类即可,需要注意的是,需要指明控件的完整类名,这个自定义控件要实现什么功能的话,可以在上述类中修改跟增加代码
<com.example.lenovo.myapplication3.XXX
android:layout_height="wrap_content"
android:layout_width="match_parent"
/>
十、碎片Fragment
碎片是一种可以嵌入在活动中的UI片段,它能让程序更加合理充分地运动用大屏幕控件,在平板上使用较多。
(一)碎片的使用
碎片的使用有两种方法,一种是在布局文件中直接使用fragment标签,一种是在主活动中使用java代码向布局中设置碎片;
-
第一种
新建一个类继承android.support.v4.app.Fragment,也可以继承android.app.Fragment,但是前者更好更新,不容易报错。然后在这个类里面重写OnCreateView方法,之后再通过在主活动布局文件中添加fragment标签即可引入碎片@Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.xxx,container,false); return view; } } ```
<fragment
android:layout_width="0dp"
android:layout_height="match_parent"
android:name="xx.xxx.xxx"<!-- 对应类的路径>
android:layout_weight="1"/>
- 第二种
新建一个xxxFrgmeent类继承继承android.support.v4.app.Fragment然后在这个类里面重写OnCreateView方法,在主活动布局中嵌套一个布局,这里使用帧布局
<FrameLayout
android:layout_height="match_parent"
android:layout_width="xdp"
android:id="@+id/xxx"
>
</FrameLayout>
再在主活动中使用以下代码给帧布局传递一个碎片
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.xxx,new xxxFragment());
transaction.commit();
(二)碎片和活动之间的通信
在活动中可以调用getSupportFragmentManager().findFragmentById()来获得碎片的实例
在碎片中可以使用getActivity()方法来得到和当前碎片相关联的活动实例
(三)碎片的生命周期
- 运行状态,当一个碎片是可见的,并且它所关联的活动正处于运行状态时,碎片也处于运行状态
- 暂停状态,当一个活动进入暂停状态时,与它相关的可见碎片就会进入到暂停状态
- 停止状态,当一个活动进入状态时,与它相关联的碎片就会进入到停止状态,或者通过调用FragmentTransaction的remove()、replace()方法将碎片从活动中移除,并且在事务提交之前没有调用addToBackStack方法,这时的碎片也会进入停止状态。
- 销毁状态,当活动被销毁时,与它想关联的碎片就会进入到销毁碎片就会进入到销毁状态。或者通过FragmentTransaction的remove、replace方法将碎片从活动h供移除,并且在事务提交之前没有调用addToBackStack方法,这时的碎片也会进入销毁状态。
(四)碎片的一些回调方法
活动有的回调方法碎片一般都有,不过碎片还提供了一些附加的回调办法
- onAttach:当碎片和活动建立关联的时候调用
- onCreateView:为碎片创建视图的时候调用
- onActivityCreated:确保与碎片相关联的活动一定已经创建完毕的时候调用
- onDestoryView,当与碎片相关联的视图被移除的时候调用
- onDetach,当碎片和活动解除关联的时候调用
当碎片第一次被加载到屏幕上时,会一次执行onAttach、onCreate、onCreateView、onActivityCreated、onStart、onResume方法,当活动进入停止状态会依次调用onPause、onStop、onDestroyView,如果之后没有调用addToBackStack方法,就会调用onDestory、onDetach方法,如果调用了addToBackStack方法,就会重新调用onCreateView、onActivityCreated、onStart、onResume方法。
(五)碎片的数据问题
当系统内存不足的时候,进入停止状态 碎片有可能会被回收,这样存在于碎片中的数据可能会消失,因此我们可以通过onSaveInstanceState()方法中来保存数据,并且在onCreate、onCreateView、onActivityCreated方法中重新获取,跟活动被回收的问题类似。