月度归档:2011年07月

eclipse提示CreateProcess error=87错误的解决方法

当eclipse控制台报出Cannot run program “"C:\Program Files\Java\jre6\bin\javaw.exe" (in directory "D:\workspace\test"): CreateProcess error=87, ²ÎÊý´í”的错误时,可以考虑是不是因为eclipse里设置的某个环境变量路径(可通过Window->Preferences->Java->Build Path->Classpath Variables查看)太长太深。我遇到的问题是因M2_REPO这个环境变量引起的,它存储的是maven本地库的位置。

解决方法:
1、在较浅的目录新建maven本地库文件夹。例如D:/m2。
2、修改%MAVEN_HOME%/conf/settings.xml文件,修改<localRepository></localRepository>节点的内容为<localRepository>D:/m2</localRepository>。
(注:默认<localRepository></localRepository>节点是被注释掉的,本地库路径指向C:\Documents and Settings\CURRENT_USER\.m2\repository,其中CURRENT_USER为当前登录用户名。这种情况下,只需要在文件中添加<localRepository>D:/m2</localRepository>即可。)
3、将原maven本地库中的所有包拷贝到新目录D:/m2中。
4、修改eclipse中M2_REPO环境变量的值(Window->Preferences->Java->Build Path->Classpath Variables),把原M2_REPO值修改为D:/m2。
5、F5刷新工程,如果工程前还带红叉,可以执行Project->Clean...。over~

--EOF--

设计模式 —— Singleton(单例模式)

『Design Patterns』对于单例模式意图的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。它与全局变量的区别在于:单例模式除了是对全局变量的一种改进之外,更主要的是它规定了一个类只能被实例化一次。单例模式的应用很广泛,比如操作系统中的文件系统和窗口管理器。

一个经典的单例模式例程(In Java)如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Singleton 
{
    private static Singleton instance = null;
 
    protected Singleton(){}
 
    public static Singleton getInstance()
    {
        if(instance == null)
        {
            instance = new Singleton();
        }
        return instance;
    }
}

稍微解释一下上述程序:单例类中静态变量instance开始设为null,客户只能通过getInstance()方法访问这个instance。instance的初始化采用Lazy(懒惰)策略,即getInstance()方法只有在第一次被访问时才初始化instance。此外,Singleton的构造函数是protected类型的,这意味着客户无法直接实例化该类(得到一个编译错误信息),从而达到防止实例化多个对象的目的。

但是上面的经典Singleton程序有一个明显的bug,那就是无法在多线程环境下工作。假设Thread A刚好执行到第11行instance = new Singleton(),并且CPU被切到了Thread B,此时instance依旧是null,于是Thread B执行instance = new Singleton()初始化instance,当CPU重新切回Thread A之后,instance又被赋值一次,这就相当于被实例化了两次。要解决多线程调用问题,有以下2个方法:
1、避免采用Lazy策略初始化instance

1
2
3
4
5
6
7
8
9
10
11
//类定义
public class Singleton 
{
    public final static Singleton INSTANCE = new Singleton();
 
    private Singleton(){}
}
 
//客户代码
Singleton singleton = Singleton.INSTANCE;
singleton.doSomething();

Singleton类的静态成员变量INSTANCE一定会在这个类第一次被访问时创建,所以这个例程是线程安全的。

2、双重加锁检测
双重加锁检测法是指在经典的单例模式例程基础上,修改其getInstance()方法,再加一个锁判定,使其线程安全。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Singleton 
{
    private static Singleton instance = null;
 
    protected Singleton(){}
 
    public static Singleton getInstance()
    {
        if(instance == null) // 1
        {
            synchronized(Singleton.class)
            {
                if(instance == null) //2
                {
                    instance = new Singleton();
                }
            }	
        }
        return instance;
    }
}

假设Thread A执行到1处CPU切到Thread B,然后Thread B进入getInstance()执行完并返回。当CPU重新切回Thread A时,Thread A独占地运行代码块synchronized(Singleton.class){},此时,因为instance已经在Thread B中初始化,所以instance != null,所以Thread A在2处判定后不会进入if分支,避免了instance被二次实例化。

References:
1.Erich Gamma, Richard Helm, Ralph Johnson, et al. 设计模式:可复用面向对象软件的基础[M], 机械工业出版社, 2006-07.

