一、Fragment
1、Fragment初探
打开或新建activity_main.xml作为主Activity的布局文件,在里面加入两个Fragment的引用,使用
android:name前缀来引用具体的
<fragment
android:id="@+id/fragment1"
android:name="com.example.fragmentdemo.Fragment1"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1" />
2、动态添加Fragment(强大之处,必须掌握 )
动态添加Fragment主要分为4步:
1.创建待添加的碎片实例。
2.获取到FragmentManager,在Activity中可以直接通过getFragmentManager得到。
3.开启一个事务,通过调用beginTransaction方法开启。
4.向容器内加入Fragment,使用replace或者add方法实现,需要传入容器的id和Fragment的实例。
5.提交事务,调用commit方法提交。
MainActivity.java
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Display display = getWindowManager().getDefaultDisplay();
if (display.getWidth() > display.getHeight()) {
Fragment1 fragment1 = new Fragment1();
getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment1).commit();
} else {
Fragment2 fragment2 = new Fragment2();
getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment2).commit();
}
}
}
备注
Fragment销毁时replace和add两个方法的区别
3、Fragment生命周期
(摘自https://developer.android.com/guide/components/fragments.html)
与Activity类似:
(1)运行程序后
(2)按back键退出程序
重点介绍几个Activity没有的:
- onAttach方法:Fragment和Activity建立关联的时候调用。
- onCreateView方法:为Fragment加载布局时调用。
- onActivityCreated方法:当Activity中的onCreate方法执行完后调用。
- onDestroyView方法:Fragment中的布局被移除时调用。
- onDetach方法:Fragment和Activity解除关联的时候调用。
4、Fragment之间通信
在fragment2中成功获取到了fragment1中的视图,并弹出Toast。这是怎么实现的呢?主要都是通过
getActivity这个方法实现的。getActivity方法可以让Fragment获取到关联的Activity,然后再调用Activity的findViewById方法,就可以获取到和这个Activity关联的其它Fragment的视图了。
二、Activity
1、所有Activity在AndroidMainfest文件中注册才能生效
Activity的注册声明都放在<application>标签内
android:name
具体活动名字,一般是 .name(缩写形式),完整形式是加上最外层的<manifest>标签的package属性所指定的程序包名
android:label
指定Activity中标题栏的内容,标题栏显示在活动最顶端。另外,还是启动器(Launcher)中应用程序显示的名称,即app_name
<intent-filter>
<action android :name= "android.intent.action.MAIN" />
<category android :name= "android.intent.category.LAUNCHER" />
</intent-filter>
做为程序的主活动的声明,即点击桌面应用程序图标时首先打开就是这个活动。
(注意:如果没有声明任何一个活动作为主活动,这个程序仍然可以正常安装,只是你无法在启动器中看到或者打开。这个程序一般都是作为第三方服务,供其他应用在内部调用,如支付宝快捷支付服务)
2、销毁一个Activity
finish( )
3、使用显式Intent
Intent是各组件之间进行交互的一个重要方式,可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据。启动Activity、Service、Broadcast
用法 Intent(Context packageContext, Class<?> cls) 第一个参数:启动活动的上下文, 第二个参数: 启动的目标活动
Activity类中提供startActivity(),专门用于启动Activity,接受一个Intent参数
例子:
Intent Intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
4、使用隐式Intent
用法1:(没有明确指出哪个Activity, 而是指出一系列更抽象的action和category等信息,然后交给系统去分析这个Intent,并帮我们找出合适的Activity去启动)
在AndroidMainfest.xml:
<activity android:name = ".SecondActivity" >
<intent-filter>
<action android:name = "com.example.activitest.ACTION_START" />
<category android:name = "android.intent.category.DEFAULT" />
<category android:name = "android.intent.category.MY_CATEGORY " />
</intent-filter>
</activity>
在FirstActivity.java:
Intent intent = new Intent("com.example.activitest.ACTION_START ");
intent.addCategory("com.example.activitytest.MY_CATEGORY")
startActivity(intent);
//表明我们要启动能够响应“com.example.activitest.ACTION_START ”这个action和"com.example.activitytest.MY_CATEGORY" 这个category的Activity
//android.intent.category.DEFAULT 是一种默认的category,startActivity自动添加到Intent中
用法2:
在FirstActivity.java:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);
//
Intent.ACTION_VIEW
系统内置的动作action
//
setData()
主要用于指定当前Intent正在操作的数据
//与此对应,我们在<intent-filter>标签中再配置一个<data>标签,
用于更精确的确定当前活动能够响应什么类型的数据。
只有<data>标签中指定的内容和Intent中携带的Data完全一致,
当前的活动才能响应该Intent
//
<data>一般配置以下内容:
android:scheme
用于指定数据的协议部分,如http部分
android:host
用于指定数据的主机名部分,如www.baidu.com部分
android:port
用于指定数据的端口部分,一般紧随在主机名之后
android:path /
android:mimeType
一般不会指定过多的内容,例如指定
android:scheme为http,
就可以响应所有的http协议的Intent
5、向下一个活动传递数据
FirstActivity发数据:
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("extra_data", "Hello SecondActivity");
startActivity(intent);
SecondActivity收数据:
Intent intent = getIntent();
String data = intent.getExtra("extra_data");
//如果传递的数据是整型,用
getIntExtra(), 数据是布尔型,用
getBooleanExtra()
//一般用Bundle传值更方便,
一是在多个Activity传递数据时,可以直接取,
不用取出来塞到Intent再传递,
二是Bundle支持数据类型更多,可以传递对象putSerializable
6、返回数据给上一个Activity
用
startActivityForResult()方法,也是用于启动Activity的,但这个方法期望在活动销毁时能够返回一个结果给上一个活动
用法:
在FirstActivity启动SecondActivity
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivityForResult(intent, 1); //请求码
requestCode 是一个唯一值,这里传入1
在SecondActivity.java
Intent intent = new Intent();
intent.putExtra("data_return", "Hello FirstActivity");
setResult(RESULT_OK, intent); //第一个参数为处理结果(RESULT_OK 或者 RESULT_CANCELED),第二个参数是把带有数据的Intent传递回去
finish();
//在SecondActivity销毁之后会回调上一个Activity的
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:
}
}
//为什么有三个参数requestCode, resultCode, data?
因为在一个Activity中可能调用startActivityForResult()方法去启动很多不同的Activity,每个Activity返回的数据都会回调onActivityResult()
因此,我们首先通过检查requestCode判断数据来源。
确定数据是从SecondActivity返回后,再通过resultCode的值判断处理结果是否成功。
如果成功,取(Intent) data值。
//如果用户是按Back键返回上一个Activity,则需要在SecondActivity.java重写onBackPressed()方法来解决这个情况
@Override
public void onBackPressed() {
Intent intent = new Intent();
intent.putExtra("data_return", "Hello FirstActivity");
setResult("RESULT_OK", intent);
finish();
}
7、Activity的生命周期
(摘自https://developer.android.com/reference/android/app/Activity.html)
Android是用任务(Task)来管理Activity的,一个任务就是一组存放在栈里的Activity的集合,这个栈也被称作为返回栈(Back Stack)
Activity状态:
1、运行状态,
当一个Activity位于Back Stack的栈顶时,处于这个状态。系统最不愿意回收这个状态的Activity
2、暂停状态,
当Activity不再位于Back Stack的栈顶,但
仍然可见时。只有内存极低时,才考虑回收。
3、停止状态,
不再位于栈顶,且
完全不可见。系统仍然会保存相应的状态和成员变量,但不完全可靠。
当需其他地方要内存时,这个状态的Activity可能会被回收
4、销毁状态,
从Back Stack中移除后就变成这种状态。
系统最倾向回收这个状态的Activity,从而保证手机内存充足
Activity生命周期:七个回调方法
除了onRestart(),两两相对,可分为三种生存期:
1、完整生存期:onCreate()和onDestroy()之间。
一般:在onCreate()完成初始化操作,在onDestroy()完成释放内存的操作
2、可见生存期:onStart()和onStop()之间,
这段期间,Activity可见,即便无法交互。
通过这两个方法,合理地管理对用户可见的资源。
如在onStart()中对可见的资源进行加载,在onStop()对可见的资源进行释放
3、前台生存期:onResume()和onPause()之间,
这段期间,Activity处于运行状态,可见,且可交互
保证Activity在回收之前,保存临时数据的方法:
onSaveInstanceState(),携带一个Bundle类型的参数,用于保存数据
用法:
@Override
protected void onSaveInstanceState( BundleoutState ) {
Super.onSaveInstanceState(outState);
String tempData = "Something you just typed";
outState.putString ("data_key", tempData);
}
@Override
protected void onCreate(
BundlesavedInstanceState
) {
Super.onCreate(
savedInstanceState
);
setContentView(R.layout.activity_main);
if (savedInstanceState != null) {
String tempData = savedInstanceState.getString("data_key") ;
}
}
8、Activity的启动模式
Activity四种启动模式:
(1)standard 默认方式
不管有没有已存在的实例,都生成新的实例。
(1)standard 默认方式
不管有没有已存在的实例,都生成新的实例。
(2)singleTop
如果跳转的Activity实例已经位于栈顶,则重复利用,不再生成新的实例
如果跳转的Activity实例已经位于栈顶,则重复利用,不再生成新的实例
如果不位在栈顶,则重新生成一个实例
应用场景:
三条推送,点进去都是一个activity,用singletop
(3)singleTask
如果发现有对应的Activity实例,则使此Activity实例之上的其他Activity实例统统出栈,使此Activity实例成为栈顶对象,显示到幕前。
应用场景:
通常应用于首页,首页肯定得在栈底部,也只能在栈底部。
(4)singleInstance
会启用一个新的栈结构,将Acitvity放置于这个新的栈结构中,并保证不再有其他Activity实例进入
应用场景:
通常用于与程序分离的页面,比如说一个新闻程序,然后一个闹钟activity,肯定是singintance
9、Activity的最佳实践
(1)知晓当前是在哪个Activity
新建一个BaseActivity继承Activity(然后让BaseActivity成为项目中所有Activity的父类):
public class BaseActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("BaseActivity", getClass().getSimpleName());
}
}
//每当我们进入一个Activity的界面,该Activity的类名就会被打印出来
(2)随时随地退出程序
需求:一个注销或退出的功能
解决思路:只需要一个专门的集合类对所有Activity进行管理就可以
public class ActivityCollector {
public static List<Activity> activities = new ArrayList<Activity>();
public static void addActivity(Activity activity) {
activities.add(activity);
}
public static void removeActivity(Activity activity) {
activities.remove(activity);
}
public static void finishAll() {
for(Activity activity : activities) {
if(!activity.isFinishing()) {
activity.finish();
}
}
}
}
然后在基础类BaseActivity的onCreate()方法和onDestroy()方法:
public class BaseActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("BaseActivity", getClass().getSimpleName());
ActivityCollector.addActivity(this);
}
@Override
protected void onDestroy() {
super.onDetroy();
ActivityCollector.removeActivity(this);
}
}
(3)启动Activity的最佳写法
假设SecondActivity中需要用到两个非常重要的字符串参数,在启动SecondActivity的时候必须传过来:
public class SecondActivity extends BaseActivity() {
public void actionStart(Context context, String data1, String data2) {
Intent intent = new Intent(context, SecondActivity.class );
intent.putExtra("param1", data1);
intent.putExtra("param2", data2);
context.startActivity(intent);
}
……
}
//可以清晰知道启动SecondActivity需要传递哪些数据,且只需要一行代码就可以启动SecondActivity,
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
SecondActivity.acionStart(FirstActivity.this, "data1", "data2") ;
}
}
);
参考:
1、《第一行代码》
2、http://blog.csdn.net/guolin_blog/article/details/8881711 Android Fragment完全解析,关于碎片你所需知道的一切
3、https://github.com/BuddyZH/FragmentPractice Fragment练习demo
4、潇涧复习总结