原文:[置顶] Android菜鸟的成长笔记(7)——什么是Activity

前面我们做了一个小例子,在分析代码的时候我们提到了Activity,那么什么是Activity呢?

Activity是Android应用程序提供交互界面的一个重要组件,也是Android重要组件之一(另外3个是Service、BroadcastReceiver和ContentProvider)。

与开发Web应用时建立Servlet类相似,建立自己的Activity也需要继承Activity基类,当然,在不同应用场景下,有时也要求继承Activity的子类。例如如果应用程序界面只包括列表,则可以让应用程序继承ListActivity;如果应用程序界面需要实现标签页效果,则可以让应用程序继承TabActivity。

Activity的启动过程

1、建立activity类及定义属性和内部方法

2、注册activity在manifest文件中

3、在启动函数onCreate中实现业务

3.1 界面定义layout

3.2界面的绑定setContentView()

package com.example.myfirstapp;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu; public class MainActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}

这是我们前面的Activity,下面我们来实现一个LauncherActivity

LauncherActivity继承了ListActivty,因此它本质上也是一个开发列表界面的Activity,但它开发出来的列表界面与普通列表界面有所不同。它开发出来的列表界面中的每个列表项都对应一个Intent,因此当用户单击不同的列表项时,应用程序会自动启动对应的Activity。

package com.example.testactivity;

import android.app.LauncherActivity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.ArrayAdapter; public class MainActivity extends LauncherActivity {
// 定义两个Activity的名称
String[] names = { "选项一", "选项二" };
// 定义两个Activity对应的实现类
Class<?>[] clazzs = { ActivityTest1.class, ActivityTest2.class }; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, names);
// 设置该窗口显示列表所需的Adapter
setListAdapter(adapter);
} @Override
protected Intent intentForPosition(int position) {
// TODO Auto-generated method stub
return new Intent(MainActivity.this,clazzs[position]);
}
}

一个Android应用通常包含多个Activity,但是只有一个Activity会作为程序的入口,如上面的MainActivity

    <application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ActivityTest1"> </activity>
<activity
android:name=".ActivityTest2"> </activity>
</application>

Activity启动其他Activity有两个方法

startActivity(Intent intent) :启动其他Activity

startActivityForResult(Intent intent, int requestCode) :以指定的请求码启动Activity,而且程序将会等到新启动Activity的结果(通过重写onActivityResult方法获取)

Android为关闭Activity提供了如下两个方法

finish() :结束当前Activity

finishActivity(int requestCode) :结束以startActivityForResult(Intent intent, int requestCode)方法启动的Activity

下面我们来看看Activity的生命周期

归纳起来Activity大致有如下4个状态

1、活动状态(runing) :当前activity处于前台,用户可见,可以获得焦点

2、暂停状态(pause):其他activity位于前台,该activity依然可见,只是不能获得焦点

3、停止状态(stop):该activity不可见,失去焦点

4、销毁状态(destory):该activity结束,或activity所在的Dalvik进程被结束

接下来再来看看配置Activity时候的android:launchMode属性

当我们启动一个应用的时候实际上Dalvik虚拟器会创建一个Task,而每个进程都有一个id,虚拟机是以栈的形式来管理每个Task的,先启动的activity放在Task栈底,后启动的activity放在Task栈顶。

Activity的加载模式,就负责管理实例化、加载activity的方式(也就是上面的android:launchMode设置)

1、standard模式

每次通过这种模式启动activity时,android总会为目标activity创建一个新的实例,并将该activity添加到栈中。

这种模式不会产生新的Task,新activity将被添加到原有的Task中。

例如:

package com.example.helloword;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast; public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "" + getTaskId());
button = (Button) findViewById(R.id.main_button);
button.setOnClickListener(new OnClickListener() { @Override
public void onClick(View arg0) {
//创建启动MainActivity的Intent
Intent intent = new Intent(MainActivity.this, MainActivity.class);
startActivity(intent);
}
});
} }

不断的按上面的按钮,控制台打印结果如下:

这证明了每次都调用了onCreate方法,但是Task是同一个。

2、singleTop模式