--EOF--

SHT 1x传感器demo程序

SHT 1x是一款性价比挺高的数字温湿度传感器,它的好处坏处就不多说了,选用它的总归有理由的。关于SHT 1x传感器本身的信息详见官网。官网已经给出了这款传感器的demo程序,里面的注释也已经足够详细。本文只是对demo程序进行分段解释,并对其英文注释作个汉化,同时也把自己前段时间在项目中所学的SHT 1x传感器知识作为补充添加进去。

源代码文件可在此处下载得到。这个程序兼容所有51系列单片机,其他CPU型号可能需要作出一定的修改才能正确运行。下面就正式开始了。

1、头文件包含

1
2
3
4
#include <AT89s53.h> //当前型号CPU头文件,不过这个demo中用到它的只有P1.0和P1.1脚的定义。 
#include <intrins.h> //_nop_()函数所需头文件   
#include <math.h>   
#include <stdio.h>   //标准I/O头文件,printf()需要。

2、全局变量、结构体和宏定义

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
/* 
  定义接收传感器数字信号的变量类型,
  可以存湿度,也可以存温度。
 */
typedef union  
{ unsigned int i; 
  float f; 
} value; 
 
/* TEMP为0, HUMI为1 */
enum {TEMP,HUMI};
 
/* 
  宏定义传感器的DATA线和SCK线
  此后的代码不再硬编码,方便移植。
 */
#define	DATA   	P1_1
#define	SCK   	P1_0
 
/*
  宏定义传感器和CPU的应答信号,
  用1表示需要应答,用0表示无需应答。
  这里的1和0与实际DATA线的应答形式无关。
  DATA线用1个下降沿表示应答。
*/
#define noACK 0
#define ACK   1
 
/*
  定义SHT 1x传感器的5个命令字,每个字的具体含义见传感器手册。
*/
                            //adr  command  r/w
#define STATUS_REG_W 0x06   //000   0011    0 写状态寄存器
#define STATUS_REG_R 0x07   //000   0011    1 读状态寄存器
#define MEASURE_TEMP 0x03   //000   0001    1 温度测量
#define MEASURE_HUMI 0x05   //000   0010    1 湿度测量
#define RESET        0x1e   //000   1111    0 软复位

3、读写传感器总线(CPU提供SCK信号,将1个字节写入DATA或从DATA中读出1个字节)

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
42
43
44
45
//------------------------------------------------------------------------------
char s_write_byte(unsigned char value) 
//------------------------------------------------------------------------------ 
// 写入1个字节内容(命令字)到总线(DATA),并等待传感器确认。  
{  
  unsigned char i,error=0;   
  for (i=0x80;i>0;i/=2)       //表示执行8次for循环体内容
  { if (i & value) DATA=1;  //从高位开始,如果value某位为1,为DATA置1, 
    else DATA=0;              //某位为0,为DATA置0。   
    _nop_();                    //observe setup time 
    SCK=1;                     //让SCK输入一个时钟信号(1高1低) 
    _nop_();_nop_();_nop_();    // 持续3个_nop_()的时间使SCK为高电平   
    SCK=0; 
    _nop_();
  } 
  DATA=1;                    //释放DATA线
  _nop_();                          
  SCK=1;           //CPU输出第9个时钟,等待传感器拉底DATA信号(表示成功接收了value值)  
  error=DATA;    //以DATA线的当前逻辑电位赋值给返回状态 
          //这里可以在error=DATA前面加几个_nop_()指令,以确保传感器有足够的时间返回确认信号
  SCK=0;         
  return error;    //error=1表示DATA未被传感器确认,写失败。error=0表示写成功。
} 
 
//------------------------------------------------------------------------------ 
char s_read_byte(unsigned char ack) 
//------------------------------------------------------------------------------ 
// 从DATA中读出1个字节(命令字)。如果要求确认(ack=ACK),则在第9个时钟拉低DATA线 。 
{  
  unsigned char i,val=0; 
  DATA=1;                           //初始化DATA线。 
  for (i=0x80;i>0;i/=2)             //这个循环体与s_write_byte()不同的地方在于:
  { SCK=1;  //s_write_byte()是先把状态字(1次1位)写到DATA,再送出时钟(SCK)。
    if (DATA) val=(val | i); //而s_read_byte是先送出时钟(SCK),再从DATA中读状态字。  
    SCK=0;         
  } 
  DATA=!ack;                        //如果要求确认,则拉低DATA线。 
  _nop_();                        
  SCK=1;                          
  _nop_();_nop_();_nop_();          //保持1段时间的SCK高电平信号,使传感器有时间接收。  
  SCK=0; 
  _nop_();                               
  DATA=1;                           //释放DATA线 
  return val; 
}

