Activity的使用

一个Activity的使用主要可以分为Manifest文件、xml布局文件和Java代码的书写三部分。为了使得逻辑较为清晰,大致可以采用先写xml布局文件,再写Java代码,最后在manifest文件中进行注册的方式,因此本文将按照上述顺序对Activity的使用做一些简单的整理。

本文主体是对《Android第一行代码》的笔记整理,同时也会尽量的参考官方文档、技术博客。这里主要是自己的学习笔记,贴在这边仅供大家讨论和批评。


布局文件

Activity是用来提供用户交互的组件,因此在写Activity之前就应该大致的了解自己所要提供的ui,而Activity的ui部分往往是写在xml文件中,因此先书写xml布局文件是顺理成章的。

An Activity is an application component that provides a screen with which users can interact in order to do something, such as dial the phone, take a photo, send an email, or view a map.

此时我们往往面临着两个问题:

  • 可视化编辑好还是代码形式好?
  • 写在xml中好还是Activity中直接添加好?

//TODO

五种基本布局

LinearLayout

一个典型的LinearLayout文件如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

</LinearLayout>

这里比较重要的值是android:orientation,默认情况下它的值为horizontal,但是建议手动设置它的排列方式。

当排列方向为horizontal时,内部控件就不能将宽度设为match_parent,否则该控件就会将水平方向全部占满,同理,vertical的时候也是一样。

因此,为了避免这样的错误发生,建议手动设置排列方式,同时在内部控件的布局上要记得考虑外部布局的排列方式。

显然,内部控件的标签应该具备相应的控制属性,以使得内部控件更加符合LinearLayout的排列规律。

  • android:layout_gravity

    当排列方向为horizontal时,则只有垂直方向上的对齐方式才会生效,反之亦成立。

  • android:layout_weight

    控件将按照设置的权值进行分布。对应方向长度设为0dp。

    应用:

    我们可以通过指定部分控件的layout_weight来实现更好的效果。比如,在一个左侧为EditText,右侧为发送Button的水平LinearLayout布局中,将Button的宽度设为wrap_content,而将EditText的weight设为1(任意正数即可),则EditText会占满屏幕所有的剩余空间。

    一些考虑:

    每个控件都可以设置它的width和height两个属性,但是weight却只有一个(而没有width_weight或者height_weight),这也间接的证明了LinearLayout会忽略指定排列方向上的布局。

RelativeLayout

此处属性比较多,但是有一定的规律。

相对于父布局的四个属性:

属性名描述
android:layout_alignParentTop和父布局的顶端对齐
android:layout_alignParentBottom和父布局的底端对齐
android:layout_alignParentLeft和父布局的左侧对齐
android:layout_alignParentRight和父布局的右侧对齐

注意:
可以同时指定多个属性,当两个属性不冲突时(如左和上),则该控件会和父布局的左上角对齐;如果两个属性冲突,则该控件则矛盾的两个方向上拉伸。

相对于其他控件的四个属性:

属性名描述
android:layout_above将控件置于指定控件之上
android:layout_below将控件置于指定控件之下
android:layout_toLeftOf将右边缘和指定控件的左边缘对齐
android:layout_toRightOf将左边缘和指定控件的右边缘对齐

注意:
此处需要提供指定控件的id,因此id的引用需要出现在定义之后。

此时,这些控件之间互斥(我的左边是你的右边,我的上边是你的下边),那么是否存在“我的左边也是你的左边”的属性呢?

相对于其他控件的另外四个属性:

属性名描述
android:layout_alignTop将上边缘和指定控件的上边缘对齐
android:layout_alignBottom将下边缘和指定控件的下边缘对齐
android:layout_alignLeft将左边缘和指定控件的左边缘对齐
android:layout_alignRight将右边缘和指定控件的右边缘对齐

讨论:
上述的属性和相对于父布局的属性较为相似,都是以align开头,表示将自己的某一边缘同指定控件的相应边缘对齐。由此而见,很多属性的设置意图都可以从字面意思上得到。

FrameLayout

应用场景相对较少,也没有任何的定位方式,所有的控件都会摆放在布局的左上角。

TableLayout

不是很常用,稍微了解一下即可。
贴上一段代码:

