NO END FOR LEARNING

Writing blog if you feel tired | 学海无涯 苦写博客

About Android Activity LifeCycle(译)

| Comments

Jasmine

Activity是应用的一个组件,它提供用户可以交互的屏幕,例如拨打电话,照相,发邮件,看地图。每一个Activity都会被赋予一个窗户用来绘画用户界面。这个窗口通常会占据整个屏幕,但是也可以比屏幕小和悬浮在其他窗口之上。

一个应用程序通常由多个Activity组成,它们之间以一种较为松弛的关系联系在一起。例如,一个Activity作为主要的Activity,它会作为程序启动时第一个展现给用户的Activity。每一个Activity能够启动另外一个Activity,以便去执行其他的动作。每一次一个新的Activity启动,前一个Activity就会停止,但是系统会将它保存在一个栈中(“back stack”)。当一个新的Activity启动时,当前的Activity会被压入栈中,并拿走焦点。这个栈遵守“后进先出”原则,所以,当用户在当前Activity完成对应操作,按下返回按钮的时候,它会从栈顶弹出,并销毁,然后前一个Activity恢复。

当一个Activity因为另一个新的Activity启动而停止时,系统会通过Activity生命周期中的回调函数通知它这个状态的变化。由于状态的改变,Activity会接受到多个回调函数,无论系统是在create,stop,resume还是destroy,并且每一次回调都提供你一个机会去执行适合这个状态变化的操作。例如,当stop时,你的Activity应该释放任何比较大的对象,例如网络和数据库连接。当Activity恢复时,你应该从新获取必要的资源和恢复之前被打断的操作。状态的转换是Activity生命周期的一部分。

通过回调函数去管理Activity的生命周期是实现健壮和灵活应用的关键。Activity的生命周期直接受到其他Activity,Task以及back stack的影响。

一个Activity可以存在于三个状态中:

Resumed

该状态下,Activity置于屏幕前景,并拥有聚焦,可以把这个状态理解为正在运行。

Paused

该状态下,另一个Activity正置于屏幕前景并拥有聚焦,但是当前Activity仍然可见。一个暂停的Activity是处于完全存活状态的(Activity对象仍然保有内存,它维持状态和成员信息,并保持与Window Manger的关系),但是如果内存不足时,系统有权利关闭该Activity。

Stopped

该状态下,该Activity完全被另一个Activity遮挡(该Activity就会进入到背景状态)。进入stopped状态的Activity也是仍然处于存活状态。然而,它对用户是不可见的,同样在系统需要内存的时候,它会被关闭。

如果一个Activity进入paused或者stopped状态,系统可以通过调用finish方法或者终止进程的方式,将Activity从内存中清除。当该Activity从新打开,他必须要重新创建一次。

Activity完整的生命周期发生于onCreate()方法和onDestroy()方法之间。Activity应该在onCreate()方法时,设置一些全局状态,例如布局,并且在onDestroy()方法释放所有保持的资源。例如,如果Activity拥有一个线程在后台运行并正在从网络上下载数据,该线程可能是在onCreate()方法中创建的,那么就应该在onDestroy()方法中停止该线程。

Activity的可见生命周期发生于onStart()方法和onStop()方法之间。在这段时间,用户可以在屏幕上看见它,并进行交互。例如,onStop()方法被调用发生在当一个新的Activity启动,而当前Activity不在可见时。在这两个方法之间,你可以保有Activity所需要的资源。例如,你可以在onStart()方法调用时,注册一个BroadCartReceiver,让他监控你对UI的操作,并在用户不在看到这个Activity时,在onStop()方法中注销这个BroadCartReceiver。

Activity前景生命周发生于onResume()方法和onPause()方法之间。在这段时间中,该Activity处于所有Activity的上方并且拥有用户输入焦点。Activity能够频繁的在前景中出镜和入镜。例如,当设备进入睡眠或者有一个对话框弹出时,在onPause()方法被调用时。因为,这个状态频繁的转变,在这两个方法中的代码要尽量的轻量级,以避免转换太慢,让用户等待。