4、启动传输信号(Transmission Start)

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
//-----------------------------------------------------------------------------
void s_transstart(void) 
//-----------------------------------------------------------------------------
//CPU给出一个TS信号,表示要开始向传感器发送命令字了。
//TS信号定义为:初始化DATA为1,SCK为0,
//当SCK为高电平时拉低DATA,此后SCK变低,当SCK再次为高时释放DATA。
//       _____         ________ 
// DATA:      |_______| 
//           ___     ___ 
// SCK : ___|   |___|   |______ 
{   
   DATA=1; SCK=0;                   //初始化DATA和SCK
   _nop_(); 
   SCK=1;                    //当SCK为高电平时
   _nop_(); 
   DATA=0;                    //拉低DATA
   _nop_(); 
   SCK=0;                      //SCK变低
   _nop_();_nop_();_nop_(); 
   SCK=1;                     //SCK再次变高电平
   _nop_(); 
   DATA=1;                     //释放DATA,完成TS信号     
   _nop_(); 
   SCK=0;      
}

5、传感器复位时序

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
//----------------------------------------------------------------------------- 
void s_connectionreset(void) 
//----------------------------------------------------------------------------- 
// 传感器复位时序定义:DATA保持9个SCK时钟的高电平时间,然后后面紧跟一个TS启动传输信号。 
//       _____________________________________________________         ________ 
// DATA:                                                      |_______| 
//          _    _    _    _    _    _    _    _    _        ___     ___ 
// SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______|   |___|   |______ 
{   
  unsigned char i;  
  DATA=1; SCK=0;                    //初始化DATA和SCK
  for(i=0;i<9;i++)                  //9个SCK时钟 
  { SCK=1; 
    SCK=0; 
  } 
  s_transstart();                   //发出一个TS启动传输信号。 
}
 
//----------------------------------------------------------------------------- 
char s_softreset(void) 
//----------------------------------------------------------------------------- 
// 通过向传感器发送一个命令字RESET来实现软复位,能清空状态寄存器,恢复默认值。  
{  
  unsigned char error=0;   
  s_connectionreset();              //传感器复位(不会清空状态寄存器)。 
  error+=s_write_byte(RESET);       //如果传感器正确接收,会返回0(DATA被拉低)。 
  return error;                     //如果error=1则表示传感器未正确接收。 
}

6、读写传感器的状态寄存器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//-------------------------------------------------------------------------------
char s_read_statusreg(unsigned char *p_value, unsigned char *p_checksum) 
//------------------------------------------------------------------------------- 
//根据协议从传感器分别读出1个字节的状态寄存器内容和1个字节的校验码 
{  
  unsigned char error=0; 
  s_transstart();                   //传输开始
  error=s_write_byte(STATUS_REG_R); //先向传感器发送一个“读状态寄存器”的命令字 
  *p_value=s_read_byte(ACK);//返回的第1字节表示状态寄存器内容,并需要确认(告知还要继续传输) 
  *p_checksum=s_read_byte(noACK);   //返回的第二字节表示校验码,无需确认,因为传输结束了。   
  return error;//如果error=1表示s_write_byte()失败,p_value和p_checksum值是废的 
}
 
//------------------------------------------------------------------------------- 
char s_write_statusreg(unsigned char *p_value) 
//------------------------------------------------------------------------------- 
//根据协议写一个字到状态寄存器。 
{  
  unsigned char error=0; 
  s_transstart();                   //传输开始
  error+=s_write_byte(STATUS_REG_W);//向传感器发送一个“写状态寄存器”的命令字 
  error+=s_write_byte(*p_value);    //向传感器发送一个状态寄存器值 
  return error; //如果error>=1表示上面的两个s_write_byte()至少1个执行失败,函数执行失败。 
}

