Android 官网Train阅读记录——1

LZ阅读的是中文翻译版本:http://hukai.me/android-training-course-in-chinese/basics/activity-lifecycle/recreating.html,试验机系统版本7.1。

1、Android入门基础

1.2 添加ActionBar

虽然早就被Toolbar取代了,但是我还是将ActionBar相关的东西看了一遍,并且实践了一下。

以下内容均支持2.1及以上版本系统。

首先,想要添加ActionBar,需要Activity继承AppCompatActivity,并且主题要继承自Theme.AppCompat,这样就会自动添加ActionBar。


为ActionBar添加UP按钮,在需要添加按钮的Activity清单文件中添加属性

android:parentActivityName="parentActivity"

在4.0及以下系统中需多加一个meta-data属性

<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.myfirstapp.MainActivity" />

在该Activity的onCreate方法中添加

getSupportActionBar().setDisplayHomeAsUpEnabled(true);
这样,该Activity的ActionBar视图左侧就会出现一个回退箭头,点击它会退到上一个Activity。

为ActionBar添加图片或文字按钮,在res目录下新建menu目录,并创建menu.xml文件,在其中添加对应的按钮即可

<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- 搜索, 应该作为动作按钮展示-->
<item android:id="@+id/action_search"
android:icon="@drawable/ic_action_search"
android:title="@string/action_search"
android:showAsAction="ifRoom" />
<!-- 设置, 在溢出菜单中展示 -->
<item android:id="@+id/action_settings"
android:title="@string/action_settings"
android:showAsAction="never" />
</menu>
其中,icon属性指明图片按钮的图片,title指明文字按钮的文字,如果有icon,就会显示为图片按钮,如果没有图片,就会显示文字按钮。showAsAction表示按钮显示的方式,ifRoom值表示如果有足够空间,就会显示,never表示该按钮永远不会显示,只会包含在三个点中。

在Activity中要重写onCreateOptionsMenu方法填充Menu

@Override
public boolean onCreateOptionsMenu(Menu menu) {
   // 为ActionBar扩展菜单项
   getMenuInflater().inflate(R.menu.main_activity_actions, menu);
   return super.onCreateOptionsMenu(menu);
}
为各按钮添加点击事件,重写onOptionsItemSelected方法

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // 处理动作按钮的点击事件
    switch (item.getItemId()) {
        case R.id.action_search:
            	openSearch();
            	return true;
        case R.id.action_settings:
            openSettings();
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}
这样ActionBar上就会出现一个图片按钮,还有三个点,点击三个点会出现settings按钮,点击相应的图片或settings按钮,会响应相应的事件。


自定义ActionBar背景,文字颜色,这些都需要自定义主题来实现。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="CustomActionBarTheme"
           parent="@style/Theme.AppCompat.Light.DarkActionBar"
           >
        <item name="actionBarStyle">@style/MyActionBar</item>
        <item name="actionBarTabTextStyle">@style/MyActionBarTabText</item>
        <item name="actionMenuTextColor">@color/actionbar_text</item>
        <item name="windowActionBarOverlay">true</item>
    </style>

    <style name="MyActionBar"
           parent="@style/Widget.AppCompat.ActionBar"
            >
        <item name="background">@color/translucent</item>
        <item name="titleTextStyle">@style/MyActionBarTitleText</item>
    </style>

    <style name="MyActionBarTitleText"
           parent="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
           >
        <item name="android:textColor">@color/actionbar_text</item>
    </style>

    <style name="MyActionBarTabText"
           parent="@style/Widget.AppCompat.ActionBar.TabText">
        <item name="android:textColor">@color/actionbar_text</item>
    </style>
</resources>

自定义ActionBar主题,必须要继承自Theme.AppCompat。

要实现自定义背景,需要自定义actionBarStyle,它的值MyActionBar继承自Widget.AppCompat.ActionBar,在MyActionBar中定义background的值,即为ActionBar的背景。

