android程序中最基本的组成部分是activity,一个程序有多个activity,当启动一个新的activity的时候,新的activity会出现在屏幕上覆盖旧的activity;当这个activity finish()的时候,之前的activity重新显示出来.
简单的说,这是一个类似于栈的结构,即原有activity A1:[A1]
现在新开activity A2:[A1 A2]
当A2finish的时候,再显示A1:[A1]
这符合栈的特点,即后入先出,也符合一般人的思考逻辑,及返回键返回到之前的页面.
但是这样的结构有一个局限性,这样启动的activity都是我们通过Activity.startActivity(intent)这种方式启动的,是属于全屏的.
当我们只是想在一个页面的某个部分去启动一个activity,而且还保持这种层次结构,应该如何进行呢?
在ios平台上最基本的元素是ViewController和Controller对应的View,因此ios平台上提供了一个以UIVIEW为元素的栈来时限这样的功能,称为UINavigationController.这里不讨论它的使用,有兴趣的同学可以自己去学习.这里重点说明一下如何用ActivityGroup来实现类似的功能.
- package com.zz;
- import java.util.Stack;
- import java.util.UUID;
- import android.app.ActivityGroup;
- import android.content.Intent;
- import android.os.Bundle;
- import android.view.KeyEvent;
- import android.view.View;
- import android.widget.LinearLayout;
- /**
- * 各个Tab对应的Activity的父类
- *
- * @author zhouzhe@lenovo-cw.com
- */
- public abstract class ActivityStack extends ActivityGroup {
- /** 一个activity的栈用来存放缓存的View */
- Stack<StackElement> stack;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- stack = new Stack<StackElement>();
- }
- /**
- * 一个抽象方法,返回一个LinearLayout实际上是一个区域用来展示栈内的view
- *
- * @return
- * @author zhouzhe@lenovo-cw.com
- * @time 2012-2-20
- */
- abstract LinearLayout getMainView();
- /**
- * 用来向栈顶添加一个元素并显示
- *
- * @param intent
- * 跟启动activity的intent一样
- * @author zhouzhe@lenovo-cw.com
- * @time 2012-2-20
- */
- void addView(Intent intent) {
- // 生成一个字符串,作为启动activity的key,后面在移除了view以后,要通过这个key来finish对应的activity
- String str = UUID.randomUUID().toString();
- getMainView().removeAllViews();
- View view = getLocalActivityManager().startActivity(str, intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)).getDecorView();
- // 注意layoutParams,否则会造成无法充满的问题
- getMainView().addView(view, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
- getMainView().requestFocus();
- // 生成一个栈内缓存对象,主要包括activity对应的view和对应的key,并压入栈中
- StackElement component = new StackElement(str, view);
- stack.add(component);
- }
- /**
- * 弹栈操作
- *
- * @return
- * @author zhouzhe@lenovo-cw.com
- * @time 2012-2-20
- */
- int pop() {
- // 先判断是否已经是栈顶元素了
- int size = stack.size();
- StackElement element = null;
- if (size > 1) {
- // 如果不是,获取到栈顶元素,并销毁.然后再获取当前的栈顶元素,显示到activityGroup
- element = stack.pop();
- getLocalActivityManager().destroyActivity(element.getTag(), true);
- element = stack.peek();
- } else if (size == 1) {
- // 如果是栈顶元素,直接显示
- element = stack.peek();
- }
- getMainView().removeAllViews();
- getMainView().addView(element.getView());
- getMainView().requestFocus();
- return stack.size();
- }
- /**
- * 清空Stack,仅保留最底层的view
- */
- void clearStack() {
- int size = stack.size();
- if (size > 1) {
- for (int i = 0; i < size - 1; i++) {
- stack.pop();
- }
- }
- }
- void clearAll() {
- int size = stack.size();
- if (size > 0) {
- for (int i = 0; i < size; i++) {
- StackElement element = stack.pop();
- getLocalActivityManager().destroyActivity(element.getTag(), true);
- }
- }
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- }
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- // 对键盘事件的处理,如果当前activityGroup中已经载入了activity,则分发给子activity处理,如果没有则自己处理.
- if (getCurrentActivity() != null) {
- return getCurrentActivity().dispatchKeyEvent(event);
- } else {
- return super.dispatchKeyEvent(event);
- }
- }
- }
这是一个比较简单的类,简单说明一下流程.
activityGroup载入activity,A1的时候,使用addView方法,压入栈中.在加载A2的时候,还是调用activityStack的addView方法,移除A1,加入A2并压入栈中.在finish A2的时候,不能直接finish,这样整个activityGroup都被finish掉了.要调用activityStack的pop方法,移除栈顶元素,销毁,显示移除后的栈顶元素.同时要注意分发键盘的back事件,同样是要用pop方法取代默认的finish方法,这样即可完成一个类似于uinavigationcontroller的栈.
有兴趣的同学看一下吧.
源代码 http://download.csdn.net/detail/zz880329/4076318