7、温湿度测量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//---------------------------------------------------------------------------------- 
char s_measure(unsigned char *p_value, unsigned char *p_checksum, unsigned char mode) 
//---------------------------------------------------------------------------------- 
// 测量温湿度。 
{  
  unsigned char error=0; 
  unsigned int i; 
 
  s_transstart();                   //启动传输 
  switch(mode){                     //表示当前是测温度还是测湿度。 
    case TEMP : error+=s_write_byte(MEASURE_TEMP); break;//如果是测温度,就发测温度命令
    case HUMI : error+=s_write_byte(MEASURE_HUMI); break;//如果是测湿度,就发测湿度命令 
    default     : break;   
  } 
  for (i=0;i<65535;i++) if(DATA==0) break; //传感器测量好之后会拉低DATA,CPU结束等待。 
  if(DATA) error+=1; // 如果DATA还是高电平,表示上个循环不是break出来的,传感器未返回成功。 
  *(p_value)  =s_read_byte(ACK);    //从总线读测量结果的高字节。
  *(p_value+1)=s_read_byte(ACK);    //从总线读测量结果的低字节。
  *p_checksum =s_read_byte(noACK);  //读校验值 
  return error; //error>=1表示返回错误。
}

8、串口初始化

1
2
3
4
5
6
7
8
9
10
//-----------------------------------------------------------------------------
void init_uart() 
//-----------------------------------------------------------------------------
//这段程序,包括前面的stdio.h头文件,均不是必须,
//只是因为main函数里用到了printf()函数,所以才要初始化串口。
{SCON  = 0x52; //设置串口控制寄存器:串口1工作方式1(8位UART,波特率可变)    
 TMOD  = 0x20; //设置定时器工作模式寄存器:定时器1工作模式为8位自动重装定时器    
 TCON  = 0x69;//设置定时器控制寄存器:启动定时器1    
 TH1   = 0xfd;// 产生9600 bps @ 11.059 MHz波特率所需的初始值   
}

9、计算湿度和温度

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
42
43
44
45
46
47
//------------------------------------------------------------------------------ 
void calc_sth11(float *p_humidity ,float *p_temperature) 
//------------------------------------------------------------------------------ 
// 计算温度[°C]和湿度[%RH]
//s_measure()函数返回的只是2个字节的原始数据(raw data),要得到正确的温湿度值还需要转化。
//这里计算的是当传感器状态寄存器最低位为0的情况,即12位湿度和14位温度的情况。
//温湿度计算公式和补偿公式详见传感器的数据手册。  
// input :  humi [Ticks] (12 bit)  
//          temp [Ticks] (14 bit) 
// output:  humi [%RH] 
//          temp [°C] 
{
  /* C1,C2,C3,T1,T2是计算湿度所需的参数,如果是8位湿度,这些值会变。 */
  const float C1=-2.0468;           // 12位湿度的参数 
  const float C2=+0.0367;           // 12位湿度的参数 
  const float C3=-0.0000015955;     // 12位湿度的参数 
  const float T1=+0.01;             //12位湿度的参数 
  const float T2=+0.00008;          //12位湿度的参数  
 
  float rh=*p_humidity;             // rh: s_measure()函数返回的湿度值  12位
  float t=*p_temperature;           // t: s_measure()函数返回的温度值  14位
  float rh_lin;                     // rh_lin: 相对湿度值,不是最终的。 
  float rh_true;                    // rh_true: 考虑的温度补偿的最终湿度值 
  float t_C;                        // t_C   :  最终温度值
 
  t_C=t*0.01 - 40.1;              //温度值计算
  rh_lin=C3*rh*rh + C2*rh + C1;     //相对湿度计算 
  rh_true=(t_C-25)*(T1+T2*rh)+rh_lin;   //根据温度补偿,计算最终湿度值 
  if(rh_true>100)rh_true=100;       //对于超量程的湿度值,要设定成最大量程和最小量程 
  if(rh_true<0.1)rh_true=0.1;       
 
  *p_temperature=t_C;               //返回温度值 [°C] 
  *p_humidity=rh_true;              //返回湿度值[%RH] 
} 
 
//-------------------------------------------------------------------- 
float calc_dewpoint(float h,float t) 
//-------------------------------------------------------------------- 
// 计算露点 (露点的概念、原理和计算公式详见相关资料)
// input:  湿度 [%RH], 温度[°C] 
// output:  露点 [°C] 
{ float k,dew_point ; 
 
  k = (log10(h)-2)/0.4343 + (17.62*t)/(243.12+t); 
  dew_point = 243.12*k/(17.62-k); 
  return dew_point; 
}

