Activity、FragmentActivity和AppCompatActivity的区别
Activity
Activity是最基础的一个,是其它类的直接或间接父类。
Activity中只能使用系统自带的host Fragment(API Level 11中加入),对应getFragmentManager方法来控制Activity和Fragment之间的交互。
FragmentActivity
在v4包中引入FragmentActivity,FragmentActivity间接继承自Activity,并提供了对v4包中support Fragment的支持。
在FragmentActivity中必须使用getSupportFragmentManager方法来处理support Fragment的交互。也可以处理support Fragment的嵌套使用。
Known limitations:
* When using the `<fragment>` tag, this implementation can not use the parent view's ID as the new fragment's ID.
You must explicitly specify an ID (or tag) in the `<fragment>`.
AppCompatActivity
AppCompatActivity继承自FragmentActivity,同时取代了ActionBarActivity。
AppCompatActivity支持ActionBar功能,同时更推荐使用ToolBar。AppCompatActivity为支持Material Design风格控件提供了便利。
使用场景
参考stack overflow中一个回答。
Activity is the baseline. Every activity inherits from Activity, directly or indirectly.
FragmentActivity is for use with the backport of fragments found in the support-v4 and support-v13 libraries. The native implementation of fragments was added in API Level 11, which is lower than your proposed minSdkVersion values. The only reason why you would need to consider FragmentActivity specifically is if you want to use nested fragments (a fragment holding another fragment), as that was not supported in native fragments until API Level 17.
AppCompatActivity is from the appcompat-v7 library. Principally, this offers a backport of the action bar. Since the native action bar was added in API Level 11, you do not need AppCompatActivity for that. However, current versions of appcompat-v7 also add a limited backport of the Material Design aesthetic, in terms of the action bar and various widgets. There are pros and cons of using appcompat-v7, well beyond the scope of this specific Stack Overflow answer.
ActionBarActivity is the old name of the base activity from appcompat-v7. For various reasons, they wanted to change the name. Unless some third-party library you are using insists upon an ActionBarActivity, you should prefer AppCompatActivity over ActionBarActivity.
So, given your minSdkVersion in the 15-16 range:
If you want the backported Material Design look, use AppCompatActivity
If not, but you want nested fragments, use FragmentActivity
If not, use Activity
Just adding from comment as note: AppCompatActivity extends FragmentActivity, so anyone who needs to use features of FragmentActivity can use AppCompatActivity.
AppCompatActivity中AppCompat系列组件的构造及替换
AppCompatActivity中通过AppCompatDelegate来扩展Activity。AppCompatDelegate可以在任一Activity中使用,需要与合适的生命周期方法挂钩。具体可参考官方文档https://developer.android.com/reference/android/support/v7/app/AppCompatDelegate或者AppCompatDelegate的源码注释。
在AppCompatActivity的onCreate方法中,调用AppCompatDelegate(基类)的create方法创建实例,并调用delegate.installViewFactory()设置factory。
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
final AppCompatDelegate delegate = getDelegate();
delegate.installViewFactory();
delegate.onCreate(savedInstanceState);
......
super.onCreate(savedInstanceState);
}
创建AppCompatDelegate子类实例的代码如下,根据手机的安卓版本来创建不同的子类实例
private static AppCompatDelegate create(Context context, Window window,
AppCompatCallback callback) {
if (Build.VERSION.SDK_INT >= 24) {
return new AppCompatDelegateImplN(context, window, callback);
} else if (Build.VERSION.SDK_INT >= 23) {
return new AppCompatDelegateImplV23(context, window, callback);
} else if (Build.VERSION.SDK_INT >= 14) {
return new AppCompatDelegateImplV14(context, window, callback);
} else if (Build.VERSION.SDK_INT >= 11) {
return new AppCompatDelegateImplV11(context, window, callback);
} else {
return new AppCompatDelegateImplV9(context, window, callback);
}
}
以android 6.0(API 23)为例,来跟踪AppCompatDelegate实例对象的创建。AppCompatDelegateImplV23间接继承AppCompatDelegateImplV9,并实现了LayoutInflater.Factory2接口。
AppCompatDelegateImplV9的installViewFactory调用了 LayoutInflaterCompat.setFactory2,设置了自身的Factory2实现。
@Override
public void installViewFactory() {
LayoutInflater layoutInflater = LayoutInflater.from(mContext);
if (layoutInflater.getFactory() == null) {
LayoutInflaterCompat.setFactory2(layoutInflater, this);
} else {
if (!(layoutInflater.getFactory2() instanceof AppCompatDelegateImplV9)) {
Log.i(TAG, "The Activity's LayoutInflater already has a Factory installed"
+ " so we can not install AppCompat's");
}
}
}
AppCompatActivity创建view时,通过PhoneWindow->LayoutInflater(createViewFromTag)进入了其实现Factory2的onCreateView方法。可参考LayoutInflater setFactory进阶中setContentView调用流程分析
/**
* From {@link LayoutInflater.Factory2}.
*/
@Override
public final View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
// First let the Activity's Factory try and inflate the view
final View view = callActivityOnCreateView(parent, name, context, attrs);
if (view != null) {
return view;
}
// If the Factory didn't handle it, let our createView() method try
return createView(parent, name, context, attrs);
}
如果AppCompatActivity并没有设置Factory,就会调用Delegate实例的createView方法创建view。
@Override
public View createView(View parent, final String name, @NonNull Context context,
@NonNull AttributeSet attrs) {
if (mAppCompatViewInflater == null) {
mAppCompatViewInflater = new AppCompatViewInflater();
}
boolean inheritContext = false;
if (IS_PRE_LOLLIPOP) {
inheritContext = (attrs instanceof XmlPullParser)
// If we have a XmlPullParser, we can detect where we are in the layout
? ((XmlPullParser) attrs).getDepth() > 1
// Otherwise we have to use the old heuristic
: shouldInheritContext((ViewParent) parent);
}
return mAppCompatViewInflater.createView(parent, name, context, attrs, inheritContext,
IS_PRE_LOLLIPOP, /* Only read android:theme pre-L (L+ handles this anyway) */
true, /* Read read app:theme as a fallback at all times for legacy reasons */
VectorEnabledTintResources.shouldBeUsed() /* Only tint wrap the context if enabled */
);
}
根据上述代码可知,Delegate实例调用了AppCompatViewInflater的createView来完成具体view的绘制。
public final View createView(View parent, final String name, @NonNull Context context,
@NonNull AttributeSet attrs, boolean inheritContext,
boolean readAndroidTheme, boolean readAppTheme, boolean wrapContext) {
final Context originalContext = context;
// We can emulate Lollipop's android:theme attribute propagating down the view hierarchy
// by using the parent's context
if (inheritContext && parent != null) {
context = parent.getContext();
}
if (readAndroidTheme || readAppTheme) {
// We then apply the theme on the context, if specified
context = themifyContext(context, attrs, readAndroidTheme, readAppTheme);
}
if (wrapContext) {
context = TintContextWrapper.wrap(context);
}
View view = null;
// We need to 'inject' our tint aware Views in place of the standard framework versions
switch (name) {
case "TextView":
view = new AppCompatTextView(context, attrs);
break;
case "ImageView":
view = new AppCompatImageView(context, attrs);
break;
case "Button":
view = new AppCompatButton(context, attrs);
break;
case "EditText":
view = new AppCompatEditText(context, attrs);
break;
case "Spinner":
view = new AppCompatSpinner(context, attrs);
break;
case "ImageButton":
view = new AppCompatImageButton(context, attrs);
break;
case "CheckBox":
view = new AppCompatCheckBox(context, attrs);
break;
case "RadioButton":
view = new AppCompatRadioButton(context, attrs);
break;
case "CheckedTextView":
view = new AppCompatCheckedTextView(context, attrs);
break;
case "AutoCompleteTextView":
view = new AppCompatAutoCompleteTextView(context, attrs);
break;
case "MultiAutoCompleteTextView":
view = new AppCompatMultiAutoCompleteTextView(context, attrs);
break;
case "RatingBar":
view = new AppCompatRatingBar(context, attrs);
break;
case "SeekBar":
view = new AppCompatSeekBar(context, attrs);
break;
}
if (view == null && originalContext != context) {
// If the original context does not equal our themed context, then we need to manually
// inflate it using the name so that android:theme takes effect.
view = createViewFromTag(context, name, attrs);
}
if (view != null) {
// If we have created a view, check its android:onClick
checkOnClickListener(view, attrs);
}
return view;
}
在上述代码中可看到,AppCompatActivity中TextView等组件,被替代为AppCompatTextView等,从而可以利用AppCompat系列组件的特性。但是书写自定义view时,需要手动使用AppCompat组件。
参考AppCompatTextView的提示
This will automatically be used when you use TextView in your layouts and the top-level activity / dialog is provided by appcompat. You should only need to manually use this class when writing custom views.
作者:zizi192
链接:https://www.jianshu.com/p/9d590c478828
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
Activity、FragmentActivity和AppCompatActivity的区别的更多相关文章
- android中activity.this跟getApplicationContext的区别
转载: http://www.myexception.cn/android/1968332.html android中activity.this和getApplicationContext的区别 在a ...
- Android中Activity和AppcompatActivity的区别(详细解析)
转载 https://blog.csdn.net/today_work/article/details/79300181 继承AppCompatActivity的界面. 如下图所示: copy界面代码 ...
- Application、Activity Stack 和 Task的区别
Application类 Application和Activity,Service一样是Android框架的一个系统组件,当Android程序启动时系统会创建一个Application对象,用来存储系 ...
- AppCompatActivity、ActionBarActivity、FragmentActivity和Activity的区别
package com.chy.myapplication; import android.support.v7.app.AppCompatActivity; import android.os.Bu ...
- Android Studio修改默认Activity继承AppCompatActivity
在Android Studio中新建Activity默认继承AppCompatActivity,感觉这点十分不爽,找了很久,终于发现在android Studio安装目录下有个模板文件,修改其中的参数 ...
- Android Studio修改默认Activity继承AppCompatActivity(转)
在Android Studio中新建Activity默认继承AppCompatActivity,感觉这点十分不爽,找了很久,终于发现在Android Studio安装目录下有个模板文件,修改其中的参数 ...
- Android零基础入门第73节:Activity初入门,创建和配置如此简单
Activity是Android应用的重要组成单元之一,也是Android应用最常见的组件之一.前面看到的示例通常都只包含一个Activity或一个AppCompatActivity,但在实际应用中这 ...
- 报错:You need to use a Theme.AppCompat theme (or descendant) with this activity.
学习 Activity 生命周期时希望通过 Dialog 主题测试 onPause() 和 onStop() 的区别,点击按钮跳转 Activity 时报错: E/AndroidRuntime: FA ...
- Android四大组件——Activity
Activity作为Android四大组件之一,也是其中最重要的一个组件.作为一个与用户交互的组件,我们可以把Activity比较成为windows系统上的一个文件夹窗口,是一个与用户交互的界面.再进 ...
随机推荐
- fiddler抓包工具遇到的问题-------502报错
遇到的问题: 打开浏览器,输入本机的虚拟机地址的bugfree,出现无法连接的提示,具体是: [Fiddler] The connection to '192.168.211.128' failed. ...
- watchbog再升级,企业黄金修补期不断缩小,或面临蠕虫和恶意攻击
概要 近日,阿里云安全团队发现wacthbo挖矿团伙[1]新增了CVE_2019_5475 的漏洞利用代码,并开始进行尝试性攻击.通过对CVE_2019_5475漏洞的生命周期进行分析后发现,漏洞批量 ...
- Python-线程(2)
目录 GIL全局解释器锁 GIL 与 Lock 多进程 VS 多线程 死锁现象 递归锁 信号量 Semaphore 线程队列 GIL全局解释器锁 在Cpython解释器中,同一个进程下开启的多线程,同 ...
- LUOGU P4163 [SCOI2007]排列
传送门 解题思路 首先我们发现这道题s的长度很小,所以考虑点暴力的做法,状压dp或搜索.本蒟蒻搜索永远调不对,所以就写了个状压dp.因为所有s里的数都要出现一次,并且最后的答案是要求整除,那么我们设d ...
- 洛谷P2526 【SHOI2001】小狗散步
原题传送门 题目背景 Grant喜欢带着他的小狗Pandog散步.Grant以一定的速度沿着固定路线走,该路线可能自交.Pandog喜欢游览沿途的景点,不过会在给定的N个点和主人相遇.小狗和主人同时从 ...
- Python学习day41-数据库(1)
figure:last-child { margin-bottom: 0.5rem; } #write ol, #write ul { position: relative; } img { max- ...
- 第一周课堂笔记2th
上课笔记2th https://mubu.com/doc/2gxvIvVLG0(老师笔记网址) 1. python python运行过程 把源代码转化成字节码(机器不能识别) 也可能不产生py ...
- python3-常用模块之sys
import syssys 是和Python解释器打交道的sys.argvprint(sys.argv) # argv的第一个参数 是python这个命令后面的值 主要用途 1. 程序员 运维人员 在 ...
- <每日一题>题目16:简单的python练习题(1-10)
#1.python程序中__name__的作用是什么? __name__这个系统变量用来表示程序的运行方式. 如果程序在当前膜快运行,__name__的名称就是__main__, 如果不在(被调用), ...
- Mysql 增加rownum
Mysql 增加rownum 实现(极度推荐) mysql本身不像oracle那样使用 rownum 来显示行号的功能.但是可以使用设置变量的方式来实现这一功能. mysql使用 @ 定义用户变量, ...