1.简介

相比苹果封闭的IOS系统,Android系统的开放性带来了很多的优势。与此同时,也带来了严重的碎片化问题,包括硬件的碎片化和软件碎片化。这里,我们主要说的是软件方面。各Android设备厂商,受限于成本和技术原因,往往无法及时把系统版本更新到最新的Android版本。这导致低版本的Android系统在市场上仍然有很高的占有率。如下是2019年7月统计的Android设备中系统版本的市场占有率分布情况。注:此数据来源于Google Play,有可能没有包含国内厂商不支持GMS的系统。


android compare android compare优势_Android


额外说一句,统计各版本系统在市场上的占有率,有什么意义呢?对于App开发者而言,当然是希望自己的应用,能在尽可能多的设备上运行,服务更多的用户(赚更多的钱),那么,当前市场上,什么版本的系统最多,自然是开发者需要考虑着重适配的系统版本了。举个栗子,如果你的app,只能支持Android5.0(Lollipop),其他版本都不能运行,那么,就算所有5.0的机器都装上了你的App,也只有3%的市场份额而已。

所以,支持高版本系统,同时兼容低版本系统,一直是App开发者的心头好。

2.AppCompat特点

  • 以Library的形式, 独立包含在应用中 ,为App提供在低版本Android系统上运行的兼容性支持。
  • AppCompat最早出现在V7 Support Library中,现已迁移到AndroidX,后续会跟随AndroidX库持续更新。下图展示的是AppCompat与Jetpack、Support Library以及Androidx的关系。

android compare android compare优势_Android_02

3.主要组件及使用方法

本文将主要说明AndroidX中AppCompat的使用。

Tool Bar

直译为工具栏(官方称应用栏),或称Action Bar,提供显示在应用顶部快捷操作的实现方案。如下图示:

android compare android compare优势_Android_03


可以通过添加操作按钮,可以将在当前上下文中最重要的操作放在应用顶部。

例如,当用户浏览文件列表时,可以再应用的顶部显示“搜索”按钮;当用户浏览单张图片时,可以在应用顶部显示“收藏“按钮;也可以提供快速跳转到“设置”的按钮,完成

工具栏中的空间有限。如果应用声明的操作数量过多,导致应用栏无法容纳,则应用栏会将无法容纳的操作发送到“溢出”菜单。应用还可以指定某项操作应始终显示在溢出菜单中,而不是显示在应用栏中。
下面介绍在Fragment中添加Tool Bar的步骤;如果需要在Activity中添加Tool Bar,与此类似,也可以参考[官方文档]: https://developer.android.google.cn/training/appbar/setting-up.html “设置应用栏”

  • 装载Fragment的Activity需要扩展 androidx.appcompat.app.AppCompatActivity
public class MyActivity extends AppCompatActivity {
	  // ...
}
  • 在应用清单中,将 元素设为使用 appcompat 的其中一个 NoActionBar 主题背景。使用其中一个主题背景可以防止应用使用原生 ActionBar 类提供应用栏。例如:
<application
   android:theme="@style/Theme.AppCompat.Light.NoActionBar"
/>

也可以把Theme定义在styles.xml文件中,如下所示,

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    </style>
</resources>

然后在清单文件中,使用这个Theme

<application
   android:theme="@style/AppTheme">
  • 向Fragment的布局文件中添加一个ToolBar,下面的示例将在Fragment界面的顶部添加一个Toolbar.
<androidx.appcompat.widget.Toolbar
 android:id="@+id/demo_toolbar"
 android:layout_width="match_parent"
 android:layout_height="?attr/actionBarSize"
 android:background="?attr/colorPrimary"
 android:elevation="4dp"
 android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
 app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
 app:layout_constraintEnd_toEndOf="parent"
 app:layout_constraintStart_toStartOf="parent"
 app:layout_constraintTop_toTopOf="parent" />

注:
android:elevation 是应用栏的高度,可参阅官方文档 Material Design 规范。
android:theme 是指ToolBar的Theme。
app:popupTheme 是指ToolBar中点击“溢出”图标,弹出的菜单的Theme。

  • 在 Fragment的 onCreateView() 方法中,调用 AppCompatActivitysetSupportActionBar() 方法,并传入工具栏。同时,必须调用setHasOptionsMenu(true)方法,设置ToolBar可用,否则工具栏将不会被创建和显示。如下示例:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
    View fragmentView = inflater.inflate(
        R.layout.fragment_tool_bar_demo, container, false);
    mToolbar = fragmentView.findViewById(R.id.demo_toolbar);
    mSearResultDemo = fragmentView.findViewById(R.id.search_demo_tv);
    ((AppCompatActivity) getActivity()).setSupportActionBar(mToolbar);
    setHasOptionsMenu(true);//必须调用此方法
    return fragmentView;
}
  • 自定义ToolBar上的按钮。
    ToolBar上的操作按钮可以在menu的XML文件中定义,可设置操作按钮的文字,图标,显示状态等信息,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/menu_action_1"
        android:title="@string/menu_action_1"
        app:showAsAction="never" />
    <item
        android:id="@+id/menu_action_2"
        android:title="@string/menu_action_2"
        app:showAsAction="never" />
    <item
        android:id="@+id/menu_action_3"
        android:title="@string/menu_action_3"
        app:showAsAction="never" />
    <item
        android:id="@+id/menu_action_search"
        android:title="@string/menu_search"
        app:actionViewClass="androidx.appcompat.widget.SearchView"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/menu_action_share"
        android:title="@string/menu_action_share"
        app:actionProviderClass="androidx.appcompat.widget.ShareActionProvider"
        app:showAsAction="ifRoom"/>
    <item
        android:id="@+id/menu_action_add_favorite"
        android:title="@string/menu_action_favorite"
        android:icon="@drawable/favorite"
        app:showAsAction="always" />