Method Description Killable after? Next
onCreate() 当Activity第一次被创建时调用。在这里,你应该做所有关于静态配置的事情-创建View,绑定数据到List等等。这个方法会传入一个Bundle对象,如果Activity中有捕获自身状态,那么它包含了Activity之前的状态。 No onStart()
onRestart() 在Activity停止之后被调用,指明Activity会被重新启动。 No onStart()
onStart() 在Activity变成用户可见状态之前调用。如果Activity要变成前景状态,那么onResume()方法会被调用,如果Activity要被隐藏,则onStop()方法会被调用。 No onResume() or onStop()
onResume() 在Activity开始与用户交互之前调用。这个时候,Activity会置于栈顶,并伴随着用户输入。 No onPause()
onPause() 在系统开始要恢复另一个Activity时被调用。该方法通常被用于提交未保存数据到持久数据中,停止动画和其他会占用CPU资源的操作。并且应该非常迅速的做这些事情,因为下一个Activity只有在当前方法执行完成之后才会恢复。如果Activity回到前端,则onResume()方法跟在onPaused()方法后面,如果对用户不可见,则onStop()方法跟在后面。 Yes onResume() or onStop()
onStop() 当Activity对用户不在可见时被调用。onStop()发生的原因是Activity被销毁,或者另一个Activity被恢复并正在覆盖当前Activity。如果紧跟随着的是onRestart()方法,则说明Activity正在恢复与用户的交互。如果跟着的是onDestory()方法,则说明这个Activity要被销毁了。 Yes onRestart() or onDestroy()
onDestroy() 在Activity被销毁时调用。这是Activity最后一个会接收到的调用。被调用的原因要么是因为finish()方法在哪个位置调用,或者因为系统因为要保留资源而临时销毁它。可以通过isFinishing()方法来区分两种不同情况。 Yes nothing

文献参考自:http://developer.android.com/guide/components/activities.html

Web MVC by Example

| Comments

早期的web应用主要是静态页面的浏览。静态页面使用HTML语言来编写,放在服务器上。用户使用浏览器通过HTTP协议请求服务器上的Web页面,服务器上的Web服务器软件接收到用户发送的请求后,读取请求URI所标识的资源,加上消息报头发送给客户端的浏览器;浏览器解析响应中的HTML数据,从而向用户呈现多姿多彩的HTML页面。

CGI->Servlet->JSP->Model1->Model2

早期使用的Web服务器扩展机制是CGI,它允许用户调用Web服务器上的CGI程序。CGI的全称是Common Gateway Interface,即公共网关接口。用户通过单击某个链接或者直接在浏览器的地址栏中输入URL来访问CGI程序,Web服务器接收到请求后,发现这个请求是给CGI程序的,于是就启动并运行这个CGI程序,对用户请求进行处理。CGI程序解析请求中的CGI数据,处理数据,并产生一个响应(通常是HTML页面)。这个响应被返回给Web服务器,Web服务器包装这个响应(例如添加消息报头),以HTTP响应的形式发送给Web浏览器。

Java Servlet(Java服务器小程序Servlet=Server+Applet)是一个基于Java技术的Web组件,运行在服务器端,由Servlet容器所管理,用于生成动态的内容。Servlet是平台独立的Java类,编写一个Servlet,实际上就是按照Servlet规范编写一个Java类。

Servlet不能独立运行,它必须被部署到Servlet容器(例如:Tomcat)中,由容器来实例化和调用Servlet的方法,Servlet容器在Servlet的生命周期内包容和管理Servlet。

用户通过单击某个链接或者直接在浏览器的地址栏中输入URL来访问Servlet,Web服务器接收到该请求后,并不是将请求直接交给Servlet,而是交给Servlet容器。Servlet容器实例化Servlet,调用Servlet的一个特定方法对请求进行处理,并产生一个响应。这个响应由Servlet容器返回给Web服务器,Web服务器包装这个响应,以HTTP响应的形式发送给Web浏览器。

下面是用servlet编写的get和post请求页面例子:

web.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">

   <servlet>
       <servlet-name>hello</servlet-name>
       <servlet-class>me.zeph.springview.demo.HelloWorldServlet</servlet-class>
   </servlet>

   <servlet-mapping>
       <servlet-name>hello</servlet-name>
       <url-pattern>/hello</url-pattern>
   </servlet-mapping>