自定义ActionBar的字体,需要在MyActionBar中添加titleTextStyle属性,它的值是MyActionBarTitleText,继承自TextAppearance.AppCompat.Widget.ActionBar.Title,在其中定义android:textColor属性即可定义ActionBar的字体颜色。

其他的像actionBarTabTextStyle属性表示ActionBar下的tab的字体样式,actionMenuTextColor属性表示文字按钮的颜色。

windowActionBarOverlay属性表示是否叠加ActionBar,其值如果为true,表示叠加,即ActionBar不占用Activity高度,Activity顶端的内容会被ActionBar遮盖,如果要看其内容,可以设置ActionBar的背景为透明;默认结尾false,表示不叠加,ActionBar占用Activity高度,Activity内容显示在ActionBar下方。


1.3 兼容不同的设备

1.3.1 适配不同的语言

很简单,就是创建多个values文件夹,类似values-zh-rCN这样,后面的zh-rCN表示中国,这样的后缀有很多,需要哪个国家或地域,就创建这样的values文件夹即可。默认的values文件夹表示英文。


1.3.2 适配不同的屏幕

1.3.2.1 适配不同的屏幕尺寸

1、用wrap_content和match_parent代替固定宽高值

2、使用RelativeLayout

3、使用尺寸限定词,如:res/layout-large

4、使用最小宽度限定词,如:res/layout-sw600dp

5、使用布局别名:res/values-large/layout.xml

<resources>
    <item name="main" type="layout">@layout/main_twopanes</item>
</resources>
res/values-sw600dp/layout.xml

<resources>
  <item name="main" type="layout">@layout/main_twopanes</item>
</resources>
这是因为3.2以前版本只能使用尺寸限定词,而最小宽度限定词只能在3.2及以上版本使用,所以用布局别名可以不用重复创建main_twopanes.xml文件。

6、使用方向限定词:

小屏幕,纵向,一个窗格                                  res/layout/onepane.xml

小屏幕,横向,一个窗格 res/layout/onepane.xml

7寸屏幕,纵向,一个窗格加ActionBar res/layout/onepane_with_bar.xml

7寸屏幕,横向,两个宽窗格加ActionBar res/layout/twopanes.xml

10寸屏幕,纵向,两个窄窗格加ActionBar    res/layout/twopanes_narrow.xml

10寸屏幕,横向,两个宽窗格加ActionBar    res/layout/twopanes.xml

电视,横向,两个宽窗格加ActionBar res/layout/twopanes.xml

这里有四种布局文件,且又有横向又有纵向,所以为了使用,可以定义以下文件

res/values/layouts.xml

<resources>
    <item name="main_layout" type="layout">@layout/onepane_with_bar</item>
    <bool name="has_two_panes">false</bool>
</resources>
res/values-sw600dp-land/layouts.xml

<resources>
    <item name="main_layout" type="layout">@layout/twopanes</item>
    <bool name="has_two_panes">true</bool>
</resources>
res/values-sw600dp-port/layouts.xml

<resources>
    <item name="main_layout" type="layout">@layout/onepane</item>
    <bool name="has_two_panes">false</bool>
</resources>
res/values-large-land/layouts.xml

<resources>
    <item name="main_layout" type="layout">@layout/twopanes</item>
    <bool name="has_two_panes">true</bool>
</resources>
res/values-large-port/layouts.xml

<resources>
    <item name="main_layout" type="layout">@layout/twopanes_narrow</item>
    <bool name="has_two_panes">true</bool>
</resources>
7、使用.9图片


1.3.2.2 适配不同的屏幕密度

1、使用dp和sp代替px

2、 提供可选择的图片,在不同的mipmap文件夹中各放置一份图片


1.4 管理Activity的生命周期

启动和销毁Activity

其中启动就是onCreate方法,通常在里面做一些初始化操作。

当在onCreate方法中创建了线程或者做了其他有可能导致内存泄漏的操作,则要在onDestroy中进行资源清理,杀死线程。


暂停和恢复Activity