10、主程序

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
//---------------------------------------------------------------------------------- 
void main() 
//---------------------------------------------------------------------------------- 
// 展示了以上函数调用的具体步骤: 
// 1. 传感器复位s_connectionreset()  
// 2. 测量温湿度s_measure()
// 3. 计算温湿度calc_sth11()
// 4. 计算露点calc_dewpoint() 
// 5. 打印温湿度和露点printf()   
 
{ value humi_val,temp_val; 
  float dew_point; 
  unsigned char error,checksum; 
  unsigned int i; 
 
  init_uart(); //初始化串口
  s_connectionreset(); //传感器复位
  while(1) //不停循环,因为单片机的main函数无返回(返回单片机就不工作了)。
  { error=0; 
    error+=s_measure((unsigned char*) &humi_val.i,&checksum,HUMI);//测量湿度
    error+=s_measure((unsigned char*) &temp_val.i,&checksum,TEMP);//测量温度
    if(error!=0) s_connectionreset();//如果测量温湿度出错,则重新复位传感器。 
    else 
    { humi_val.f=(float)humi_val.i;//将整数强制转换成浮点数,
      temp_val.f=(float)temp_val.i;//强制转换无需考虑整数和浮点数在寄存器中存储方式。
      calc_sth11(&humi_val.f,&temp_val.f);//计算温湿度
      dew_point=calc_dewpoint(humi_val.f,temp_val.f); //计算露点
      //打印输出值
      printf("temp:%5.1fC humi:%5.1f%% dew point:%5.1fC\n",temp_val.f,humi_val.f,dew_point); 
    } 
   for (i=0;i<40000;i++); //延迟一小会儿,使得传感器不至于持续工作而发热,影响测量结果。 
  } 
}

以上就是SHT 1x系列传感器demo程序的分段解释,相对也比较简单,只要熟读datasheet,搞清楚它的工作原理,理解和编写起来没什么大问题,demo中的main函数只是调用了几个最常用的测量函数,还有比如读写状态寄存器和软复位程序均没有用到,这些函数的调用方法也类似,没什么不同。

--EOF--

Blogrss设计思路

Blogrss源码包的目录结构如下所示:

1
2
3
4
5
6
7
8
9
10
11
blogrss
   ├─manifest.json
   ├─popup.html
   ├─popup.js
   ├─background.html
   ├─main.css
   ├─icon_19_19.png
   ├─icon_32_32.png
   ├─icon_64_64.png
   ├─icon_128_128.png
   └─logo.png

根据名称很容易看出:manifest.json为定义插件的元数据文件。popup.html为弹窗文件,popup.js是popup.html中调用的javascript函数,background.html是后台运行文件,剩下的几个文件都算是素材文件。

在popup.html的<body>标签里可以设置插件弹窗的大小,超过设定值自动出现滚动条。

1
2
3
4
5
<body style="width: 500px; height: 200px; font-size: 12px;">
	<script type="text/javascript">
		display();
	</script>
</body>

弹窗中内容由popup.js的display()函数给出,如下。

1
2
3
4
5
6
7
8
9
10
function display()
{
	var bgpage = chrome.extension.getBackgroundPage();
	document.open();
	document.write(bgpage.getXMLContent());
	document.close();
	bgpage.remain = 0;
	localStorage.setItem('remain', String(0));
	chrome.browserAction.setBadgeText({text: String(0)});
}

首先由于Blogrss会每隔15分钟读取一下rss源,而popup.html的生命周期决定了不可能把轮询代码写在它里面,只能写在后台运行文件background.html里。var bgpage = chrome.extension.getBackgroundPage()表示取得后台页面,调用它的getXMLContent()方法获得要展示的html内容,然后通过document.write()写入popup.html页面。remain是显示在插件右下角的数字,表示新内容的条数,因为这个值必须在浏览器重启之后依然有效,因此这里修改完后将它存人localStorage(关于localStorage参见『Chrome插件开发学习笔记』),方便在适当时候再取出。

setTimeout(func, milliseconds)函数能让func函数在milliseconds微秒之后执行。为了达到每隔15分钟读取rss源一次,我们需要在功能函数最后重新调用setTimeout()一次,使得自己在15分钟后能再执行一次,如下:

