Android菜鸟的成长笔记(7)——什么是Activity

原文:[置顶] 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

时间: 2024-11-01 12:39:31

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

Android菜鸟的成长笔记(5)——Android系统源代码你下载了吗?

原文:Android菜鸟的成长笔记(5)--Android系统源代码你下载了吗? 在上一篇中我们用Android系统源代码分析了我们前面写的代码,有的朋友可能就会问怎么才能下载到Google官方的源代码呢?下面我们通过Git管理工具来对Android系统源代码进行下载.另外为了方便有的朋友下载,我将下载好的各个版本的源码存放到360云盘,云盘下载链接如下: http://yunpan.cn/QDEkq3uFrbvrI (访问密码:968e) 首先下载Git版本管理工具:下载地址:http://c

Android菜鸟的成长笔记(6)——剖析源码学自定义主题Theme

原文:Android菜鸟的成长笔记(6)--剖析源码学自定义主题Theme 还记得在Android菜鸟的成长笔记(3)中我们曾经遇到了一个问题吗?"这个界面和真真的QQ界面还有点不同的就是上面的标题myFirstApp,怎么去掉这个标题呢?",当时我直接在AndroidMainfest.xml中添加了一个属性: android:theme="@android:style/Theme.NoTitleBar" 可能有的朋友就会迷惑了,为什么添加了这个属性就可以了.这一篇

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

原文:Android菜鸟的成长笔记(1)--Android开发环境搭建从入门到精通 今天在博客中看到好多Android的初学者对Android的开发环境的搭建不熟悉而导致不能进行学习,所以我决定自己写一个搭建过程的文章. 一.JDK安装 http://www.oracle.com/index.html  下载地址 选择JavaSE JDK进行下载 下载下来后进行安装(默认步骤安装) 设置环境变量步骤如下: 我的电脑->属性->高级->环境变量->系统变量中添加以下环境变量:    

Android菜鸟的成长笔记(4)——你真的理解了吗?

原文:Android菜鸟的成长笔记(4)--你真的理解了吗? 在上一篇中我们查看了QQ的apk源文件中的布局结构,并仿照QQ完成了我们第一个应用的界面,详细请看<Android菜鸟的成长笔记>专栏.这一篇中我们来具体看看这个界面到底是怎么呈现出来的,具体的原理是什么等问题,下面我们将一步一步的解开留在我们心中的谜团. 有的朋友可能会产生这样的疑问为什么几句代码就能显示这样好看的界面? 其实能让这个界面显示的如此丰富多彩,一半功劳在我们编写的那几句代码,还有一半功劳在我们尊敬的google工程师

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

原文:Android菜鸟的成长笔记(3)--给QQ登录界面说So Easy 上一篇:Android菜鸟的成长笔记(2)--第一个Android应用 我们前面已经做了第一个Android应用程序,虽然有点像QQ的登录界面,但是很多地方还是很难看,这一篇咱们来将这个界面做成一个标准的商业界面,并一起来了解Android中的代码运行的原理. 好吧,咱们开始吧,首先启动模拟器,为了让咱们的界面和QQ的登录界面一样我下载了一个QQ的apk文件,下面咱们将这个apk安装到我们的模拟器上,看看效果. 怎么将a

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

原文:[置顶] Android菜鸟的成长笔记(13)--异步任务(Async Task) Android的UI线程主要负责处理用户的事件及图形显示,因此主线程UI不能阻塞,否则会弹出一个ANR(Application Not Responding)异常,所以不能在UI线程中执行耗时操作.AsyncTask<>是一个抽象类,通常被继承,继承时需要指定三个泛型: AsyncTask<Params, Progress, Result> Params:启动任务执行的输入参数的类型 Prog

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

原文:Android菜鸟的成长笔记(2)--第一个Android应用 上一篇:Android菜鸟的成长笔记(1)--Anddroid环境搭建从入门到精通  在上一篇Android菜鸟的成长笔记(1)中我们已经介绍了Android环境的搭建,下面我们就来开发一个属于我们自己的好玩的应用吧,是不是已经迫不及待了,下面我们先来看看运行效果. 首先我们要创建一个手机模拟器 点击eclipse上面的模拟器图标,弹出如下弹框. 点击右边的New...按钮,我们来创建一个"手机",这个手机几乎和我们

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

原文:[置顶] Android菜鸟的成长笔记(14)-- Android中的状态保存探究(上) 我们在用手机的时候可能会发现,即使应用被放到后台再返回到前台数据依然保留(比如说我们正在玩游戏,突然电话来了,当接完电话游戏继续玩),某些应用甚至会保留你离开时候的状态及数据,这些原理是什么?怎么去实现这样的应用?这将是我们这一篇文章要解开的问题. 有一句很常见的代码如下,很多人不知道为什么要加这么一句话 @Override protected void onCreate(Bundle savedIn

Android菜鸟的成长笔记(15)—— Android中的状态保存探究(下)

原文:Android菜鸟的成长笔记(15)-- Android中的状态保存探究(下) 在上一篇中我们简单了解关于Android中状态保存的过程和原理,这一篇中我们来看一下在系统配置改变的情况下保存数据及恢复数据的过程. 下面我们先来看一个现象:(代码在 Android中状态保存探究(上)中) 先启动应用如下: 打印的Log 再翻转屏幕 打印的Log如下 可以看到每翻转一次屏幕实际上系统会停止原理的activity并销毁然后重新启动一次,在这个过程中会调用onSaveInstanceState方法