与standard模式不同的是当将要被启动的目标Activity已经位于Task栈顶时,系统不会重新创建activity实例。

如果将上面代码中的Activity的启动模式改为singleTop,点击多次,都不会再次调用onCreate方法。

3、singleTask模式

采用这种模式的Activity在同一个Task内只有一个实例。分为如下三种情况:

(1)如果将要启动的目标Activity不存在,体统会创建目标activity的实例,并将它加入Task栈顶

(2)如果将要启动的目标activity已经位于Task栈顶,此时与singleTop模式的行为相同

(3)如果将要启动的目标activity已经存在、但是没有位于Task栈顶,系统将会把位于该activity上面的所有activity移出Task栈,从而使目标activity转入栈顶

4、singleInstance模式

这种模式下,系统会保证无论哪个Task中启动目标activity,只会创建一个目标activity实例,并会使用一个全新的Task栈来装载activity实例。

接下来我们进入Android系统源代码看看Activity装载界面的过程

    /**
* Set the activity content to an explicit view. This view is placed
* directly into the activity's view hierarchy. It can itself be a complex
* view hierarhcy.
*
* @param view The desired content to display.
*/
public void setContentView(View view) {
getWindow().setContentView(view);
}

打开Activity.java的源码会看到setContentView方法实际上调用的是Window对象的setContentView方法,其实Window是一个抽象类,真正是通过PhoneWindow来实现的

    @Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
mContentParent.addView(view, params);
final Callback cb = getCallback();
if (cb != null) {
cb.onContentChanged();
}
}

如果根视图为null则创建一个window否则之间加载视图文件,这样我们就明白了,其实视图是加载到Window对象上的,接下来我们再来看一下如何将Activity和Window联系起来,其实在启动activity的时候会调用一个attach方法

    final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
Object lastNonConfigurationInstance,
HashMap<String,Object> lastNonConfigurationChildInstances,
Configuration config) {
attachBaseContext(context); mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
mUiThread = Thread.currentThread(); mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstance = lastNonConfigurationInstance;
mLastNonConfigurationChildInstances = lastNonConfigurationChildInstances; mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}

看到代码中有mWindow = PolicyManager.makeNewWindow(this)现在应该明白了吧。

总结起来有两点:

1、Activity构造的时候调用了attach绑定了一个窗体

2、Activity在setContentView的时候实际上是它所绑定的窗体设置contentView