<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TableRow>
        <TextView
            android:layout_height="wrap_content"
            android:textSize="60sp"
            android:text="1_1"/>

        <TextView
            android:layout_height="wrap_content"
            android:textSize="60sp"
            android:text="1_2"/>
    </TableRow>

    <TableRow>
        <TextView
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:textSize="60sp"
            android:text="2_1"/>

        <TextView
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:textSize="60sp"
            android:text="2_2"/>
    </TableRow>

    <TableRow>
        <Button
            android:layout_height="wrap_content"
            android:layout_span="2"
            android:text="commit"/>
    </TableRow>

</TableLayout>
  • android:layout_width

    在每一个TableRow子标签中,控件是水平排列的(可以认为是一个LinearLayout?),此时不需要指定android:layout_width,但是可以指定android:layout_weight。指定android:layout_weight会改变控件在水平方向上的排列,但是不会改变单元格的宽度。

  • android:layout_span

    可以指定android:layout_span="2"来指定该控件将占据两列的宽度。不管span的值如何指定,控件长度将不小于1,不大于所有列的长度。

  • android:strethColumns

    需要写在父标签中,例如android:strethColumns=”1”,可以达到自适应屏幕宽度的作用,列号从开始。与指定layout_weight不同,它会改变列的实际宽度。

AbsoluteLayout

传说中的第五个基本布局,但是官方已经不推荐使用了。

引入布局

可以在一个布局文件中引用另外一个布局文件的布局,使用方法非常简单,只需要在需要引用该布局的地方加上<include layout="@layout/layout_tobe_included" />即可。这样可以复用布局文件,避免重复代码。

一些常见的控件

TextView

  • android:gravity

    指定文字的对齐方式(推荐),可选值有top、bottom、left、right和center等,可以用”|“来同时指定多个值

  • android:textSize

  • android:textColor

Button

可配置的属性同TextView差不多。

在较新的版本中,Button中的字符会自动显示为大写,解决方法是设置android:textAllCaps="false"

EditText

  • android:hint

    设置提示文本,只有text为空时才显示。

  • android:maxLines

    防止输入内容行数过多使得控件不断拉伸,导致界面难看。

ImageView

  • android:src
    设置图片的来源,如 android:src="@drawable/ic_launcher"

ProgressBar

  • android:visiblity

    可选值为visible、invisible和gone。gone表示不仅不可见,还不占用任何屏幕控件。

  • style

    指定ProcessBar的不同样式。

  • android:max

    给进度条设置最大值。

AlertDialog

对话框应该是在运行时才会出现,因此主要在Activity代码中添加。它能够屏蔽掉其他控件的交互能力。

ProgressDialog

与AlertDialog类似,但是可以显示一个进度条。

ListView

并不是特别的复杂

自定义控件

需要添加自定义控件的完整类名。

Activity类代码

生命周期

首先需要管理的是Activity的生命周期。

Activity有四个重要的状态:
1. active or running:
处于前台,或者说在back stack的顶部。
2. paused:
失去focus,但是仍然可见。它将保持所有的状态和成员信息,仍然attach在window manager上,只有在系统内存极低时才会被销毁。
3. stopped:
完全被其他Activity遮盖。仍然保持所有的状态和成员信息,但是不再可见,并且经常在其他地方需要内存时被销毁。
4. 当activity处于paused或者stopped状态时,系统在需要内存时就会请求activity自己finish或者简单的杀死它的进程。当用户再次看到这个Activity时,需要重新启动并且重新获取它之前的状态。
在此插入一个生命周期图:

Activity有三个重要的循环:
* 完整生命周期:
处于onCreate和onDestroy之间。在onCreate方法中做全局的准备工作,在onDestroy方法中释放资源。
* 可见期:
处于onStart和相应的onStop之间。此时用户可以看见Activity,但是可能不处于前台,也不能同用户进行交互。此时可以持有一些同显示相关的资源。
* 前台期:
处于onResume和onPause之前。此时该Activity处于其他所有Activity前面,并且可以与用户交互。Activity可能在resumed和paused之间频繁切换,因此它们中的代码应该尽量保持轻量。

理论的东西讲的太多了,还是直接讲讲生命周期相关的回调函数应该写些什么东东吧。

  • onCreate(Bundle savedInstanceState)
    再第一次被创建时调用,一般可以在这个方法中完成Activity的初始化动作,比如说加载布局(比如setContentView方法),绑定事件等。
  • onPause()
    我们通常在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据(通常是交给ContentProvider持有),但是执行速度一定要快,不然会影响到新的栈顶Activity的使用。