</web-app>
servlet.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package me.zeph.springview.demo;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class HelloWorldServlet extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      resp.setContentType("text/html");
      PrintWriter writer = resp.getWriter();
      writer.write("<h1>HelloWorld</h1>");
      writer.write("<form action='hello' method='post'>");
      writer.write("<input type='text' name='value'>");
      writer.write("<input type='submit' value='submit'>");
      writer.write("<form/>");
  }

   @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      resp.setContentType("text/html");
      String value = req.getParameter("value");
      PrintWriter writer = resp.getWriter();
      writer.write("Hi, " + value);
  }
}

这样的web开发流程都在实现一个servlet类的实例。也就是无论是业务逻辑还是前端显示,都是放在Servlet类中来完成,通过实现doGet和doPost的方法,来完成前端参数的获取和视图的渲染。

但这样做的缺点是表现逻辑、控制逻辑和业务逻辑全部写在了Java类中,导致逻辑有些混乱

之后,JSP技术出现,它由Sun和许多公司参与共同创建的一种使软件开发者可以响应客户端请求,而动态生成HTML、XML或其他格式文档的Web网页的技术标准。

它以Java语言作为脚本语言的,使Java代码和特定的预定义动作可以嵌入到静态页面中。

Sun这样做提供了非常好的前端显示,前端开发工程师也可以更好地改善页面体验,但实际上,它仍然没有解决前端显示和控制逻辑以及业务逻辑的混乱问题。

Servlet是将前端显示放在了Java类中,而JSP是将控制和业务逻辑放在了JSP中。

JSP+JavaBean是纯JSP的增强版被称为Model1。特点是使用<jsp:useBean>标准动作,自动将请求参数封装为JavaBean组件。

这样可以将部分业务逻辑封装到JavaBean中。

Model1的架构中,JSP要负责控制逻辑、表现逻辑和业务对象(JavaBean)的调用,所以实际上仍然不理想。

Model2架构其实可以认为就是我们所说的Web MVC模型,只是控制器采用Servlet、模型采用JavaBean、视图采用JSP

下面是一个Model2的例子:

web.xml配置和上面一样配置一个Servlet映射。但是Servlet只负责控制逻辑,不进行前端操作,而是直接将前端渲染分发给jsp页面进行。

HelloWorldServlet.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package me.zeph.springview.demo;

import me.zeph.springview.demo.domain.User;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloWorldServlet extends HttpServlet {

   public static final String GET_PATH = "WEB-INF/view/hello-world.jsp";
   public static final String POST_PATH = "WEB-INF/view/hello-world-confirm.jsp";

   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
     req.getRequestDispatcher(GET_PATH).forward(req, resp);
   }

   @Override
   protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         User user = getUserFromRequest(req);
     String path = null;
     if (user.validate()) {
        req.setAttribute("user", user);
        path = POST_PATH;
     } else {
        req.setAttribute("error", true);
        path = GET_PATH;
     }
     req.getRequestDispatcher(path).forward(req, resp);
   }

   private User getUserFromRequest(HttpServletRequest req) {
     User user = new User();
     user.setName(req.getParameter("name"));
     user.setPassword(req.getParameter("password"));
     return user;
   }
}
hello-world.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>hello world</title>
</head>
<body>
<form action="helloWorld" method="post">
    <label for="name">name:</label><input type="text" id="name" name="name">
    <label for="password">password:</label><input type="password" id="password" name="password">
    <input type="submit" value="submit">
    <c:if test="${error}">
        login failed
    </c:if>
</form>
</body>
</html>
hello-world-confirm.jsp
1
2
3
4
5
6
7
8
9
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>helloWorldConfirm</title>
</head>
<body>
hi,${user.name}
</body>
</html>
User.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package me.zeph.springview.demo.domain;

public class User {
  public static final String NAME = "zeph";
  public static final String PASSWORD = "123456";
  private String name;
  private String password;

   public String getName() {
      return name;
  }

   public void setName(String name) {
      this.name = name;
  }

   public String getPassword() {
      return password;
  }

   public void setPassword(String password) {
      this.password = password;
  }

   public boolean validate() {
      return NAME.equals(name) && PASSWORD.equals(password);
  }
}

总结,Model2模式已经很好的将控制逻辑,业务逻辑和显示逻辑分开,但其中也有些位置还可以进一步改进。

例如:从参数到业务模型的转换(数据绑定),视图显示技术不容易更换(View解析)。

不过,Web MVC框架替我们解决的了这些问题(流行的Web MVC框架有:Spring MVC,Struts)。

关于Spring MVC框架的使用将留在下一篇介绍。