Activity 和 AppCompatActivity 的区别

技术学习 / 2022-01-11

写在前面

最近在学习 android 开发~~(被逼无奈)~~,偶然发现 activity 有两个继承的类,而且不相同,一个是 Activity,另一个则是 AppcompatActivity,这两个类都可以继承来编写活动的逻辑,不过还是有一些微小的差别的,比如对于主题使用的语法不同(踩坑),这里吹一波 Google 的文档,无论什么项目的文档都写得巨详细,对新手的学习也特别友好

差异

最明显的差异就是继承两者的界面不同:

  • 继承 Activity 的界面(无 ActionBar):

    Activity 无 ActionBar

    代码如下

    public class MainActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            if (savedInstanceState != null) {
                String tempData = savedInstanceState.getString("data_key");
            }
            Button startNormalActivity = (Button) findViewById(R.id.start_normal_activity);
            Button startDialogActivity = (Button) findViewById(R.id.start_dialog_activity);
            startNormalActivity.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(MainActivity.this, NormalActivity.class);
                    startActivity(intent);
                }
            });
            startDialogActivity.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(MainActivity.this, DialogActivity.class);
                    startActivity(intent);
                }
            });
        }
    }
    
  • 继承 AppcompatActivity 的界面(有 ActionBar):

    AppcompatActivity 有 ActionBar

    代码如下

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            if (savedInstanceState != null) {
                String tempData = savedInstanceState.getString("data_key");
            }
            Button startNormalActivity = (Button) findViewById(R.id.start_normal_activity);
            Button startDialogActivity = (Button) findViewById(R.id.start_dialog_activity);
            startNormalActivity.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(MainActivity.this, NormalActivity.class);
                    startActivity(intent);
                }
            });
            startDialogActivity.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(MainActivity.this, DialogActivity.class);
                    startActivity(intent);
                }
            });
        }
    }
    

对比两段代码可以看出,只有继承的头文件不同,运行出来的界面也不一样,顶部的 ActionBar 在 AS 中只有继承 AppCompatActivity时才会出现(注:在 Eclipse 中继承 Activity 的效果和 AS 中继承 AppCompatActivity 的效果才一样)

去掉 AppCompatActivity 的标题栏

if (getSupportActionBar() != null){
	getSupportActionBar().hide();
}

Google 官方 api 文档对于 AppCompatActivity 功能的介绍

贴一段英文的科普回答

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 兼容老版本的新功能,如果你要在老版本系统使用 md 设计风格,就用 AppCompatActivity,如果你不想使用 md,但你又想使用 fragments,那你就用 FragmentActivity,如果你都不想要,那就直接用 Activity,当然由于 AppCompatActivity 又是继承 FragmentActivity 的,所以用 AppCompatActivity 就够了

加载流程的区别

通过分析源码可知,Activity 关于界面的绘制实际上是交给 PhoneWindow 中的 setContentView 实现的,而对于 AppCompatActivity 来说,通过拦截 View 的创建来实现对低版本进行相应的兼容,不执行系统的 onCreateView,而是执行自己的 onCreateView 进行替换所有系统的 View 控件

总结

Activity 和 AppCompatActivity 主要有两点变化

  • 主界面带有 ActionBar 的标题栏
  • theme 主题只能使用 android:theme=“@style/Theme.AppCompat.(主题)”, 而不能使用 android:style,否则会报错(踩坑警告!!!)