1
2
3
4
5
6
7
setTimeout(refreshinback, 2000);
function refreshinback()
{
	getXMLContent();
	chrome.browserAction.setBadgeText({text: String(remain)}); 
	setTimeout(refreshinback, 900000); //15min
}

在refreshinback函数体中,调用getXMLContent()以获得最新的网站内容。getXMLContent()仅仅是将loadXmlFile()函数返回的xml文档按RSS2.0标准解析,然后通过getDataByid()重新封装。最后的返回值rt_html中就是解析完成的html代码,可直接通过document.write()输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function getXMLContent(){
	xmlObj=loadXmlFile("http://fengchj.com/?feed=rss2");
	var items=xmlObj.getElementsByTagName("item").length;
 
	rt_html = "";
	for(i=0;i<items;i++){
		getDataByid(i);
	}
 
//	......
//	......
//	......
 
	return rt_html;
}

Blogrss的源代码已上传至google code相应页面,有兴趣的朋友可以到这里checkout后查看。

--EOF--

Chrome插件开发学习笔记

Chrome插件开发比想象中要简单一些,它有固定的模板,就像八股文,因此只要理清程序的执行逻辑,就能快速开发出一个实用的浏览器插件。

一般来讲,Chrome插件至少包含2个文件:

1、manifest.json。这是一个json格式的配置文件,用于声明插件的基本信息以及插件目录下每个资源的作用。这里有manifest.json文件格式的官方说明。
2、popup.html。这个静态页面所展示的内容就是我们点击浏览器插件图标后弹出窗口中显示的内容。由于Chrome插件主要的开发语言是javascript,因此,这个文件可以并且只能用静态的html或动态的javascript语言编写。

只需以上2个文件以及一些logo图标就能写出一个简单的Chrome插件了。这篇文章里有一个时钟的例子,适合初学者了解Chrome插件开发的整个流程。

此外,功能稍强一点的插件还需用到background.html文件,这是一个后台运行的文件,书写规则与popup.html一样,仅允许html+javascript。它们不同的地方在于:popup.html页面只有我们点击了插件图标后代码才会执行一次,而background.html文件会在浏览器加载插件那一刻开始运行,而且常驻在内存里,直到浏览器关闭或disable插件代码才结束运行。一些定时刷新或定时检查功能,例如Google Mail Checker,就是通过在background.html页面里写入定时检测代码,实现对邮箱的定时访问。要使用background.html需要在manifest.json里将其与background_page参数相关联。由于background.html页面中代码的生命周期很长,因此如果不是必须要用就尽量少用。打开Chrome的任务管理器,可以看到每个使用了background页面的插件的cpu和内存消耗量,其中一些甚至存在内存泄漏情况,运行时间越长,占用内存越大,会拖累浏览器的运行速度。background.html页面另外一个重要功能是能够提交跨域ajax请求。

要想在其他页面里访问background.html中的定义的全局变量和方法,可以调用chrome.extension.getBackgroundPage()函数来实现。例如:

1
2
3
var bgpage = chrome.extension.getBackgroundPage();
bgpage.var1 = "test"; //调用background.html页面中的变量,并为它赋值。
bgpage.test(); //调用background.html页面中的test()方法。

background.html的生命周期虽然比popup.html长,但是当浏览器关闭时,background.html中的变量值就丢失了,要想永久保存一些变量值,使得浏览器重启之后该值仍然有效,就要用到localStorage,这实际上是html5标准的本地存储功能。可以将它理解成一个小型注册表,存储的是键值对,它有3个常用接口,用于读、写、删除对应键的值,分别是localStorage.getItem("key")、localStorage.setItem("key", value)、localStorage.removeItem("key")。打个不恰当的比喻,如果background.html里定义的变量作用域是application的话,那么localStorage的作用域就是cookie。

Chrome允许在插件的右下角显示最多4个字符的标记(Badge),用于提示一些重要信息,比如Google Mail Checker中提示的新邮件数目、Xmark提示当前书签处理状态等。它们都是通过chrome.browserAction.setBadgeText({text: string})这个API来实现的。只要在background.html里用setTimeout(function_name, time)设定好定时执行的程序,定期检查即可。

--EOF--