暂停就是onPause,通常可以在里面做以下操作:

停止动画或其他正在运行的操作

提交在用户离开时期待保存的内容

释放系统资源,如广播、传感器等

恢复就是onResume,通常用来初始化在onPause里面释放掉的组件,并执行那些Activity每次进入Resumed state都需要的初始化操作。


停止与重启Activity

因为系统在Activity停止时会在内存中保存Activity的实例,所以有时不需要实现onStop,onRestart甚至是onStart方法,因为大多数的Activity相对比较简单,Activity会自己停止与重启,我们只需要使用onPause来停止正在运行的动作并断开系统资源链接。

当Activity调用onStop方法,Activity不再可见,并且应该释放那些不再需要的所有资源。一旦 Activity停止了,系统会在需要内存空间时摧毁它的实例。极端情况下,系统会直接杀死我们的app进程,并不执行Activity的onDestroy方法,因此我们需要使用onStop方法来释放资源,从而避免内存泄漏。

Activity已经停止后,Activity对象会保存在内存中,并在Activity Resume时被重新调用。我们不需要再回复到Resumed state状态前重新初始化那些被保存在内存中的组件。系统同样保存了每一个在布局中的视图的当前状态,如果用户在EditText组件中输入了text,它会被保存,因此不需要保存与恢复它。

当Activity从Stopped状态回到前台时,它会调用onRestart方法,系统再调用onStart方法,onStart方法会在每次Activity可见时都会被调用。onRestart方法则是只在Activity从Stopped状态恢复时才会被调用,因此我们可以使用它来执行一些特殊的恢复工作,请注意之前是被Stop而不是Destroy。


重新创建Activity

因为系统资源紧张而导致Activity的Destroy,系统会在用户回到这个Activity时有这个Activity存在过的记录,系统会使用那些保存的记录数据(描述了当Activity被Destroy时的状态)来重新创建一个新的activity实例。那些被系统用来恢复之前状态而保存的数据被叫做“instance state”,它是一些存放在Bundle对象中的key-value pairs。

你的Activity会在每次旋转屏幕时被destroyed与recreated。当屏幕方向改变时,系统会Destroy与Recreate前台的Activity,因为屏幕配置被改变,你的Activity可能需要另一些替代的资源(例如layout)。

默认情况下,系统使用Bundle实例来保存每一个View对象中的信息(例如输入EditText中的文本内容)。因此,如果Activity被destroyed与recreated,则layout的状态信息会自动恢复到之前的状态。然而,Activity也许存在更多你想要恢复的状态信息,例如记录用户Progress的成员变量。

为了使Android系统能够恢复Activity中的View状态,每个View都必须有一个唯一ID,由android:id属性定义。

为了保存更多的状态信息,可以复写onSaveInstanceState方法,例

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
...

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state
    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
    savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);

    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(savedInstanceState);
}
Caution:必须要调用onSaveInstanceState方法的弗雷实现,这样默认的弗雷实现才能保存视图的状态信息。

为了恢复Activity的状态信息,可以下onCreate中直接恢复

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Always call the superclass first

    // Check whether we're recreating a previously destroyed instance
    if (savedInstanceState != null) {
        // Restore value of members from saved state
        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
        mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // Probably initialize members with default values for a new instance
    }
    ...
}
由于onCreate方法会在第一次创建新的Activity实例与重新创建之前被Destroy的实例时都会被调用,我们必须在尝试读取Bundle对象前检测它是否为null。若为null,系统则创建一个新的Activity实例,而不是恢复之前被Destroy的Activity。

也可以复写onRestoreInstanceState方法,因为此方法在onStart方法之后执行,系统仅仅会在需要恢复状态信息时才会调用之,因此不需要检查Bundle是否为null。

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState);

    // Restore state members from saved instance
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}
Caution:与上面的保存状态信息方法一样,总是需要调用onRestoreInstanceState方法的父类实现,这样默认的父类实现才能恢复视图的状态信息。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值