注意:
在实现这些生命周期相关的回调函数时,必须首先调用超类的实现。

被回收了怎么办?

在onSaveInstanceState(Bundle outState)方法中保存临时数据,而在onCreate或者onRestoreInstanceState方法中恢复数据。

注意:
onSaveInstanceState并不在生命周期的回调中,因此并非是在所有情况下都会被调用,因此一些数据应该尽量在onPause方法中进行存储。

与下一个Activity传递数据

需要详细了解Intent的用法,此处不赘述。

向下一个Activity传递数据

在Intent中放入数据,然后通过startActivity方法或者startActivityForResult方法启动下一个Activity,下一个Activity被启动后,通过getIntent方法得到启动该Activity的Intent,请取出其中的数据。

返回数据给上一个Activity

  • 上一个Activity
    需要通过startActivityForResult方法启动下一个Activity,第一个参数是Intent,第二个参数是请求码,请求码在之后可以用来判断是从哪次请求中返回的数据(不一定只有一种请求)。
    此外,需要复写onActivityResult方法,先根据返回的requestCode判断请求类型,然后再判断resultCode是否是正常返回(否则从Intent中取数据可能会导致异常),最后再从Intent中获取数据。

  • 下一个Activity
    在需要返回数据时,将数据放于Intent中,然后通过setResult方法返回,该方法第一个参数是返回码,RESULT_OK应该表示返回成功,而RESULT_CANCELED会在其他情况下被返回(如按下back键被按下时)。

    注意:
    数据只会通过Intent被返回一次,而且是在Activity结束之后,因此只能通信一次,整个Activity就像被调用的一个函数一样。

创建一个菜单

首先需要在menu目录下创建menu的布局文件,它的代码可以如下:

<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:id="@+id/add_item"
        android:title="Add" />

    <item
        android:id="@+id/remove_item"
        android:title="Remove" />
</menu>

然后需要在onCreateOptionSMenu方法中创建menu:

    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity, menu);
        return true;
    }

返回true表示允许创建的菜单显示出来,若为false则无法显示。

最后为了能够响应菜单事件,需要重写onOptionsItemSelected方法:

public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.add_item:
                Toast.makeText(this, "You clicked Add", Toast.LENGTH_SHORT).show();
                break;
            case R.id.remove_item:
                Toast.makeText(this, "You clicked Remove", Toast.LENGTH_SHORT).show();
        }
        return true;
    }

如果希望将菜单点击事件传递下去,继续触发其他处理,则返回false;如果认为已经处理完毕,不需要将事件传递下去则返回true。如果采用的是return super.onOptionsItemSelected(item),系统缺省返回false。

注意:
现在很多手机已经取消了menu按键,此时可以通过openOptionsMenu方法打开menu,也可以通过closeOptionsMenu方法关闭menu。

处理返回按键

重写onBackPressed方法:

public void onBackPressed() {
        // do anything you want.
        //super.onBackPressed();
    }

默认的实现简单的finish当前的Activity,重写该方法可以自定义back按键的动作。

处理Fragment

这将专门的在”Fragment的使用“中阐述。

Manifest文件

为了能够被Context.startActivity()方法启动,所有的Activity都需要在Manifest文件中注册。

Device Compatibility

System Permissons

Intent filter

详细的查看Intent用户手册。

* 注意:*
如果Activity支持隐式Intent启动,则需要添加DEFAULT的category,这是因为startActivity和startActivityForResult方法都会默认的添加DEFAULT的category。

启动模式

<activity>标签下指定android:launchMode属性来选择启动模式。不指定则默认为standerd模式。

  • standard
    每次启动一个新的Activity,它就会在back stack中入栈,并处于栈顶的位置。系统不会在乎这个Activity是否已经存在于back stack中,每次启动都会创建一个新的实例。
  • singleTop
    如果待启动Activity已经在back stack栈顶,则直接使用它而不重新创建。
  • singleTask
    如果待启动Activity在back stack中(不仅仅是在栈顶),则弹出该Activity之上所有的Activity,否则创建一个新的Activity。
  • singleInstance
    用来实现其他程序和我们的程序共享这个Activity的实例。因此,在这个模式下会有一个单独的back stack来管理这个Activity(实际上singleTask模式指定了不同的taskAffinity也会启动一个新的back stack),不管是哪个应用程序访问这个活动,都共用同一个back stack。
    // TODO
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值