</menu>

注:
app:showAsAction用來标识这个Menu Item在ToolBar上的显示状态,包含如下几种:

always— 一直显示;
ifRoom — 如果ToolBar上有足够的空间,则显示,否则会放到“溢出”列表;
never— 始终放到“溢出“列表,不管是否有空间。

  • 加载自定义的menu布局
    重写Fragment中的onCreateOptionsMenu()方法,加载上面的menu xml文件。例如:
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.tool_bar_menu, menu);
    super.onCreateOptionsMenu(menu, inflater);
}
  • 响应点击事件
    重写Fragment中的onOptionsItemSelected()方法,处理按钮的点击事件,如下所示:
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
    switch(item.getItemId()) {
        case R.id.menu_action_1:
            // Add your code for action_1 button clicked
            break;
        case R.id.menu_action_2:
            break;
        case R.id.menu_action_3:
            break;
        case R.id.menu_action_add_favorite:
            break;
        default:
            break;
    }
    return super.onOptionsItemSelected(item);
}
  • 使用Tool Bar的Utility方法
    将工具栏设为 Fragment的应用栏后,如果要使用 ToolBar的Utility方法,可调用 Activity的 getSupportActionBar() 方法。此方法将返回对 appcompat ActionBar 对象的引用。获得该引用后,您就可以调用任何 ActionBar 方法来调整应用栏。例如,要隐藏应用栏,可调用 ActionBar.hide()

AppCompatActivity

可作为应用的Activity的基类,替换原生的Activity基类,实现有ToolBar的应用界面;目前,AppCompatActivity 通过间接继承ComponentActivity,现了LifecycleOwner接口,在应用自己的Activity中,可以通过 getLifecycle() 方法拿到 Lifecycle ,并添加 Observer 来实现对 Activity 生命周期的监听。 如下示例:

public class MyActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        testLifecycle();
    }
    private void testLifecycle() {
        getLifecycle().addObserver(new LifecycleObserver() {
            @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
            void onResume(){
                Log.d(TAG, "onResume: called by LifecycleObserver");
            }
            @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
            void onPause() {
            }
            @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
            void onDestroy() {
            }
        });
    }
}

AppCompatDialog

对话框类,使用此基类配合AppCompatActivity,可以实现与App其他界面风格统一的对话框。

  • styles.xml文件定义如下的风格样式
<resources>
    <style name="myDialogStyle" parent="Theme.AppCompat.Light.Dialog.Alert">
        <item name="colorAccent">@color/myColorAccent</item>
        <item name="android:textColorPrimary">@color/myTextColorPrimary</item>
        <item name="android:background">@color/myDialogBackGroundColor</item>
    </style>
</resources>
  • 构建AppCompatDialog时指定样式
private void testAppCompatDialog() {
    AlertDialog.Builder builder = new AlertDialog.Builder(this,R.style.myDialogStyle);
    builder.setTitle("AppCompatDialog");
    builder.setMessage("This is a demo dialog");
    builder.setPositiveButton("OK", null);
    builder.setNegativeButton("Cancel", null);
    builder.show();
}
  • 效果展示

ShareActionProvider

在应用栏上支持标准化分享操作,从而在应用之间通过Intent共享数据。例如发送电子邮件或发布到社交应用。
可以在onCreateOptionsMenu()中,初始化ShareActionProvider,并设置Intent,示例如下:

@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
    MenuItem shareItem = menu.findItem(R.id.menu_action_share);
    mShareActionProvider = (ShareActionProvider)
        MenuItemCompat.getActionProvider(shareItem);
    Intent myShareIntent = new Intent(Intent.ACTION_SEND);
    myShareIntent.setType("text/plain");
    myShareIntent.putExtra(Intent.EXTRA_TEXT, "a single string for share");
    mShareActionProvider.setShareIntent(myShareIntent);
    super.onCreateOptionsMenu(menu, inflater);
}

参考资料

https://developer.android.google.cn/training/appbar https://developer.android.google.cn/reference/androidx/appcompat/app/AppCompatActivity.html