Android菜鸟的成长笔记(7)——什么是Activity的更多相关文章

  1. Android菜鸟的成长笔记(3)——给QQ登录界面说So Easy

    原文:Android菜鸟的成长笔记(3)--给QQ登录界面说So Easy 上一篇:Android菜鸟的成长笔记(2)--第一个Android应用 我们前面已经做了第一个Android应用程序,虽然有 ...

  2. Android菜鸟的成长笔记(2)——第一个Android应用

    原文:Android菜鸟的成长笔记(2)--第一个Android应用 上一篇:Android菜鸟的成长笔记(1)--Anddroid环境搭建从入门到精通 在上一篇Android菜鸟的成长笔记(1)中我 ...

  3. Android菜鸟的成长笔记(1)——Android开发环境搭建从入门到精通

    原文:Android菜鸟的成长笔记(1)--Android开发环境搭建从入门到精通 今天在博客中看到好多Android的初学者对Android的开发环境的搭建不熟悉而导致不能进行学习,所以我决定自己写 ...

  4. Android菜鸟的成长笔记(14)—— Android中的状态保存探究(上)

    原文:[置顶] Android菜鸟的成长笔记(14)—— Android中的状态保存探究(上) 我们在用手机的时候可能会发现,即使应用被放到后台再返回到前台数据依然保留(比如说我们正在玩游戏,突然电话 ...

  5. Android菜鸟的成长笔记(13)——异步任务(Async Task)

    原文:[置顶] Android菜鸟的成长笔记(13)——异步任务(Async Task) Android的UI线程主要负责处理用户的事件及图形显示,因此主线程UI不能阻塞,否则会弹出一个ANR(App ...

  6. Android菜鸟的成长笔记(12)——Handler、Loop、MessageQueue

    原文:[置顶] Android菜鸟的成长笔记(12)——Handler.Loop.MessageQueue 当一个程序第一次启动时,Android会启动一条主线程(Main Thread),主线程主要 ...

  7. Android菜鸟的成长笔记(11)——Android中的事件处理

    原文:[置顶] Android菜鸟的成长笔记(11)——Android中的事件处理 Android提供了两种方式来处理事件,一个是基于回调的事件处理,另一个是基于监听的事件处理,举个例子: 基于回调的 ...

  8. Android菜鸟的成长笔记(10)——使用Bundle在Activity之间传值

    原文:[置顶] Android菜鸟的成长笔记(10)——使用Bundle在Activity之间传值 前面我们了解了如何启动一个Activity,一个Activity在启动另外一个Activity的时候 ...

  9. Android菜鸟的成长笔记(9)——Intent与Intent Filter(下)

    原文:[置顶] Android菜鸟的成长笔记(9)——Intent与Intent Filter(下) 接着上一篇的内容,下面我们再来看看Intent的Data与Type属性. 一.Data属性与Typ ...

  10. Android菜鸟的成长笔记(8)——Intent与Intent Filter(上)

    原文:[置顶] Android菜鸟的成长笔记(8)——Intent与Intent Filter(上) Intent代表了Android应用的启动“意图”,Android应用将会根据Intent来启动指 ...

随机推荐

  1. GridView控件-01-[简单的数据显示]

    GridView绑定数据分为两种,一种是多值绑定,另一种是字段绑定. 多值绑定(直接绑定到数据源就行,不需要使用字段): 前台代码: <asp:GridView ID="GridVie ...

  2. CentOS6.5 配置防火墙+允许指定ip访问端口

    参考博文: iptables防火墙只允许指定ip连接指定端口.访问指定网站 一.配置防火墙 打开配置文件 [root@localhost ~]# vi /etc/sysconfig/iptables ...

  3. 简单描述RAID级别:

    简单描述RAID级别: RAID 0 是俩盘一起读写,如果一个坏了那么数据全丢失: RAID 1是一块写,一块用来备份,坏一块无所谓: RAID 2 ,3 ,4 不常用: 最常用的就是RAID 5和R ...

  4. 文本导出到pdf文件(使用QPrinter和QPainter和QTextDocument)

    程序中数据导出是经常有的需求,今天学习把文本导出到pdf文件.主要是用QPrinter,QPainter TextEditToPdf::TextEditToPdf(QWidget *parent, Q ...

  5. 海量数据存储之Key-Value存储简介

    Key-value存储简介 具备高可靠性及可扩展性的海量数据存储对互联网公司来说是一个巨大的挑战,传统的数据库往往很难满足该需求,并且很多时候对于特定的系统绝大部分的检索都是基于主键的的查询,在这种情 ...

  6. 黑马day16 jquery&amp;层次选择器

    假设想通过DOM元素之间的层次关系来获取特定元素,比如后代元素,子元素,相邻元素,兄弟元素等,则须要使用层次选择器. 1 .ancestor descendant 使用方法: $("form ...

  7. em换算px

    一般浏览器默认的1em=16px,所以常用字体大小如下: 10px=0.625em 12px=0.75em 14px=0.875em 16px=1em 18px=1.125em 20px=1.25em ...

  8. WCF技术剖析之二十: 服务在WCF体系中是如何被描述的?

    原文:WCF技术剖析之二十: 服务在WCF体系中是如何被描述的? 任何一个程序都需要运行于一个确定的进程中,进程是一个容器,其中包含程序实例运行所需的资源.同理,一个WCF服务的监听与执行同样需要通过 ...

  9. Android studio: 自 maven 增加一個函式庫

    在 android studio 裏要加入一個 3rd party 的 library 其實不是很麻煩, 祇是現在沒有 UI, 所以需要一些手動作業.看來 google 很看好 android stu ...

  10. mysql双机热备的配置步骤

    设置双机热备: 首先要在两台机器上建立同步用户: grant replication slave on *.* to 'repdcs'@'192.168.21.39' identified by '1 ...