咖啡伴侣

呆在上海
posts - 163, comments - 156, trackbacks - 0, articles - 2

2008年6月17日

package main

import (
    "fmt"
    "time"
)

var ch chan int = make(chan int, 1)

func main() {
    go aaa()

    select {
    case <-ch: //拿到锁
        fmt.Println("call")
    case <-time.After(5 * time.Second): //超时5s
        fmt.Println("5 sec call")
    }
}

func aaa() {
    time.Sleep(time.Second * 3)
    ch <- 1
}

posted @ 2013-12-24 13:03 oathleo 阅读(7275) | 评论 (0)编辑 收藏

conn, err = ln.Accept()
go handleConnection(conn)
看到这里我曾经有个疑问,为什么不是  handleConnection(&conn) ?

下面这个例子解释这个问题

package main

import (
    "fmt"
)

type Interface interface {
    say() string
}

type Object struct {
}

func (this *Object) say() string {
    return "hello"
}

func do(i Interface) string {
    return i.say()
}

func main() {
    o := Object{}
    fmt.Println(do(&o))
    fmt.Printf("CCCCCCCCCCC:%T", o)
}

函数的参数以接口定义,编译器会自己判断参数是对象还是对象的指针
比如,say是指针上的方法,所以do只接受Object的指针做参数,do(o)是编译不过的

所以看到库里接口做参数类型定义的时候,可以简单认为,这个接口肯定是个对象指针(虽然也可以用对象,单估计没有哪个类库会用)

例如:
conn, err = ln.Accept()
go handleConnection(conn)

这里conn是个接口,不需要 go handleConnection(&conn)

posted @ 2013-12-22 12:45 oathleo 阅读(4381) | 评论 (1)编辑 收藏

package main

import (
    "fmt"
    "mag/common"
    "time"
)

func main() {
    c := make(chan bool, 10)

    tt := common.GetTodayGivenTime("161300")
    dd := common.SinceNow(tt)
    time.AfterFunc(dd, func() { //非阻塞
        
//后续每24小时建立目录
        ticker24h := time.NewTicker(5 * time.Second)
        for {
            select {
            case <-ticker24h.C:
                fmt.Println("print")
            }
        }
    })

    <-c
}

posted @ 2013-12-19 16:15 oathleo 阅读(5358) | 评论 (0)编辑 收藏

声明:
源slice= src
添加slice = app
结果slice=tar
append时
len tar === len src +   len app
1)如果len(src) + len(app) <= cap(src)    cap tar  =   cap(src)
2)否则 
      a) len(src) + len(app) > 2* cap(src)     cap tar  =   len(src) + len(app)
      b) cap(src) < len(src) + len(app) <= 2* cap(src)    cap tar = 2* cap(src)
    data := make([]int, 10, 20)
    data[0] = 1
    data[1] = 2

    dataappend := make([]int, 12, 30)//修改这个len 
    dataappend[0] = 1
    dataappend[1] = 2

    result := append(data, dataappend)

    result[0] = 99
    result[11] = 98

    fmt.Println("length:", len(data), "cap:", cap(data), ":", data)
    fmt.Println("result length:", len(result), "cap:", cap(result), ":", result)
    fmt.Println("length:", len(dataappend), "cap:", cap(dataappend), ":", dataappend)

posted @ 2013-11-20 18:48 oathleo 阅读(5245) | 评论 (1)编辑 收藏

1.slice1:= slice[0:2]
引用,非复制,所以任何对slice1或slice的修改都会影响对方
data := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
data1 := data[0:2]
data1[0] = 99
fmt.Println(data1)
fmt.Println(data)
[99 2]
[99 2 3 4 5 6 7 8 9 0]
2.append
append 比较特殊
声明:
源slice= src
添加slice = app
结果slice=tar
1)如果len(src) + len(app) <= cap(src)  src和tar 是指向同一数据引用 ,即修改src或tar,会影响对方
2)否则 tar 是copy的方式 src + app ,即修改src或tar,不会影响对方
无论哪种情况不会影响app,因为app都会用copy的方式进入tar
 
func test2() {
data := make([]int, 10, 20)
data[0] = 1
data[1] = 2
dataappend := make([]int, 10, 20)//len <=10 则  result[0] = 99 会 影响源Slice
dataappend[0] = 1
dataappend[1] = 2
result := append(data, dataappend...)
result[0] = 99
result[11] = 98
fmt.Println("length:", len(data), ":", data)
fmt.Println("length:", len(result), ":", result)
fmt.Println("length:", len(dataappend), ":", dataappend)
}

posted @ 2013-11-20 18:46 oathleo 阅读(6659) | 评论 (1)编辑 收藏

index := bytes.IndexByte(buf_PN, 0)
rbyf_pn := buf_PN[0:index]

posted @ 2013-11-19 10:16 oathleo 阅读(8980) | 评论 (0)编辑 收藏

c := exec.Command("taskkill.exe", "/f", "/im", "test.exe")
err := c.Start()

posted @ 2013-11-15 14:07 oathleo 阅读(6739) | 评论 (4)编辑 收藏

s2 := append(s1, *)

切片s1上记录的切片信息复制给s2,

1.如果s1指向的底层array长度不够,append的过程会发生如下操作:内存中不仅新开辟一块区域存储append后的切片信息,而且需要新开辟一块区域存储底层array(复制原来的array至这块新array中),最后再append新数据进新array中,这样,s2指向新array。

2.如果s1指向的底层array长度够,
s2和s1指向同一个array,append的结果是内存中新开辟一个区域存储新切片信息。

开辟一块区域存储底层array 使用下面的策略:
1.如果 增加的 len < s的cap 则 新s的cap*2
2.如果 增加的 len > s的cap 则 新s的cap = 老cap + 增加数据的 len

posted @ 2013-11-05 16:39 oathleo 阅读(4510) | 评论 (0)编辑 收藏


 // (A)
time.AfterFunc(5 * time.Minute, func() {
    fmt.Printf("expired")
}

// (B) create a Timer object
timer := time.NewTimer(5 * time.Minute)
<-timer.C
fmt.Printf("expired")

// (C) time.After() returns timer.C internally
<-time.After(5 * time.Minute)
fmt.Printf("expired")

posted @ 2013-10-10 15:07 oathleo 阅读(1659) | 评论 (0)编辑 收藏

对亍非缓冲通道,“从通道接收数据”的操作
一定会在 “向通道发送数据”的操作完成前发生。

package main

import (
    "fmt"
)

var c = make(chan int)
var str string

func ready() {
    str = "abc"
    fmt.Println("ready1")
    <-c //get
    fmt.Println("ready2")
}

func main() {
    go ready()
    c <- 1 //put
    fmt.Println(str)
}

ready1
ready2
abc

posted @ 2013-10-10 10:56 oathleo 阅读(1550) | 评论 (0)编辑 收藏

new(T) 分配了零值填充的T
类型的内存空间,并且返回其地址,一个*T 类型的值。用Go 的术语说,它返回了一个
指针,指向新分配的类型T 的零值。有一点非常重要:
new 返回指针。

内建函数make(T, args) 与new(T) 有着不同的功能。它只能创建slice,map
和channel,并且返回一个有初始值(非零)的T 类型,而不是*T。本质来讲,导致这
三个类型有所不同的原因是指向数据结构的引用在使用前必须被初始化。

T{name:"aaa",age:11}
返回 T类型 而不是*T

posted @ 2013-10-08 10:49 oathleo 阅读(429) | 评论 (0)编辑 收藏

接着上回,对象序列化和反序的效率已经很高,试试原生数据的效率

先上代码
package main

import (
    "fmt"
    "math/rand"
    "opbuf"
    "time"
)

type RTValue struct {
    Time   int32
    Status int16
    Value  float32
}

func main() {

    size := 1000000
    col := make([]RTValue, size)
    for i := 0; i < size; i++ {
        col[i] = RTValue{Time: int32(i), Status: int16(i), Value: rand.Float32()}
    }

    fmt.Println("send data:", col[size-1])
    var opbuff *opbuf.OPBuffer = opbuf.NewOPBuffer()
    start := time.Now().UnixNano()
    for i := 0; i < size; i++ {
        //        opbuff.PutByte(col[i].Data)
        opbuff.PutInt32(col[i].Time)
        opbuff.PutInt16(col[i].Status)
        opbuff.PutFloat32(col[i].Value)
    }
    fmt.Println("send cost:", (time.Now().UnixNano()-start)/1000000)

    opbuff.Flush()

    start = time.Now().UnixNano()
    for i := 0; i < size; i++ {
        col[i].Time,_ = opbuff.GetInt32()
        col[i].Status,_ = opbuff.GetInt16()
        col[i].Value,_ = opbuff.GetFloat32()
    }
    fmt.Println("rev cost:", (time.Now().UnixNano()-start)/1000000)
    fmt.Println("rev data:", col[size-1])

}
123

Go原生代码性能:
total record: 1000000
send data: {999999 16959 0.69153386}
send cost: 93
rev cost: 61
rev data: {999999 16959 0.69153386}
 
结论:
1.不管什么语言,大批量同类型数据的传输,原生性能还是比第三方序列化 效率高很多
2.C++ 使用memcpy put 原始类型,效率还是比go高很多
C++原生代码性能:
total record 1000000
time pack 11 ms
time unpack 57 ms
 
 

posted @ 2013-09-29 09:57 oathleo 阅读(1159) | 评论 (0)编辑 收藏

模拟测试1,000, 000条数据 每条10个字节  也就是10M不到的 数据(高度结构化的数据)
过程
1.对象序列化为 byte
2.byte反序为对象
3.gzip压缩byte

测试语言go
测试方案: raw byte,json ,bson, msgpack (protostuff需要先做对象配置文件,比较麻烦,通常认为和msgpack性能相当 )
结果:msgpack 胜出


大小
gzip压缩后大小
对象到byte耗时
byte到对象耗时
raw 10000000
6573252(65%) 未测试
未测试
json
47515988 7919511 (17%) 3248ms 5280ms
bson
49888910 9506965 (19%)
3863ms 6235ms
msgpack
29934223 7448484 2046ms 3113ms


raw data: 1000000
raw data gzip compress: 6573252 //gzip压缩后大小

start: 1000000
Marshal cost: 3248  //json 序列化耗时
json string: 47515988 
json byte: 47515988  //二进制数组大小
Unmarshal cost: 5280  //json 反序列化耗时
test data: {1 100 0.9405091}
json gzip compress: 7919511 //gzip压缩后大小

start
Marshal cost: 3863
bson byte: 49888910
Unmarshal cost: 6235
test data: {1 100 0.9405091}
bson gzip compress: 9506965


start: 1000000
Marshal cost: 2046
msgpack: 29934223
Unmarshal cost: 3113
test data: {1 100 0.9405091}
msgpack gzip compress: 7448484

posted @ 2013-09-29 09:52 oathleo 阅读(3064) | 评论 (0)编辑 收藏

(本文包括章节:1、由来,2、算法简单回顾,3、演习道具,4、演习,5、算法提出者Leslie的八卦。hoho)

1、由来:

刘备接受了诸葛亮的提议,决定将paxos算法的思想应用到蜀帝国的决策机制上。然而,玄德生性谨慎,决定先行试点,实践下可行性。孔明提议,由蜀国五大肌肉男:关羽、张飞、赵云、马超、黄忠,做为决策者,而廖化、周仓、魏延分别无序的提出关于同一件事的水火不容的三个提案,孔明坚信:即使脑残者使用了paxos算法,也不会出现冲突的政令不一情况。paxos算法理论以及刘备是怎么被孔明忽悠的部分,同学们可以参考上篇《paxos分布式一致性算法--讲述诸葛亮的反穿越》:http://blog.csdn.net/russell_tao/article/details/7244530


闲话少叙,书接上文。

为了少打点字,刘备与诸葛亮俩玻璃不再以对话形式出现了。他们设置了五个官署(五虎将办公地,相当于Server),三个提案点(周仓等三人,发起提案时的办公地。相当于Client),当然都不在一起,信使们从提案点到官署传递信息的话,正常情况下需要半个小时,也就是30分钟。这次演习,哥俩不关注学习情况,所以paxos第三段就不在演习内容里了。诸葛亮为廖化、周他、魏延对于事件e准备了三个自相矛盾的提案,我们分别用p1、p2和p3代替吧。先行说明提案:


事件e(也就是本次paxos实例):蜀国今后的发展路线

提案p1:学习红色锤子镰刀,走激进主义,一切发展按照计划进行,小民们凭票消费,银子多了也没用,集中力量办大事,崇尚国家垄断主义。

提案p2:学习自由联盟,走自由主义,宁失去效率也不失去公正,发展民营经济为先,民主、法制、新闻自由,通过这种公正来激发社会的整体创造力。

提案p3:坚持孔孟之道,走保守主义,兼顾黄老之学,坚信中学为体、西学为用,国体不可大改,走有大汉国情的老路让别人说去吧。


2、算法简单回顾

我们再简单回顾下提案者和作为决策者的五虎将行动准则,共有六步,书记官(暂让五虎将兼职)负责记录下通过的提案p(通过了就叫法令了),这样,我们用1a,1b,2a,2b,3a,3c来表述全部的六步。(这六步就是三段式提交了,这在上篇《paxos分布式一致性算法--讲述诸葛亮的反穿越》里讲过,不再复述。)

魏延、廖化、周仓:

1a,作为提案者,首先向刘备要到个编号,搞清楚自己对事件e的态度。记录下当前时间,接下来向五虎将的多数派(3个或以上)发送事件+编号。

2a,此时开始处理五虎将的回应,这就有多种情况了。收到明确拒绝就得放弃!检查沙漏,如果到达时间限制了,还没有足够的多数派回应,那么就试着给五虎将的其他人再发送提案看看。如果收到了足够的五虎将里多数派的回应,那么,确定在2a这步里,如果要提案,到底提哪个提议?是自己现在要提的提案?

3a,提案者如果收到足够的五虎将多数派回应通过,则记录提案为通过的政策法令,同时通知所有书记官,也就是兼职的五虎将,把法令记录到羊皮纸上来。

五虎将:

1b,作为决策者,也需要沙漏,主要用于2b步骤后批准政策法令后,给自己设定个超时时间,若第三步信使没有过来,则超时后自动把提案变成政策法令记录到羊皮纸上。1b这个步骤是收到了信使的消息,来自于1a步骤里的提案者。收到事件e和编号N。五虎将这时将有可能出现三个动作:拒绝、通过以及第三个复杂点的动作,虽然通过但告诉魏延廖化,哥曾经批准过某提案了。(三种条件的达成请参考上篇文章《paxos分布式一致性算法--讲述诸葛亮的反穿越》)

2b,与1b步骤相同,唯一不一样的是,如果决定批准某个提案,必须先把该提案和编号记录到羊皮纸的背面。(羊皮纸的详细用途参见演习前提)

3b,记录法案到羊皮纸的正面上。(本步骤不在下面演习中出现)


3、演习道具

先解释下我们用到的道具吧。

羊皮纸(相当于硬盘):其正面记录真正通过的法令,背面相当于永久有效的草纸,背面记录一个三元组(S,V,Sh),S表示上次批准的提案编号,V表示上次批准的提案,Sh表示处理过的最大提案编号。(羊皮纸丢掉后的效果在演习结束后说明)

草纸:与羊皮纸背面相同,记录三元组。唯一不同的是,草纸容易丢失。

沙漏:记录时间。我们简单的认为,任何两个地方一次通讯时间为30分钟。所以,如果我们从提案者那出发,信使到五虎将再回来,我们认为一个小时足矣(忽略五虎将或者提案者的处理时间)。


下面的演习中,只有消息的丢失,实际上对于消息的重发和延迟,也不会有任何问题。只是对五虎将的缺席,需要做说明。如果五虎将的羊皮纸丢失,是不能直接再次加入进五人决策团的,必须学习到最新的状态。没丢羊皮纸,则可以随时加入进来。

书记官记录法令中的不一致情况这里不加讨论。


为了方便在图表中表示,我们先给五虎将五个字母编号:关羽a,张飞b,赵云c,马超d,黄忠e。

三种颜色表示不同的提案者:黄色表示廖化,蓝色表示周仓,红色表示魏延。


下面这幅图,表示不同的时间点,五虎将和三个提案者当时的状态。

->表示第一步预提案。包括1a和1b两步。

-->表示第二步提交提案,包括2a和2b。

五虎将记录的(s,v,sh)表示的三元组上面讲过了。法令项下面对应的是提案者魏、廖、周三人的状态。(wait)表示刚发出提案,1小时内等待返回呢。

e is drop表示发送给e黄忠的提案消息丢失了。

好了,可以往下看了。


4、演习

先放图,解释在下面。



详细说明上图:

8:30分上班了,红色周仓同学首先向关羽、赵云、黄忠三人发出了提案p1,编号为100,周仓开始等返回,预计9:30分时能收到三位的返回。我们假定,发给黄忠的信使出门就被孔明的跑车撞了。孔明闯祸后老实了,以下,不再出现信使失误事件了。

8:40分,崇尚民主的廖化同学向关羽、张飞、黄忠三人发出了编号为101的提案p2,预计9:40分收到返回的信使。

8:50分,喜欢孔孟的魏延同学向赵云、马超、黄忠三人发出了编号为110(魏延就是搞到大编号了啊)的提案p3,预计9:50收到返回的信使。

9:00整,周仓的提案p1到了关羽、赵云手里(黄忠没收到),两人无条件接受,记录(100,p1,100),承诺编号低于100的提案我可不会再处理了,然后两个信使开始返回。

9:10分,廖化编号为101的提案p2到了关羽、张飞、黄忠之手,张飞、黄忠哥俩从没收过事件e的提案,毫无疑问记为(101,p2,101),让信使回复接受。关羽则不然,红脸兄在10分钟前收到了周仓的编号为100的p1提案。所以,按规则办,关羽改自己的记录为(100,p1,101),让信使给廖化回复:你的编号101比较大,我同意你继续,不过我之前同意过一个编号为100的提案p1,请注意哦。

9:20分,魏延的p3提案到了赵云、马超、黄忠三人之手,马超第一次收到提案,记为(110,p3,110),回复批准。赵云和黄忠则不同,赵云收到过周仓的p1提案,这时要比提案编号了,魏延的110大于周仓的100,于是赵云记为(100,p1,110),告诉信使:我通过了,我承诺编号小于110的我不会处理,同时,我曾经批准过编号为100的提案p1。同理,黄忠记为(101,p2,110),也告诉信使:我曾经批准过编号为101的提案p2。

9:30分,周仓同学检测返回的信使了,关羽和赵云都返回批准,但是黄忠没有返回。因为必须N/2+1,也就是大多数人批准才行,所以,周仓向张飞发出提案p1。

9:40分,廖化收到了来自关羽、张飞、黄忠的回复,三人皆表示同意,但关羽表示:关某曾收到过编号100的p1提案。所以按照规则,廖化此时不能坚持自己原来的提案p2,而要改成关羽返回的提案p1,然后发起提交皆段,同样是让信使带给关羽、张飞、黄忠三人,我们用->>(a,b,e)表示。

9:50分,魏延收到了赵云、马超、黄忠三人在9:20分的答复,三人都同意了,但回答各不相同。马超没有多话,赵云说我曾收到过编号为100的p1提案,黄忠说我曾经收到过编号为101的p2提案。于是,魏延根据规则,不再提自己原来的p3提案,改为101编号对应的提案p2。接着,魏延开始向这三人发出提交请求,编号为110的提案p2。

10:00整,张飞收到了9:30分周仓补发的编号为100的提案p1,这之前,张飞在9:10分时曾经批准过来自廖化的提案p2,编号是101。所以,张飞在9:10时就已经承诺了,以后决不再处理编号小于101的提案。于是,张飞大吼一声:我拒绝。当然信使将会在10:30才能把消息带给周仓。

10:10分,关羽、张飞、黄忠收到了来自廖化于9:40分发出的(101,p1)提案,关羽和张飞都发现自己可以批准,记录到羊皮纸的背面,同时告诉信使:告诉廖化P1提案我批准了,我承诺编号小于101的提案不予理会。黄忠则不然,老将黄忠在9:20分时收到过魏延编号为110的提案,那时他批准了,意味着,所有小于110的提案他都会拒绝掉。这次廖化的提案才101,当然被拒绝掉了。三人的回复将于10:40会到达廖化处。

10:20分,魏延编号为110的P2提案到达赵云、马超、黄忠,三人没有疑问,毕竟110编号最大,都表示批准,并记录(110,p2,110)到各自的羊皮纸背面,回复信使通过。

10:30分,周仓收到了他在9:30分发给张飞的回复,张飞在10:00拒绝了,所以周仓这个提案就此作废。

10:40分,廖化收到了10:10来自关羽、张飞、黄忠的回复,关张二人批准,然而老黄忠明确表示拒绝,于是这次编号101的提案作废。

10:50分,魏延收到了赵云、马超、黄忠的回复,三人都表示批准,于是编号为110的提案p2最终作为法令记录下来(之后的3b学习过程略过),从此以后,蜀国的路线被确立为走民主路线,许多年后,蜀国统一了银河系。完。


以上任何步骤,大家可以任意制造难度,例如让同一个信使重复投递消息,或者延迟一天后消息到达某虎将处。或者让某个虎将正常如厕,而后正常归来。大家会发现,一致性是可以达到的,无论怎样,对于同一个事件e,互相冲突的三个法案:p1,p1,p3,一定只有一个可以达成。

对于任一虎将兄的挂掉,我们要分情况。如果是去大便,那么他的羊皮纸是不能丢的。大便完了,可以正常回到自己的官署办公。但是如果把羊皮纸丢了,那就不能立刻加入,必须向所有其他人学习,把失落的过程都学到,才能正常加入。这点至关重要,就是说,只要硬盘不坏,随时SERVER重启都能加入。硬盘一坏,对不起,学习完了才能继续办公。


5、后记---Leslie的八卦:

paxos算法是解决分布式服务数据一致性的终极算法,google的基础服务chubby(GFS的基础服务)的开发者说, “there is only one consensus(一致性) protocol, and that’s Paxos”。Microsoft有fast paxos论文,yahoo的zookeeper也用了paxos算法。可见,paxos是解决完全的分布式服务(无单点)间数据一致性的最好方法。但是paxos比较复杂,特别是网上的中文资料里少有能说得清楚的(主要是太多paxos变种算法了,掺合到一起搅得人头大),例如中文wiki上的paxos解释,光看这个是不可能搞懂paxos的。


paxos算法由Leslie Lamport在1990年提出,毫无疑问,paxos想解决的就是分布式环境下(server会挂掉,通讯协议不可靠,消息可能延迟、丢失、重发)如何保持数据一致性的问题。Leslie Lamport同学在1982年提出的“拜占庭将军”问题上尝到了甜头,这也是个分布式环境下的一致性问题,Leslie通过类比的方式,伪造了“拜占庭将军”历史,通过这种简单的类比成功的简化了复杂的分布式环境,效果非常好。于是在1990年Leslie同样用类比的方式提出了paxos算法,该问题跟“拜占庭将军”问题的区别是,“拜占庭将军”允许有叛徒,也就是允许伪造消息(默许被黑客攻击),而paxos则不允许消息被伪造。

Leslie很有幽默感的把论文写成一个考古发现,至始至终都在虚构他的“考古发现”。他说在考古中发现了失落的文明:希腊的paxos小岛。这里的议员通过邮递员传递消息,议会中一个议员提出法案,多数议员批准后法案获得通过。当然无论议员还是邮递员,都是兼职的,他们不可靠,随时可能走人,呵,典型的分布式环境,server可以挂,消息可以丢。Leslie根据考古文献反推出了paxos议会如何搞定法案一致性的问题。

发表论文时,Leslie一直用这种语气在写论文,于是《ACM Transactions on Computer Systems》编辑们认为太荒诞了,不能从头到尾虚构故事吧?毕竟是严谨的科学杂志,于是打回。Leslie同学身为牛人,坚持自己的看法,同时认为编辑们没有幽默感,拒绝修改。时间流逝,一晃九年过去,九年后有团队根据该论文开发出一个paxos实现,终于,编辑们低头了,允许发布Leslie的论文,但还是加了段编者著,在其中表示Leslie其实是个热爱计算机技术的考古学家!也算稍事解嘲。


写这两篇文章,我也试了下借喻的手段,用我们熟悉的三国人物,看看能否讲清楚paxos。其实paxos的算法本身算不得很复杂,但如果想讲清楚在各种异常情形下paxos算法的表现,给大家带来的明确的直观感受:paxos确实能解决一致性问题,这就不容易了。所以篇幅所限,只写了丢失一个消息的情况。不过大家如果从头看到这,应该可以简单的任意推导出其他异常吧?


最后,上面说的只是算法机制,如果需要了解现有的各种产品实现,最方便的还是看zookeeper源码,毕竟是开源的,例如去:http://zookeeper.apache.org/doc/r3.3.2/zookeeperOver.html,可以看下概述。淘宝开发团队有许多关于zookeeper实现的文章,到网上搜下就能看到。

对google的chubby实现,因为不是开源的,只有篇论文可以看:http://static.googleusercontent.com/external_content/untrusted_dlcp/research.google.com/zh-CN/us/archive/chubby-osdi06.pdf

posted @ 2013-09-28 10:16 oathleo 阅读(648) | 评论 (0)编辑 收藏

一日,诸葛亮找到刘备,突然献上一曲《独角戏》,而后放声大哭。刘备正沉醉于新曲,暗叹孔明大才,竟作得如此不凡仙乐,看到孔明忽而大悲,慌问:“水,何事悲恸?”
 
诸葛亮止住抽泣:“亮自主公三顾茅庐出山以来,蒙主公厚爱,自比如鱼得水,敢不尽力?然每日击鼓升帐,皆亮一人在上唱独角戏,众将在下唯唯诺诺,只是照亮的安排做事。如此下去,亮日后定会被司马懿那厮累死呀。”
刘备眨着充满问号的大眼睛:“孔明可是说曹贼丞相府小小的主薄司马懿?他有何德何能。。。”
诸葛亮慌打断:“亮心有些乱,且不提司马懿那小子。”
诸葛亮正襟危坐:“主公,我们要法制不要人制呀!万一哪天亮西去。。。”(刘备止含泪花握住孔明双手,孔明亦紧紧反握住刘备的大手)
半晌,诸葛亮续道:“岂不人亡政息?且主公百年后,阿斗与亮的关系又怎能比得如今亮与主公般相敬如宾?若亮在外争战,阿斗与亮政见不合要亮退兵,决策没有一致性,必将造成大错!如此,我大蜀何以恢复汉室江山呀?!”
刘备:“备深感如此。”
诸葛亮:“亮昨夜夜观天象。。。”
刘备大喜:“孔明可有良法?”
诸葛亮:“。。。亮昨夜夜观天象,竟然睡着,原来近日太耗心力。做一梦,数千年弹指间,亮醒来才觉泪流满面。梦中一帅哥自称陶辉,献上色目人大牛Leslie一法名paxos,或可解我等燃眉之急。”
刘备狂喜:“好!”继而搔了搔头:“先请孔明试言我大蜀帝国决策上有哪些问题?”
诸葛亮:“喏。”



1、蜀国现在决策制度的缺陷
诸葛亮:“主公,当下蜀国所有决策皆来自亮,这有两个问题,一、若亮身体有恙则政令必有耽误。二、随着汉中的收复,我们的地盘越来越大,事务也越来越多,目前亮乃五百年不世出奇才,尚能支撑,可若是将来收复长安,亮一人之力必不堪重负。请问主公有何策解此二难?”


刘备沉吟着:“可让法正法孝直,黄权黄公衡为你副手,平日助你共同议政决策,能帮你减负呀。孔明你老习惯在初一十五深入民间依红偎翠,那时他们都可暂时顶替于你,如此也不怕政令耽误了。”
诸葛亮咳嗽了下:“此二人皆治世之才!然,若子龙请求黄公衡允许蜀棉私营,而同时主公又请求亮加强垄断这有钱途的行业--禁止蜀棉私营,文武百官令行两出,或听亮的搞国家垄断,或听黄公衡的搞民营经济,百姓何以自处?”

刘备沉思半晌,方答道:“我们把决策分为两部分,一种是新增政策,如我正准备加税。另一种是下级官员请求政令的解释,比如马超出征归来时问伤兵抚恤金是多少等等。这样,孔明可处理所有新增决策,法正与黄权只负责解释已有决策。下面官员在执行时,任意找你三人中清闲者,就某个事件询问有何政令可指导,需要增加新的法令时,则只能找孔明你,孔明你决定新法令后,再通知法正和黄权这哥俩,这样法令就同步且一致了。当孔明不在时,由法正顶上这个决策位置;法正不在时,由黄权顶上。如此可好?”
诸葛亮惊喜道:“善!这可是master-slave设计呀!”
刘备也睁大了双眼闪着问号。诸葛亮咳嗽了下:“亮昨夜未睡好,失言了。”

诸葛亮又说道:“可这样还有问题,日后若我们收复许昌洛阳建业后,那时新法令会更多,只允许一人处理新法令新决策,必然还会忙不过来!而且,人为的指定亮的第二顺拉继承者是法正,黄权为第三顺位,这样也不妥,在地位不平等时,若以后决策组又增加许多新人,或者同一时间多人一起吃酒吃坏肚子,都会非常麻烦。”

刘备拍案而起:“孔明你主张大家都是同样地位,没有主次之分?这样无论哪个人出问题了,都不会对蜀国有什么影响?而且多人之间信息共享后,不会因人废事,也不会有人亡政息之事了?”
诸葛亮:“Bingo! 全对!这是真正的分布式!”
刘备大声叫好:“分布式?好名字,和八阵图一样响亮呀!”
诸葛亮:“但这完全平等的分布式决策机制,仍然必须政令统一,不能有不一致的法令,例如黄权认为他昨天中午通过的法令是嚼口香糖者一律杖责十板,免得有人随地乱吐影响市容(好象他们还立法大便后必须冲马桶)。而法正却在昨天上午就接受番邦李光耀的提议,允许嚼外国进口环保口香糖,百姓到底听谁的呢?”
刘备:“我知道孔明你很讨厌威权国家,别老抱怨,新加坡又没碍你事。上面这就是一致性问题了。孔明别卖关子了,快说你的paxos解决方法吧。”



2、paxos需要解决的分布式问题
诸葛亮激动道:“paxos可是真正的民主呀,两千年后我们汉人仍然做不到,这不是汉人的劣根性(乌坎村都能办好的),实是历史遗毒呀。闲话少叙,我们先来看看除了能保持一致性,paxos能解决哪些问题吧。

一、决策委员会里缺了哪个人都可以,蜀国照常做出决策。

二、大家的办公地又不在一起,平时通过信使小吏们传递消息,若信使在路上传消息时被马车撞死,仍然不会有政令不一致。

三、若信使被马车撞伤了,医治后迟了几个月才送到某人(例如法正),还不会出现政令不一致。

四、若信使被马车撞失忆了,以为刚送过消息的黄权还没送过,又跑去告诉黄权一次,同样不会有不一致出现。”
刘备:“孔明,我知道你马车机关多,开名车也不用总提嘛!若是信使被曹操的间谍收买了也没事吗?”
诸葛亮尴尬道:“这个不行,我们还是要相信人性本善嘛。呃,蜀国大部分都是好人。嗯,好吧,我们国安局不是吃干饭的,信使可以丢失、重复传递、延迟,但是我们保证不会被收买的。”
刘备:“好吧,能解决这四个问题也很不错,基本异常都考虑到了。快说说这个paxos解决之道吧。”



3、paxos的约束条件
诸葛亮:“刚刚不是说了民主吗?民主是个宝呀,它能解决一切问题。决策者之间不分高下,所以既然想要他们保持一致,我们就要用投票,少数服从多数!”
刘备:“怎么个投法?”
诸葛亮:“如果主公手下五虎上将是五个决策者。。。”刘备:“那五个肌肉男?”
诸葛亮:“正是,这证明即使五个头脑简单的武夫也能做好。”(五虎将齐打喷嚏。)
诸葛亮:“谁提议新政令(提案者),谁就发起投票。我们保证,投票者必须是决策者中的大多数。”
刘备:“怎么定大多数呢?”
诸葛亮:“任意两次投票中,必须有重合的决策者,这就是大多数了。比如五虎将做决策者,每次政令通过中,必须有三个人或更多投票的人才能决定,这样两次投票中至少有一人都参加了,他就可以拍板!对提案者来说,如果大多数投票者都投赞成这个提议,法令就通过。”
刘备沉重地说道:“孔明,万一总是凑不成大多数,岂不是耽误我们的现代化进程?民主,对中国国情来说,太复杂了。”

诸葛亮又激动了:“主公,不复杂的,长远来看好处很明显,不要短视!如果能做到以个三个基本点,所有政令绝对不会出现不一致,而且不会出现无法进行下去的事。一、所有政令必须被提出后才能批准;二、一次提出政令的过程中,只能批准一条政令;三、书记官(负责永久记录政令的官员)只能学习已经批准的政令。只要做到这三点,肯定不会政令不一致!”
刘备:“可是孔明,你在说什么呀?我只想知道决策者该怎么做。”
诸葛亮自信满满:“别急主公,从数学上可以证明,只要满足上面三条,一定不会出现政令不一。当然,这三条太宽泛了,不能对决策者做出指导。我还有更加严格的约束。一、每个决策者必须接受他收到的第一个提议政令。”
刘备:“凭什么呀?”诸葛亮:“我们要假定提议者已经搞清楚了一切,肯定是好提案啦。这不是我们的重点,别打断我。”
诸葛亮:“二、一旦关于一件事,我们通过一条法令后,之后关于这件事通过的任何法令,都还得是这个法令。”
刘备呆了下:“这不废话吗?”
诸葛亮自信满满:“虽然是废话,但你想,保证了这第2条,是不是所有的政令都必须一致呀?”
刘备:“可是对决策者没指导意义呀。”
诸葛亮自信满满:“是的,所以,我们加强约束,三、如果一条法令批准后,之后每一个决策者如果关于这件事又通过法令,那这个法令还得是同一条。”
刘备傻了:“你说得是没错,可这有什么用呢?”
诸葛亮自信满满:“所以继续加强约束:四、如果一条法令被批准通过了,之后提议者关于这件事,又提新法令,必须还得是同一个法令。”
刘备怒了:“孔明我想揍你了,你说这些有个屁用啊!”
诸葛亮自信满满:“别急主公,现在我要祭出最强约束条件作为我的奥义了:五、每个提案都得有个独一无二的编号,如果编号N的提案通过了,那么大多数决策者们,要么从没接受者编号小于N的任何提议,要么最近一次批准通过的法令就是这个提案。”
刘备开始追打诸葛亮:“孔明你个坏人,你玩我呀!这屁话你对我说!”
诸葛亮边逃边喊:“wiki里就是这么解释的,哎,主公你不懂数学别打我嘛。Leslie的论文也是这么写的。。。”



4、paxos执行流程
刘备:“真爽,孔明你手感不错。说点实在的吧,不懂的东西少扯。”
诸葛亮:“主公,你不懂数学嘛。好吧,我来说说paxos算法的流程,就三段式,六个步骤而已。角色包括,提案者,决策者,书记官(学习政令的)。
一、提案者先从主公那里搞到个独一无二的编号,例如N。找到决策者们的多数派,就说五虎将吧,找到三个肌肉男先。假设,这个提案者来自成都,想提的是,外地蜀国将级官员不得无故进入魏国使者驻蜀驿馆。那么,提案者发给三个五虎将,提案中说,我现在有个编号N的提案,关于蜀国高级将领进出魏国使者驿馆的事,请回答我。”

二、五虎将们收到了关于使者驿馆事件的提案,编号是N。其中任一个决策者,比如赵云,他在收到N提案后,首先检查,之前关于魏国使者驿馆事件,有没有收到过提案啊?如果没收到,当然回复提案通过,同时赵云拿出自己的小本本记上,已经回复编号N的提案。如果收到过关于驿馆事件的编号M的提案,就检查编号M,如果M大于N,那么跟信使说,我拒绝这个提案。如果M小于N,回复通过,并且说,关于这事,上次我已经收到了编号M的提案了。

三、提案者如果收到多数决策者的通过回复,就开始正式提议了。这时,先检查五虎将的回复,如果都简单的回复通过,那么就正式提议之前想提议的《蜀国将级官员不得无故进入魏国使者驻蜀国驿馆》提案。如果决策者们不是简单的回复通过,而是说:这次我赵云通过了,但是我曾经回复过编号M的提案。这样,提案者需要从这次决策者们的回复中,找出所有编号M中的最大值。假设就赵云复杂的回复了,其他四人都是简单的回复通过。那么,提案者这次不能正式提议自己原来想提的,而要提议编号M对应的提案。

四、同第二步骤一样,五虎将们根据二步骤的准则,选择通过还是不通过。
五、提案者如果发现多数决策者同意了,意味着法令通过,这时他要记录法令,同时告诉书记官们。
六、书记官们在羊皮纸上记录法令。“



5、paxos算法里的各角色该做的事
刘备搔搔头:“孔明,你再说说提案者,决策者要做的事吧,书记官的很简单,就不用说了。”
诸葛亮:“主公,书记官的工作不简单啊,信使会传丢消息的,书记官也会生病的。我们既要在法令通过时主动通知书记官,又要允许书记官在对法令不清楚时过来主动询问。不过,既然主公想多了解提案者和决策者的工作,我就来详细说说。
一、提案者。首先他得从主公那搞来一个独一无二的编号。”
刘备:“我很忙的孔明,我是一把手哎。”
诸葛亮有些无奈:“就光给编号也不干呀!那让他们自己维护自己的编号吧,遇到编号相同时,按级别排序,例如按关羽、张飞、赵云、马超、黄忠排序。然后要找到五虎将的多数派,例如关张赵这三人,发自己要决定的事以及编号过去。这是第一步。在第三步时,又到了提案者要做工作了。如果关羽又不响应自己了,那么再发给黄忠问问看。直到有大多数人响应自己。对于响应的处理,有以下情况:
A、这些响应中,如果有人明确拒绝,比如赵云说,关于驿馆事件,我已经批了编号大于N的提案,那么这次提案最好就放弃吧,或者加大自己的编号,重复第一步再提!
B、张飞说我可以通过,但是之前我批准过驿馆事件编号小于N的提案,内容是允许进入达到政治避难目的。那么,这次提案内容必须变更为张飞之前提交的方案。
C、所有人都无条件通过。继续正式提交自己的方案。
到第五步,如果多数派批准了,那么方案正式成为法令。提案者要告诉书记官记录哦。”
刘备:“你这么说我就明白了嘛。多简单?先前搞七搞八的说了一大通。”
诸葛亮:“唉,先前的证明嘛。当然,微软还搞了个两段式提交,号称fast paxos,那个雅虎的zookeeper也是的,其实也就对第五步做了优化。主公,不要打我,你不用管我刚才说了什么。我们继续说决策者的工作。
第二步,决策者开始工作了。例如还是说赵云,他在收到N提案后,首先检查,之前关于魏国使者驿馆事件,有没有收到过提案啊?如果没收到,简单的回复提案通过,同时赵云拿出自己的小本本记上,已经回复编号N的提案。赵云同时承诺,以后收到编号小于N的关于驿馆事件的提案,保证不批!如果收到过编号M的提案,检查这上次编号M,如果M大于N,那么跟信使说,我拒绝这个提案。如果M小于N,回复通过,并且说,关于这事,上次我已经收到了编号M的提案了。
第四步决策者批准时也和上面一样。不过fast paxos等两段式的paxos改进算法,在这里决策者们已经可以记录法案了。”
刘备:“好孔明!我有些明白了,不过光说不练假把式,演习下吧。把五个肌肉男叫来,你我来提案,外加捣乱,你可以用你的跑车撞信使了,看看是否出现不一致。”
诸葛亮:“No problem。不过现在我口干舌燥,咱们下回再说吧。”(想从具体的演习,从时间和各种容错上看paxos的效用,敬请期待下篇《paxos算法如何容错的--讲述五虎将的实践》

posted @ 2013-09-28 10:15 oathleo 阅读(202) | 评论 (0)编辑 收藏

测试1000个数据 每个数据10个字节,分别使用字节、json、bson方式 存储,并用gzip压缩

结果bson比json还大一点,确实出乎意料

个人结论是BSON对比json更加适合存储,在传输上没有太大优势

  BSON相对JSon
1.更快的遍历速度
2.操作更简易
3.增加了额外的数据类型

raw data: 10000
raw data gzip compress: 6553

json string: 44524
json byte: 44524
json gzip compress: 8125

bson byte: 46910
bson gzip compress: 9721


package main

import (
    "bytes"
    "compress/gzip"
    "fmt"
    "labix.org/v2/mgo/bson"
    "math/rand"
)

type HisCollection struct {
    RTValues []RTValue
}

type RTValue struct {
    Time   int32
    Status int16
    Value  float32
}

func main() {
    fmt.Println("start")

    size := 1000
    col := make([]RTValue, size)

    for i := 0; i < size; i++ {
        col[i] = RTValue{Time: int32(i), Status: 100, Value: rand.Float32()}
    }

    his := HisCollection{RTValues: col}
    data, err := bson.Marshal(&his)
    if err != nil {
        panic(err)
    }
    //    fmt.Println(data)
    fmt.Println("bson byte:", len(data))

    var compress_data_buf bytes.Buffer
    writer := gzip.NewWriter(&compress_data_buf)
    defer writer.Close()

    writer.Write(data)
    writer.Flush()

    fmt.Println("bson gzip compress:",len(compress_data_buf.Bytes()))

}

package main

import (
    "bytes"
    "compress/gzip"
    "fmt"
    "math/rand"
    "openplant/opnet"
)

func main() {
    var compress_data_buf bytes.Buffer
    writer := gzip.NewWriter(&compress_data_buf)
    defer writer.Close()

    size := 1000
    for i := 0; i < size; i++ {
        writer.Write(opnet.WarpInt32ToByte(int32(i)))
        writer.Write(opnet.WarpInt16ToByte(int16(100)))
        writer.Write(opnet.WarpFloat32ToByte(rand.Float32()))
    }

    writer.Flush()

    fmt.Println("raw data:", 10000)

    fmt.Println("raw data gzip compress:", len(compress_data_buf.Bytes()))

}
111

package main

import (
    "bytes"
    "compress/gzip"
    "encoding/json"
    "fmt"
    "math/rand"
)

type HisCollection struct {
    RTValues []RTValue
}

type RTValue struct {
    Time   int32
    Status int16
    Value  float32
}

func main() {
    fmt.Println("start")

    size := 1000
    col := make([]RTValue, size)

    for i := 0; i < size; i++ {
        col[i] = RTValue{Time: int32(i), Status: 100, Value: rand.Float32()}
    }

    his := HisCollection{RTValues: col}

    data, err := json.Marshal(&his)

    fmt.Println("json string:", string(data))
    fmt.Println("json string:", len(string(data)))

    if err != nil {
        panic(err)
    }
    //    fmt.Println(data)
    fmt.Println("json byte:", len(data))

    var compress_data_buf bytes.Buffer
    writer := gzip.NewWriter(&compress_data_buf)
    defer writer.Close()

    writer.Write(data)
    writer.Flush()

    fmt.Println("json gzip compress:", len(compress_data_buf.Bytes()))

}

posted @ 2013-09-23 14:08 oathleo 阅读(3283) | 评论 (0)编辑 收藏

     摘要: 工作项目需要在java和c/c++之间进行socket通信,socket通信是以字节流或者字节包进行的,socket发送方须将数据转换为字节流或者字节包,而接收方则将字节流和字节包再转换回相应的数据类型。如果发送方和接收方都是同种语言,则一般只涉及到字节序的调整。而对于java和c/c++的通信,则情况就要复杂一些,主要是因为java中没有unsigned类型,并且java和c在某些数据类型上的长...  阅读全文

posted @ 2013-09-23 10:02 oathleo 阅读(222) | 评论 (0)编辑 收藏

bson的介绍不说了
golang下的解析包找到2个 一个是mongo的http://labix.org/gobson
,另外一个比较小众https://github.com/sbunce/bson

这里用的是mongo的作为例子。
对象加上不同的注解,
可以轻松转成xml json bson 想想都兴奋 
package main

import (
    "fmt"
    "labix.org/v2/mgo/bson"
)

type TestStruct struct {
    Name string
    ID   int32
}

func main() {
    fmt.Println("start")
    data, err := bson.Marshal(&TestStruct{Name: "Bob"})
    if err != nil {
        panic(err)
    }
    fmt.Println("%q", data)

    value := TestStruct{}
    err2 := bson.Unmarshal(data, &value)
    if err2 != nil {
        panic(err)
    }
    fmt.Println("value:", value)

    mmap := bson.M{}
    err3 := bson.Unmarshal(data, mmap)
    if err3 != nil {
        panic(err)
    }
    fmt.Println("mmap:", mmap)

}

posted @ 2013-09-22 16:08 oathleo 阅读(7684) | 评论 (0)编辑 收藏

Panic和Recover

Go没有像Java那样的异常机制,它不能抛出异常,而是使用了panicrecover机制。一定要记住,你应当把它作为最后的手段来使用,也就是说,你的代码中应当没有,或者很少有panic的东西。这是个强大的工具,请明智地使用它。那么,我们应该如何使用它呢?

Panic

是一个内建函数,可以中断原有的控制流程,进入一个令人恐慌的流程中。当函数F调用panic,函数F的执行被中断,但是F中的延迟函数会正常执行,然后F返回到调用它的地方。在调用的地方,F的行为就像调用了panic。这一过程继续向上,直到发生panicgoroutine中所有调用的函数返回,此时程序退出。恐慌可以直接调用panic产生。也可以由运行时错误产生,例如访问越界的数组。

Recover

是一个内建的函数,可以让进入令人恐慌的流程中的goroutine恢复过来。recover仅在延迟函数中有效。在正常的执行过程中,调用recover会返回nil,并且没有其它任何效果。如果当前的goroutine陷入恐慌,调用recover可以捕获到panic的输入值,并且恢复正常的执行。

下面这个函数演示了如何在过程中使用panic

var user = os.Getenv("USER")  func init() {     if user == "" {         panic("no value for $USER")     } } 

下面这个函数检查作为其参数的函数在执行时是否会产生panic

func throwsPanic(f func()) (b bool) {     defer func() {         if x := recover(); x != nil {             b = true         }     }()     f() //执行函数f,如果f中出现了panic,那么就可以恢复回来     return } 

最容易理解就是给个例子,文章里有例子:

package main  import(     "fmt"     //"os" )  var user = "" func inita() {     defer func(){         fmt.Print("defer##\n")     }()     if user == "" {         fmt.Print("@@@before panic\n")         panic("no value for user\n")         fmt.Print("!!after panic\n")     } }  func throwsPanic (f func()) (b bool){     defer func(){         if x:= recover(); x != nil{             fmt.Print(x)             b = true         }     }()     f()     fmt.Print("after the func run")     return }  func main(){     throwsPanic(inita) } 

执行结果:

D:\go>go run b.go
@@@before panic
defer##
no value for user

如上面所说的:

panicuser=""时,打断了函数的执行,fmt.Print("!!after panic\n")没有执行。 但函数中的延迟函数会正常执行,打印了 defer##。然后返回到调用该函数的地方,继续上面的过程。

直到执行完所有函数的defer,退出程序。Recover可以捕获到panic的值,上面的打印no value for user。并且恢复正常的执行。

posted @ 2013-09-22 09:32 oathleo 阅读(2231) | 评论 (0)编辑 收藏

Go语言的传参和传引用[OSC源创会主题补充1]

66人收藏此文章, 我要收藏发表于2天前(2013-09-14 22:10) , 已有1496次阅读 ,共12个评论

OSC源创会主题补充系列:

  1. Go语言的传参和传引用
  2. Go语言的类型转换和类型断言

Go语言规范虽然很简单, 但是深入掌握Go语言却需要很多底层知识.

本来第20期的武汉OSC源创会有Go语言的专题讲座, 谁知道说取消就取消了.

我最近也整理了一些Go语言资料, 有Go语言的历史/现状/未来发展的八卦和Go语言常见的问题和陷阱两个部分, 本来打算OSC源创会能和武汉的Gopher分享 下的, 谁知道(由于不是赞助商也不是微软的大牛)主办方根本不给任何的机会.

100+人数的交流会基本都是扯淡, 还是小规模的讨论沙龙比较靠谱, 以后再也不会去OSC源创会当听众了.

现在计划将各个小问题暂时作为博客发表.

传参和传引用的问题

很多非官方的文档和教材(包括一些已经出版的图书), 对Go语言的传参和引用的讲解 都有很多问题. 导致众多Go语言新手对Go的函数参数传参有很多误解.

而传参和传引用是编程语言的根本问题, 如果这个问题理解错误可能会导致很多问题.

slice不是引用!

首先, Go语言的函数调用参数全部是传值的, 包括 slice/map/chan 在内所有类型, 没有传引用的说法.

具体请看Go语言的规范:

After they are evaluated, the parameters of the call are passed by value to the function and the called function begins execution.

from: http://golang.org/ref/spec#Calls

什么叫引用?

比如有以下代码:

var a Object doSomething(a) // 修改a的值 print(a) 

如果函数doSomething修改a的值, 然后print打印出来的也是修改后的值, 那么就可以认为doSomething是通过引用的方式使用了参数a.

为什么slice不是引用?

我们构造以下的代码:

func main() {     a := []int{1,2,3}     fmt.Println(a)     modifySlice(a)     fmt.Println(a) }  func modifySlice(data []int) {     data = nil } 

其中modifySlice修改了切片a, 输出结果如下:

[1 2 3] [1 2 3] 

说明a在调用modifySlice前后并没有任何变化, 因此a必然是传值的!

为什么很多人误以为slice是引用呢?

可能是 因为很多新接触Go语言的新手, 看到Go语言的文档说Go的切片和C语言的数组类型, 而C语言的数组是传地址的(注意: 不是传引用!).

下面这个代码可能是错误的根源:

func main() {     a := []int{1,2,3}     fmt.Println(a)     modifySliceData(a)     fmt.Println(a) }  func modifySliceData(data []int) {     data[0] = 0 } 

输出为:

[1 2 3] [0 2 3] 

函数modifySliceData确实通过参数修改了切片的内容.

但是请注意: 修改通过函数修改参数内容的机制有很多, 其中传参数的地址就可以修改参数的值(其实是修改参数中指针指向的数据), 并不是只有引用一种方式!

传指针和传引用是等价的吗?

比如有以下代码:

func main() {     a := new(int)     fmt.Println(a)     modify(a)     fmt.Println(a) }  func modify(a *int) {     a = nil } 

输出为:

0xc010000000 0xc010000000 

可以看出指针a本身并没有变化. 传指针或传地址也只能修改指针指向的内存的值, 并不能改变指针本身在值.

因此, 函数参数传传指针也是传值的, 并不是传引用!

所有类型的函数参数都是传值的!

包括slice/map/chan等基础类型和自定义的类型都是传值的.

但是因为slicemap/chan底层结构的差异, 又导致了它们传值的影响并不完全等同.

重点归纳如下:

  • GoSpec: the parameters of the call are passed by value!
  • map/slice/chan 都是传值, 不是传引用
  • map/chan 对应指针, 和引用类似
  • slice 是结构体和指针的混合体

  • slice 含 values/count/capacity 等信息, 是按值传递

  • slice 中的 values 是指针, 按值传递
  • 按值传递的 slice 只能修改values指向的数据, 其他都不能修改

  • 以指针或结构体的角度看, 都是值传递!

那Go语言有传引用的说法吗?

Go语言其实也是有传引用的地方的, 但是不是函数的参数, 而是闭包对外部环境是通过引用访问的.

查看以下的代码:

func main() {     a := new(int)     fmt.Println(a)     func() {         a = nil     }()     fmt.Println(a) } 

输出为:

0xc010000000 <nil> 

因为闭包是通过引用的方式使用外部环境的a变量, 因此可以直接修改a的值.

比如下面2段代码的输出是截然不同的, 原因就是第二个代码是通过闭包引用的方式输出i变量:

for i := 0; i < 5; i++ {     defer fmt.Printf("%d ", i)     // Output: 4 3 2 1 0 }  fmt.Printf("\n")     for i := 0; i < 5; i++ {     defer func(){ fmt.Printf("%d ", i) } ()     // Output: 5 5 5 5 5 } 

像第二个代码就是于闭包引用导致的副作用, 回避这个副作用的办法是通过参数传值或每次闭包构造不同的临时变量:

// 方法1: 每次循环构造一个临时变量 i for i := 0; i < 5; i++ {     i := i     defer func(){ fmt.Printf("%d ", i) } ()     // Output: 4 3 2 1 0 } // 方法2: 通过函数参数传惨 for i := 0; i < 5; i++ {     defer func(i int){ fmt.Printf("%d ", i) } (i)     // Output: 4 3 2 1 0 } 

总结

  • 函数参数传值, 闭包传引用!
  • slice 含 values/count/capacity 等信息, 是按值传递
  • 按值传递的 slice 只能修改values指向的数据, 其他都不能修改
  • slice 是结构体和指针的混合体

posted @ 2013-09-16 09:23 oathleo 阅读(3997) | 评论 (1)编辑 收藏

数组 Arrays

数组是内置(build-in)类型,是一组同类型数据的集合,它是值类型,通过从0开始的下标索引访问元素值。在初始化后长度是固定的,无法修改其长度。当作为方法的入参传入时将复制一份数组而不是引用同一指针。数组的长度也是其类型的一部分,通过内置函数len(array)获取其长度。

初始化

数组的初始化有多种形式,查看示例代码 , 在线运行示例代码

  • [5] int {1,2,3,4,5} 
    长度为5的数组,其元素值依次为:1,2,3,4,5
  • [5] int {1,2} 
    长度为5的数组,其元素值依次为:1,2,0,0,0 。在初始化时没有指定初值的元素将会赋值为其元素类型int的默认值0,string的默认值是""
  • [...] int {1,2,3,4,5} 
    长度为5的数组,其长度是根据初始化时指定的元素个数决定的
  • [5] int { 2:1,3:2,4:3} 
    长度为5的数组,key:value,其元素值依次为:0,0,1,2,3。在初始化时指定了2,3,4索引中对应的值:1,2,3
  • [...] int {2:1,4:3} 
    长度为5的数组,起元素值依次为:0,0,1,0,3。由于指定了最大索引4对应的值3,根据初始化的元素个数确定其长度为5

赋值与使用

数组通过下标访问元素,可修改其元素值

arr :=[...] int {1,2,3,4,5} arr[4]=arr[1]+len(arr)      //arr[4]=2+5 

通过for遍历数组元素,查看示例代码,在线运行示例代码

arr := [5]int{5, 4, 3}  for index, value := range arr {     fmt.Printf("arr[%d]=%d \n", index, value) }  for index := 0; index < len(arr); index++ {     fmt.Printf("arr[%d]=%d \n", index, arr[index]) } 

数组是值类型,将一个数组赋值给另一个数组时将复制一份新的元素,查看示例代码,在线运行示例代码

arr2 := [5]int{1, 2}  arr5 := arr2 arr5[0] = 5 arr2[4] = 2 fmt.Printf(" arr5= %d \n arr2=%d \n arr5[0]==arr2[0]= %s \n", arr5, arr2, arr5[0] == arr2[0])  OutPut:  arr5=[5 2 0 0 0]   arr2=[1 2 0 0 2]   arr5[0]==arr2[0]= false 

切片 Slices

数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型Slices切片,与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。切片中有两个概念:一是len长度,二是cap容量,长度是指已经被赋过值的最大下标+1,可通过内置函数len()获得。容量是指切片目前可容纳的最多元素个数,可通过内置函数cap()获得。切片是引用类型,因此在当传递切片时将引用同一指针,修改值将会影响其他的对象。

初始化

切片可以通过数组来初始化,也可以通过内置函数make()初始化 .初始化时len=cap,在追加元素时如果容量cap不足时将按len的2倍扩容 查看示例代码在线运行示例代码

  • s :=[] int {1,2,3 } 
    直接初始化切片,[]表示是切片类型,{1,2,3}初始化值依次是1,2,3.其cap=len=3
  • s := arr[:] 
    初始化切片s,是数组arr的引用
  • s := arr[startIndex:endIndex] 
    将arr中从下标startIndex到endIndex-1 下的元素创建为一个新的切片
  • s := arr[startIndex:] 
    缺省endIndex时将表示一直到arr的最后一个元素
  • s := arr[:endIndex] 
    缺省startIndex时将表示从arr的第一个元素开始
  • s1 := s[startIndex:endIndex] 
    通过切片s初始化切片s1
  • s :=make([]int,len,cap) 
    通过内置函数make()初始化切片s,[]int 标识为其元素类型为int的切片

赋值与使用

切片是引用类型,在使用时需要注意其操作。查看示例代码 ,在线运行示例代码 切片可以通过内置函数append(slice []Type,elems ...Type)追加元素,elems可以是一排type类型的数据,也可以是slice,因为追加的一个一个的元素,因此如果将一个slice追加到另一个slice中需要带上"...",这样才能表示是将slice中的元素依次追加到另一个slice中。另外在通过下标访问元素时下标不能超过len大小,如同数组的下标不能超出len范围一样。

  • s :=append(s,1,2,3,4)
  • s :=append(s,s1...)
转载时请注明出处!老虞http://www.cnblogs.com/howDo/

posted @ 2013-09-12 09:20 oathleo 阅读(1800) | 评论 (0)编辑 收藏

服务器端/客户端 在 login的时候经常多次read write
这个时候 read 要完整,第一次没有read完,就write,第二次read 到的仍然是上次没有read完的数据

posted @ 2013-09-11 08:56 oathleo 阅读(286) | 评论 (0)编辑 收藏

// bufio 包实现了带缓存的 I/O 操作
// 它封装一个 io.Reader 或 io.Writer 对象
// 使其具有缓存和一些文本读写功能
------------------------------------------------------------
// bufio.go
------------------------------------------------------------
// Reader 实现了带缓存的 io.Reader 对象
type Reader struct {
// 私有字段
}
// NewReaderSize 将 rd 封装成一个拥有 size 大小缓存的 bufio.Reader 对象
// 如果 rd 的基类型就是 bufio.Reader 类型,而且拥有足够的缓存
// 则直接将 rd 转换为基类型并返回
func NewReaderSize(rd io.Reader, size int) *Reader
// NewReader 相当于 NewReaderSize(rd, 4096)
func NewReader(rd io.Reader) *Reader
------------------------------------------------------------
// Peek 返回缓存的一个切片,该切片引用缓存中前 n 字节数据
// 该操作不会将数据读出,只是引用
// 引用的数据在下一次读取操作之前是有效的
// 如果引用的数据长度小于 n,则返回一个错误信息
// 如果 n 大于缓存的总大小,则返回 ErrBufferFull
// 通过 Peek 的返回值,可以修改缓存中的数据
// 但是不能修改底层 io.Reader 中的数据
func (b *Reader) Peek(n int) ([]byte, error)
func main() {
s := strings.NewReader("ABCDEFG")
br := bufio.NewReader(s)
b, _ := br.Peek(5)
fmt.Printf("%s\n", b)
// ABCDE
b[0] = 'a'
b, _ = br.Peek(5)
fmt.Printf("%s\n", b)
// aBCDE
}
------------------------------------------------------------
// Read 从 b 中读出数据到 p 中,返回读出的字节数
// 如果 p 的大小 >= 缓存的总大小,而且缓存不为空
// 则只能读出缓存中的数据,不会从底层 io.Reader 中提取数据
// 如果 p 的大小 >= 缓存的总大小,而且缓存为空
// 则直接从底层 io.Reader 向 p 中读出数据,不经过缓存
// 只有当 b 中无可读数据时,才返回 (0, io.EOF)
func (b *Reader) Read(p []byte) (n int, err error)
func main() {
s := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
br := bufio.NewReader(s)
b := make([]byte, 20)
n, err := br.Read(b)
fmt.Printf("%-20s %-2v %v\n", b[:n], n, err)
// ABCDEFGHIJKLMNOPQRST 20 <nil>
n, err = br.Read(b)
fmt.Printf("%-20s %-2v %v\n", b[:n], n, err)
// UVWXYZ1234567890     16 <nil> 
n, err = br.Read(b)
fmt.Printf("%-20s %-2v %v\n", b[:n], n, err)
//                      0  EOF
}
------------------------------------------------------------
// ReadByte 从 b 中读出一个字节并返回
// 如果 b 中无可读数据,则返回一个错误
func (b *Reader) ReadByte() (c byte, err error)
// UnreadByte 撤消最后一次读出的字节
// 只有最后读出的字节可以被撤消
// 无论任何操作,只要有内容被读出,就可以用 UnreadByte 撤消一个字节
func (b *Reader) UnreadByte() error
func main() {
s := strings.NewReader("ABCDEFG")
br := bufio.NewReader(s)
c, _ := br.ReadByte()
fmt.Printf("%c\n", c)
// A
c, _ = br.ReadByte()
fmt.Printf("%c\n", c)
// B
br.UnreadByte()
c, _ = br.ReadByte()
fmt.Printf("%c\n", c)
// B
}
------------------------------------------------------------
// ReadRune 从 b 中读出一个 UTF8 编码的字符并返回
// 同时返回该字符的 UTF8 编码长度
// 如果 UTF8 序列无法解码出一个正确的 Unicode 字符
// 则只读出 b 中的一个字节,并返回 U+FFFD 字符,size 返回 1
func (b *Reader) ReadRune() (r rune, size int, err error)
// UnreadRune 撤消最后一次读出的 Unicode 字符
// 如果最后一次执行的不是 ReadRune 操作,则返回一个错误
// 因此,UnreadRune 比 UnreadByte 更严格
func (b *Reader) UnreadRune() error
func main() {
s := strings.NewReader("你好,世界!")
br := bufio.NewReader(s)
c, size, _ := br.ReadRune()
fmt.Printf("%c %v\n", c, size)
// 你 3
c, size, _ = br.ReadRune()
fmt.Printf("%c %v\n", c, size)
// 好 3
br.UnreadRune()
c, size, _ = br.ReadRune()
fmt.Printf("%c %v\n", c, size)
// 好 3
}
------------------------------------------------------------
// Buffered 返回缓存中数据的长度
func (b *Reader) Buffered() int
func main() {
s := strings.NewReader("你好,世界!")
br := bufio.NewReader(s)
fmt.Println(br.Buffered())
// 0
br.Peek(1)
fmt.Println(br.Buffered())
// 18
}
------------------------------------------------------------
// ReadSlice 在 b 中查找 delim 并返回 delim 及其之前的所有数据的切片
// 该操作会读出数据,返回的切片是已读出数据的引用
// 切片中的数据在下一次读取操作之前是有效的
//
// 如果 ReadSlice 在找到 delim 之前遇到错误
// 则读出缓存中的所有数据并返回,同时返回遇到的错误(通常是 io.EOF)
// 如果在整个缓存中都找不到 delim,则 err 返回 ErrBufferFull
// 如果 ReadSlice 能找到 delim,则 err 始终返回 nil
//
// 因为返回的切片中的数据有可能被下一次读写操作修改
// 因此大多数操作应该使用 ReadBytes 或 ReadString,它们返回的不是数据引用
func (b *Reader) ReadSlice(delim byte) (line []byte, err error)
func main() {
s := strings.NewReader("ABC DEF GHI JKL")
br := bufio.NewReader(s)
w, _ := br.ReadSlice(' ')
fmt.Printf("%q\n", w)
// "ABC "
w, _ = br.ReadSlice(' ')
fmt.Printf("%q\n", w)
// "DEF "
w, _ = br.ReadSlice(' ')
fmt.Printf("%q\n", w)
// "GHI "
}
------------------------------------------------------------
// ReadLine 是一个低级的原始的行读取操作
// 大多数情况下,应该使用 ReadBytes('\n') 或 ReadString('\n')
// 或者使用一个 Scanner
//
// ReadLine 通过调用 ReadSlice 方法实现,返回的也是缓存的切片
// ReadLine 尝试返回一个单行数据,不包括行尾标记(\n 或 \r\n)
// 如果在缓存中找不到行尾标记,则设置 isPrefix 为 true,表示查找未完成
// 同时读出缓存中的数据并作为切片返回
// 只有在当前缓存中找到行尾标记,才将 isPrefix 设置为 false,表示查找完成
// 可以多次调用 ReadLine 来读出一行
// 返回的数据在下一次读取操作之前是有效的
// 如果 ReadLine 无法获取任何数据,则返回一个错误信息(通常是 io.EOF)
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)
func main() {
s := strings.NewReader("ABC\nDEF\r\nGHI\r\nJKL")
br := bufio.NewReader(s)
w, isPrefix, _ := br.ReadLine()
fmt.Printf("%q %v\n", w, isPrefix)
// "ABC" false
w, isPrefix, _ = br.ReadLine()
fmt.Printf("%q %v\n", w, isPrefix)
// "DEF" false
w, isPrefix, _ = br.ReadLine()
fmt.Printf("%q %v\n", w, isPrefix)
// "GHI" false
}
------------------------------------------------------------
// ReadBytes 在 b 中查找 delim 并读出 delim 及其之前的所有数据
// 如果 ReadBytes 在找到 delim 之前遇到错误
// 则返回遇到错误之前的所有数据,同时返回遇到的错误(通常是 io.EOF)
// 只有当 ReadBytes 找不到 delim 时,err 才不为 nil
// 对于简单的用途,使用 Scanner 可能更方便
func (b *Reader) ReadBytes(delim byte) (line []byte, err error)
func main() {
s := strings.NewReader("ABC DEF GHI JKL")
br := bufio.NewReader(s)
w, _ := br.ReadBytes(' ')
fmt.Printf("%q\n", w)
// "ABC "
w, _ = br.ReadBytes(' ')
fmt.Printf("%q\n", w)
// "DEF "
w, _ = br.ReadBytes(' ')
fmt.Printf("%q\n", w)
// "GHI "
}
------------------------------------------------------------
// ReadString 功能同 ReadBytes,只不过返回的是一个字符串
func (b *Reader) ReadString(delim byte) (line string, err error)
func main() {
s := strings.NewReader("ABC DEF GHI JKL")
br := bufio.NewReader(s)
w, _ := br.ReadString(' ')
fmt.Printf("%q\n", w)
// "ABC "
w, _ = br.ReadString(' ')
fmt.Printf("%q\n", w)
// "DEF "
w, _ = br.ReadString(' ')
fmt.Printf("%q\n", w)
// "GHI "
}
------------------------------------------------------------
// WriteTo 实现了 io.WriterTo 接口
func (b *Reader) WriteTo(w io.Writer) (n int64, err error)
func main() {
s := strings.NewReader("ABCEFG")
br := bufio.NewReader(s)
b := bytes.NewBuffer(make([]byte, 0))
br.WriteTo(b)
fmt.Printf("%s\n", b)
// ABCEFG
}
------------------------------------------------------------
// Writer 实现了带缓存的 io.Writer 对象
// 如果在向 Writer 中写入数据的过程中遇到错误
// 则 Writer 不会再接受任何数据
// 而且后续的写入操作都将返回错误信息
type Writer struct {
// 私有字段
}
// NewWriterSize 将 wr 封装成一个拥有 size 大小缓存的 bufio.Writer 对象
// 如果 wr 的基类型就是 bufio.Writer 类型,而且拥有足够的缓存
// 则直接将 wr 转换为基类型并返回
func NewWriterSize(wr io.Writer, size int) *Writer
// NewWriter 相当于 NewWriterSize(wr, 4096)
func NewWriter(wr io.Writer) *Writer
------------------------------------------------------------
// Flush 将缓存中的数据提交到底层的 io.Writer 中
func (b *Writer) Flush() error
// Available 返回缓存中的可以空间
func (b *Writer) Available() int
// Buffered 返回缓存中未提交的数据长度
func (b *Writer) Buffered() int
// Write 将 p 中的数据写入 b 中,返回写入的字节数
// 如果写入的字节数小于 p 的长度,则返回一个错误信息
func (b *Writer) Write(p []byte) (nn int, err error)
// WriteString 同 Write,只不过写入的是字符串
func (b *Writer) WriteString(s string) (int, error)
func main() {
b := bytes.NewBuffer(make([]byte, 0))
bw := bufio.NewWriter(b)
fmt.Println(bw.Available()) // 4096
fmt.Println(bw.Buffered())  // 0
bw.WriteString("ABCDEFGH")
fmt.Println(bw.Available()) // 4088
fmt.Println(bw.Buffered())  // 8
fmt.Printf("%q\n", b)       // ""
bw.Flush()
fmt.Println(bw.Available()) // 4096
fmt.Println(bw.Buffered())  // 0
fmt.Printf("%q\n", b)       // "ABCEFG"
}
------------------------------------------------------------
// WriteByte 向 b 中写入一个字节
func (b *Writer) WriteByte(c byte) error
// WriteRune 向 b 中写入 r 的 UTF8 编码
// 返回 r 的编码长度
func (b *Writer) WriteRune(r rune) (size int, err error)
func main() {
b := bytes.NewBuffer(make([]byte, 0))
bw := bufio.NewWriter(b)
bw.WriteByte('H')
bw.WriteByte('e')
bw.WriteByte('l')
bw.WriteByte('l')
bw.WriteByte('o')
bw.WriteByte(' ')
bw.WriteRune('世')
bw.WriteRune('界')
bw.WriteRune('!')
bw.Flush()
fmt.Println(b) // Hello 世界!
}
------------------------------------------------------------
// ReadFrom 实现了 io.ReaderFrom 接口
func (b *Writer) ReadFrom(r io.Reader) (n int64, err error)
func main() {
b := bytes.NewBuffer(make([]byte, 0))
s := strings.NewReader("Hello 世界!")
bw := bufio.NewWriter(b)
bw.ReadFrom(s)
bw.Flush()
fmt.Println(b) // Hello 世界!
}
------------------------------------------------------------
// ReadWriter 集成了 bufio.Reader 和 bufio.Writer
// 它实现了 io.ReadWriter 接口
type ReadWriter struct {
*Reader
*Writer
}
// NewReadWriter 封装 r 和 w 为一个 bufio.ReadWriter 对象
func NewReadWriter(r *Reader, w *Writer) *ReadWriter
------------------------------------------------------------
// scan.go
------------------------------------------------------------
// Scanner 提供了一个方便的接口来读取数据,例如读取一个多行文本
// 连续调用 Scan 方法将扫描数据中的“指定部分”,跳过各个“指定部分”之间的数据
// Scanner 使用了缓存,所以“指定部分”的长度不能超出缓存的长度
// Scanner 需要一个 SplitFunc 类型的“切分函数”来确定“指定部分”的格式
// 本包中提供的“切分函数”有“行切分函数”、“字节切分函数”、“UTF8字符编码切分函数”
// 和“单词切分函数”,用户也可以自定义“切分函数”
// 默认的“切分函数”为“行切分函数”,用于获取数据中的一行数据(不包括行尾符)
//
// 扫描在遇到下面的情况时会停止:
// 1、数据扫描完毕,遇到 io.EOF
// 2、遇到读写错误
// 3、“指定部分”的长度超过了缓存的长度
// 如果要对数据进行更多的控制,比如的错误处理或扫描更大的“指定部分”或顺序扫描
// 则应该使用 bufio.Reader
type Scanner struct {
// 私有字段
}
// SplitFunc 用来定义“切分函数”类型
// data 是要扫描的数据
// atEOF 标记底层 io.Reader 中的数据是否已经读完
// advance 返回 data 中已处理的数据长度
// token 返回找到的“指定部分”
// err 返回错误信息
// 如果在 data 中无法找到一个完整的“指定部分”
// 则 SplitFunc 返回 (0, nil) 来告诉 Scanner
// 向缓存中填充更多数据,然后再次扫描
//
// 如果返回的 err 是非 nil 值,扫描将被终止,并返回错误信息
//
// 如果 data 为空,则“切分函数”将不被调用
// 意思是在 SplitFunc 中不必考虑 data 为空的情况
//
// SplitFunc 的作用很简单,从 data 中找出你感兴趣的数据,然后返回
// 并告诉调用者,data 中有多少数据你已经处理过了
type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)
// NewScanner 创建一个 Scanner 来扫描 r
// 默认切分函数为 ScanLines
func NewScanner(r io.Reader) *Scanner
// Err 返回扫描过程中遇到的非 EOF 错误
// 供用户调用,以便获取错误信息
func (s *Scanner) Err() error
------------------------------------------------------------
// Bytes 将最后一次扫描出的“指定部分”作为一个切片返回(引用传递)
// 下一次的 Scan 操作会覆盖本次返回的结果
func (s *Scanner) Bytes() []byte
// Text 将最后一次扫描出的“指定部分”作为字符串返回(值传递)
func (s *Scanner) Text() string
------------------------------------------------------------
// Scan 在 Scanner 的数据中扫描“指定部分”
// 找到后,用户可以通过 Bytes 或 Text 方法来取出“指定部分”
// 如果扫描过程中遇到错误,则终止扫描,并返回 false
func (s *Scanner) Scan() bool
func main() {
s := strings.NewReader("ABC\nDEF\r\nGHI\nJKL")
bs := bufio.NewScanner(s)
for bs.Scan() {
fmt.Printf("%s %v\n", bs.Bytes(), bs.Text())
}
// ABC ABC
// DEF DEF
// GHI GHI
// JKL JKL
}
------------------------------------------------------------
// Split 用于设置 Scanner 的“切分函数”
// 这个函数必须在调用 Scan 前执行
func (s *Scanner) Split(split SplitFunc)
func main() {
s := strings.NewReader("ABC DEF GHI JKL")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanWords)
for bs.Scan() {
fmt.Println(bs.Text())
}
// ABC
// DEF
// GHI
// JKL
}
------------------------------------------------------------
// ScanBytes 是一个“切分函数”
// 用来找出 data 中的单个字节并返回
func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error)
func main() {
s := strings.NewReader("Hello 世界!")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanBytes)
for bs.Scan() {
fmt.Printf("%s ", bs.Text())
}
}
------------------------------------------------------------
// ScanRunes 是一个“切分函数”
// 用来找出 data 中的单个 UTF8 字符的编码并返回
// 如果 UTF8 解码出错,则返回的 U+FFFD 会被做为 "\xef\xbf\xbd" 返回
// 这使得用户无法区分“真正的U+FFFD字符”和“解码错误的返回值”
func ScanRunes(data []byte, atEOF bool) (advance int, token []byte, err error)
func main() {
s := strings.NewReader("Hello 世界!")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanRunes)
for bs.Scan() {
fmt.Printf("%s ", bs.Text())
} // H e l l o   世 界 !
}
------------------------------------------------------------
// ScanLines 是一个“切分函数”
// 用来找出 data 中的单行数据并返回(包括空行)
// 行尾标记可能是 \n 或 \r\n(返回值不包括行尾标记)
func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error)
------------------------------------------------------------
// ScanWords 是一个“切分函数”
// 用来找出 data 中的单词
// 单词以空白字符分隔,空白字符由 unicode.IsSpace 定义
func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error)

posted @ 2013-09-05 16:01 oathleo 阅读(1193) | 评论 (0)编辑 收藏

     摘要: 周末天气不好,只能宅在家里,于是就顺便看了一下Go语言,觉得比较有意思,所以写篇文章介绍一下。我想写一篇你可以在乘坐地铁或公交车上下班时就可以初步了解一门语言的文章。所以,下面的文章主要是以代码和注释为主。只需要你对C语言,Unix,Python有一点基础,我相信你会在30分钟左右读完并对Go语言有一些初步了解的。Hello World文件名 hello.go1234567package main...  阅读全文

posted @ 2013-09-03 09:20 oathleo 阅读(231) | 评论 (0)编辑 收藏

     摘要: 希望你看到这篇文章的时候还是在公交车和地铁上正在上下班的时间,我希望我的这篇文章可以让你利用这段时间了解一门语言。当然,希望你不会因为看我的文章而错过站。呵呵。如果你还不了解Go语言的语法,还请你移步先看一下上篇——《Go语言简介(上):语法》goroutineGoRoutine主要是使用go关键字来调用函数,你还可以使用匿名函数,如下所示:1234567891011121...  阅读全文

posted @ 2013-09-03 09:20 oathleo 阅读(675) | 评论 (0)编辑 收藏

分类: Go2013-07-31 11:02 177人阅读 评论(0) 收藏 举报
1、整形到字符串:
    
  1. var i int = 1  
  2. var s string  
  1. s = strconv.Itoa(i) 或者 s = FormatInt(int64(i), 10)  

2、字符串到整形
    
  1. var s string = "1"  
  2. var i int  
  3. i, err = strconv.Atoi(s) 或者 i, err = ParseInt(s, 10, 0)  

3、字符串到float(32 / 64)
    
  1. var s string = 1  
  2. var f float32  
  3. f, err = ParseFloat(s, 32)  


 float 64的时候将上面函数中的32转为64即可


4、整形到float或者float到整形
    直接使用float(i) 或者 int(f) 直接进行转换即可

posted @ 2013-08-30 11:37 oathleo 阅读(24342) | 评论 (0)编辑 收藏

golang strconv

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


a:=strconv.FormatFloat(10.100,'f',-1,32)

输出:

10.1

a := strconv.FormatFloat(10.101, 'f', -1, 64)

输出:

10.101

a := strconv.FormatFloat(10.010, 'f', -1, 64)

输出:10.01

a:=strconv.FormatFloat(10.1,'f',2,64)

输出:10.10


f 参数可以时e,E,g,G

-1 代表输出的精度小数点后的位数,如果是<0的值,则返回最少的位数来表示该数,如果是大于0的则返回对应位数的值

64 为float的类型,go中float分为32和64位,因此就需要传入32或者64


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


golang strconv.ParseInt 是将字符串转换为数字的函数,功能灰常之强大,看的我口水直流.

func ParseInt(s string, base int, bitSize int) (i int64, err error)

参数1 数字的字符串形式

参数2 数字字符串的进制 比如二进制 八进制 十进制 十六进制

参数3 返回结果的bit大小 也就是int8 int16 int32 int64

代码:

01package main
02     
03import (
04    "strconv"
05)
06     
07func main() {
08    i, err := strconv.ParseInt("123", 10, 32)
09    if err != nil {
10        panic(err)
11    }
12    println(i)
13}


posted @ 2013-08-30 11:26 oathleo 阅读(5737) | 评论 (0)编辑 收藏

做了下go和java的http性能的简单比较
服务端直接输出字符串
使用JMeter
windows下
 



2000的并发,测试结果很出乎意料,go不会这么差吧


研究了半小时,原因如下
tomcat的servlet里加了        response.setHeader("Pragma""no-cache");
go里没有设置该参数

设置后重新跑测试



可以了吧




posted @ 2013-08-27 15:29 oathleo 阅读(7020) | 评论 (5)编辑 收藏

golang html 与 golang客户端 上传文件

 May 30 , 2013 at 08:30 am -  263点击 -  0 评论

小文件上传

 var buffer bytes.Buffer

w := multipart.NewWriter(&buffer)
// Write fields and files
w.CreateFormField("input1")
w.WriteField(
"input1","value1")
w.CreateFormFile(
"file","filename.dat")

resp,err :
= http.Post(url,w.FormDataContentType(),&buffer)


服务器的handler:

func uploadHandler(w http.ResponseWriter, r 
*http.Request){

 
if r.URL.Path=="/upload.go" {   

        fn,header,err:
=r.FormFile("file")

        defer fn.Close()

        f,err:
=os.Create("filenametosaveas")

        defer f.Close()

        io.Copy(f,fn)

    }

}


客户端代码:
func Upload() (err error) {

    
// Create buffer

    buf :
= new(bytes.Buffer) // caveat IMO dont use this for large files, \

    
// create a tmpfile and assemble your multipart from there (not tested)

    w :
= multipart.NewWriter(buf)

    
// Create file field

    fw, err :
= w.CreateFormFile("file""helloworld.go"//这里的file很重要,必须和服务器端的FormFile一致

    
if err != nil {

        fmt.Println(
"c")

        
return err

    }

    fd, err :
= os.Open("helloworld.go")

    
if err != nil {

        fmt.Println(
"d")

        
return err

    }

    defer fd.Close()

    
// Write file field from file to upload

    _, err 
= io.Copy(fw, fd)

    
if err != nil {

        fmt.Println(
"e")

        
return err

    }

    
// Important if you do not close the multipart writer you will not have a

    
// terminating boundry

    w.Close()

    req, err :
= http.NewRequest("POST","http://192.168.2.127/configure.go?portId=2", buf)

    
if err != nil {

        fmt.Println(
"f")

        
return err

    }

    req.Header.Set(
"Content-Type", w.FormDataContentType())

      var client http.Client

    res, err :
= client.Do(req)

    
if err != nil {

        fmt.Println(
"g")

        
return err

    }

    io.Copy(os.Stderr, res.Body) 
// Replace this with Status.Code check

    fmt.Println(
"h")

    
return err

}


html上传,原文

package main

import (
    
"fmt"
    
"io"
    
"net/http"
    
"log"
)

// 获取大小的接口
type Sizer interface {
    Size() int64
}

// hello world, the web server
func HelloServer(w http.ResponseWriter, r *http.Request) {
    
if "POST" == r.Method {
        file, _, err :
= r.FormFile("file")
        
if err != nil {
            http.Error(w, err.Error(), 
500)
            
return
        }
        defer file.Close()
        f,err:
=os.Create("filenametosaveas")
        defer f.Close()
        io.Copy(f,file)
        fmt.Fprintf(w, 
"上传文件的大小为: %d", file.(Sizer).Size())
        
return
    }

    
// 上传页面
    w.Header().Add("Content-Type""text/html")
    w.WriteHeader(
200)
    html :
= `
<form enctype="multipart/form-data" action="/hello" method="POST">
    Send 
this file: <input name="file" type="file" />
    
<input type="submit" value="Send File" />
</form>
`
    io.WriteString(w, html)
}

func main() {
    http.HandleFunc(
"/hello", HelloServer)
    err :
= http.ListenAndServe(":12345", nil)
    
if err != nil {
        log.Fatal(
"ListenAndServe: ", err)
    }
}



大文件上传

关键的不同是io.MultiReader

package main 

import ( 
  
"fmt" 
  
"net/http" 
  
"mime/multipart" 
  
"bytes" 
  
"os" 
  
"io" 
  ) 


func postFile(filename 
string, target_url string) (*http.Response, error) { 
  body_buf :
= bytes.NewBufferString(""
  body_writer :
= multipart.NewWriter(body_buf) 

  
// use the body_writer to write the Part headers to the buffer 
  _, err := body_writer.CreateFormFile("upfile", filename) 
  
if err != nil { 
    fmt.Println(
"error writing to buffer"
    
return nil, err 
  } 

  
// the file data will be the second part of the body 
  fh, err := os.Open(filename) 
  
if err != nil { 
    fmt.Println(
"error opening file"
    
return nil, err 
  } 
  defer fh.Close()
  
// need to know the boundary to properly close the part myself. 
  boundary := body_writer.Boundary()
  close_string :
= fmt.Sprintf("\r\n--%s--\r\n", boundary)
  close_buf :
= bytes.NewBufferString(close_string)
  
// use multi-reader to defer the reading of the file data until writing to the socket buffer. 
  request_reader := io.MultiReader(body_buf, fh, close_buf) 
  fi, err :
= fh.Stat() 
  
if err != nil { 
    fmt.Printf(
"Error Stating file: %s", filename) 
    
return nil, err 
  } 
  req, err :
= http.NewRequest("POST", target_url, request_reader) 
  
if err != nil { 
    
return nil, err 
  } 

  
// Set headers for multipart, and Content Length 
  req.Header.Add("Content-Type""multipart/form-data; boundary=" + boundary) 
  req.ContentLength 
= fi.Size()+int64(body_buf.Len())+int64(close_buf.Len()) 

  
return http.DefaultClient.Do(req) 
}



posted @ 2013-08-27 09:10 oathleo 阅读(3036) | 评论 (0)编辑 收藏

        rune_str := []rune(info)
        fmt.Print("rune_len:" , len(rune_str))
        fmt.Print("string_len:" , len(info))

string 和对应的 rune数组的len不一定相同

如果info是有中文的,则两个length是不一样的,做string处理的时候,要注意

posted @ 2013-08-19 11:31 oathleo 阅读(2750) | 评论 (0)编辑 收藏

xml对应的struct 属性必须大写,否则无法实现!
Code是必须的
package main

import (
    "encoding/xml"
    "fmt"
    "os"
)

type xmldas struct {
    XMLName  xml.Name       `xml:"das"`
    DataPort string         `xml:"DataPort,attr"`
    Desc     string         `xml:"desc,attr"`
    Src      xmlsource      `xml:"source"`
    Dest     xmldestination `xml:"destination"`
}

type xmlsource struct {
    Path  string `xml:"path,attr"`
    Param string `xml:"param,attr"`
}

type xmldestination struct {
    Path  string `xml:"path,attr"`
    Param string `xml:"param,attr"`
}

func main() {
    v := xmldas{DataPort: "8250", Desc: "123"}
    v.Src = xmlsource{Path: "123", Param: "456"}
    v.Dest = xmldestination{Path: "789", Param: "000"}
    output, err := xml.MarshalIndent(v, "  ", "    ")
    if err != nil {
        fmt.Printf("error: %v\n", err)
    }
    os.Stdout.Write([]byte(xml.Header))
    os.Stdout.Write(output)
}

posted @ 2013-08-16 15:53 oathleo 阅读(2687) | 评论 (1)编辑 收藏

将xml文件解析成对应的struct对象是通过xml.Unmarshal来完成的,这个过程是如何实现的?可以看到我们的struct定义后面多了一些类似于xml:"serverName"这样的内容,这个是struct的一个特性,它们被称为 struct tag,它们是用来辅助反射的。


package main

import (
    "encoding/xml"
    "fmt"
    "os"
)

type Servers struct {
    XMLName xml.Name `xml:"servers"`
    Version string   `xml:"version,attr"`
    Svs     []server `xml:"server"`
}

type server struct {
    ServerName string `xml:"serverName"`
    ServerIP   string `xml:"serverIP"`
}

func main() {
    v := &Servers{Version: "1"}
    v.Svs = append(v.Svs, server{"Shanghai_VPN", "127.0.0.1"})
    v.Svs = append(v.Svs, server{"Beijing_VPN", "127.0.0.2"})
    output, err := xml.MarshalIndent(v, "  ", "    ")
    if err != nil {
        fmt.Printf("error: %v\n", err)
    }
    os.Stdout.Write([]byte(xml.Header))

    os.Stdout.Write(output)
}


posted @ 2013-08-12 17:03 oathleo 阅读(1617) | 评论 (0)编辑 收藏

exec卡住了,阻塞调用肯定卡住了
调用Start

func (*Cmd) Run

func (c *Cmd) Run() error

Run starts the specified command and waits for it to complete.

The returned error is nil if the command runs, has no problems copying stdin, stdout, and stderr, and exits with a zero exit status.

If the command fails to run or doesn't complete successfully, the error is of type *ExitError. Other error types may be returned for I/O problems.

func (*Cmd) Start

func (c *Cmd) Start() error

Start starts the specified command but does not wait for it to complete.

posted @ 2013-08-08 09:07 oathleo 阅读(289) | 评论 (0)编辑 收藏

// Description: Golang语法与代码格式速记
// Author: cxy
// Date: 2013-04-01
// Version: 0.3
// TODO 说明


// TODO package

// Go是采用语法解析器自动在每行末尾增加分号,所以在写代码的时候可以把分号省略。
// Go编程中只有几个地方需要手工增加分号,如: for循环使用分号把初始化,条件和遍历元素分开。在一行中有多条语句时,需要增加分号。
// 不能把控制语句(if, for, switch, or select)、函数、方法 的左大括号单独放在一行, 如果你这样作了语法解析器会在大括号之前插入一个分号,导致编译错误。

// 引用包名与导入路径的最后一个目录一致
import "fmt"
import "math/rand"
fmt.Println(rand.Intn(10))    // 0到10之间的非负伪随机数

// 用圆括号组合导入包,这是“factored”导入语句
import ("fmt"; "math")
import (
    "fmt"
    "math"
)
// 导入包可以定义别名,防止同名称的包冲突
import n "net/http"
import (
    控制台 "fmt"
    m "math"
)
控制台.Println(m.Pi)

// 首字母大写的名称是被导出的, 首字母小写的名称只能在同一包内访问(同包跨文件也能访问)
var In int // In is public
var in byte // in is private
var 看不见 string // 看不见 is private
const Com bool = false // Com is public
const 还是看不见 uint8 = 1 // 还是看不见 is private
type Integer int // Integer is public
type ブーリアン *bool // ブーリアン is private
func Export() {// Export is public
func 导入() {// 导入 is private
func (me *Integer) valueOf(s stringint {// valueOf is private
func (i ブーリアン) String() string {// String is public

// Go 的基本类型:
┌──────┬─────────┬────────┬─────────┬───────────┬────────────┐
│ bool │ string  │        │         │           │            │
├──────┼─────────┼────────┼─────────┼───────────┼────────────┤
│ int  │ int8    │ int16  │ int32   │ int64     │            │
│      │         │        │ rune    │           │            │
├──────┼─────────┼────────┼─────────┼───────────┼────────────┤
│ uint │ uint8   │ uint16 │ uint32  │ uint64    │ uintptr    │
│      │ byte    │        │         │           │            │
├──────┼─────────┼────────┼─────────┼───────────┼────────────┤
│      │         │        │ float32 │ float64   │            │
├──────┼─────────┼────────┼─────────┼───────────┼────────────┤
│      │         │        │         │ complex64 │ complex128 │
└──────┴─────────┴────────┴─────────┴───────────┴────────────┘
// byte 是 uint8 的别名
// rune 是 int32 的别名,代表一个Unicode码点

// 变量声明, 使用var关键字    (Go中只能使用var声明变量,无需显式初始化值)
var i int    // i = 0
var s string    // s = ""    (Go中的string不存在nil(null)值,默认零值就是空串 "" 或 ``)
var e error    // e = nil, error是Go的内建接口类型,不是基本类型。

// var 语句声明了一个变量的列表,类型在变量名之后
var a,b,c int    // a = 0, b = 0, c = 0
var (
    a int    // a = 0
    b string    // b = ""
    c uint    // c = 0
)

// 变量定义时初始化赋值,每个变量对应一个值
var a int = 0
var a,b int = 0, 1

// 初始化使用表达式时,可以省略类型,变量从初始值中获得类型
var a = 'A'    // a int32
c := 1 + 2i    // c complex128
var a,b = 0, "B"    // a int, b string
a, b := 0, "B"    // a int, b string
c := `formatted
 string`    // c string

// := 结构不能使用在函数外,函数外的每个语法块都必须以关键字开始

// 常量可以是字符、字符串、布尔或数字类型的值,数值常量是高精度的值
const x int = 3
const (
    a byte = 'A'
    b string = "B"
    c bool = true
    d int = 4
    e float32 = 5.1
    f complex64 = 6 + 6i
)

// 未指定类型的常量由常量值决定其类型
const a = 0    // a int
const (
    b = 2.3    // b float64
    c = true    // c bool
)

// 自动枚举常量 iota
// iota的枚举值可以赋值给数值兼容类型
// 每个常量单独声明时, iota不会自动递增(无意义)
const a int = iota    // a = 0
const b int = iota    // b = 0
const c byte = iota    // c = 0
const d uint64 = iota    // d = 0

// 常量组合声明时, iota每次引用会逐步自增, 初始值为0,步进值为1
const (
    a uint8 = iota    // a = 0
    b int16 = iota    // b = 1
    c rune = iota    // c = 2
    d float64 = iota    // d = 3
    e uintptr = iota    // e = 4
)

// 枚举的常量都为同一类型时, 可以使用简单序列格式.
const (
    a = iota    // a int32 = 0
    b            // b int32 = 1
    c            // c int32 = 2
)

// 枚举序列中的未指定类型的常量会跟随序列前面最后一次出现类型定义的类型
const (
    a byte = iota    // a uint8 = 0
    b                // b uint8 = 1
    c                // c uint8 = 2
    d rune = iota    // d int32 = 3
    e                // e int32 = 4
    f                // f int32 = 5
)

// iota自增值只在一个常量定义组合中有效,跳出常量组合定义后iota值归0
const (
    a = iota    // a int32 = 0
    b            // b int32 = 1
    c            // c int32 = 2
)
const (
    e = iota    // e int32 = 0    (iota重新初始化并自增)
    f            // f int32 = 1
)

// 定制iota序列初始值与步进值 (通过数学公式实现)
const (
    a = (iota + 2) * 3    // a int32 = 0    (a=(0+2)*3) 初始值为6,步进值为3
    b                    // b int32 = 3    (b=(1+2)*3)
    c                    // c int32 = 6    (c=(2+2)*3)
    d                    // d int32 = 9    (d=(3+2)*3)
)

// 数组声明带有长度信息,数组的长度固定
var a [3]int = [3]int{0, 1, 2}    // a = [0 1 2]
var b [3]int = [3]int{}    // b = [0 0 0]
var c = [3]int{}    // c = [0 0 0]
d := [3]int{}    // d = [0 0 0]
fmt.Printf("%T\t%#v\t%d\t%d\n", d, d, len(d), cap(d))    // [3]int    [3]int{0, 0, 0}    3    3
// 使用自动计算数组初始数据的长度
var a = []int{0, 1, 2}
x := [][3]int{{0, 1, 2}, {3, 4, 5}}

// slice 指向数组的值,并且同时包含了长度信息
var a []int
fmt.Printf("%T\t%#v\t%d\t%d\n", a, a, len(a), cap(a))    // []int    []int(nil)    0    0
var a = new([]int)
fmt.Printf("%T\t%#v\t%d\t%d\n", a, a, len(*a), cap(*a))    // *[]int    &[]int(nil)    0    0
var b = make([]int, 0)
fmt.Printf("%T\t%#v\t%d\t%d\n", b, b, len(b), cap(b))    // []int    []int{}    0    0
var c = make([]int, 3, 10)
fmt.Printf("%T\t%#v\t%d\t%d\n", c, c, len(c), cap(c))    // []int    []int{}    3    10
var d []int = []int{0, 1, 2}
fmt.Printf("%T\t%#v\t%d\t%d\n", d, d, len(d), cap(d))    // []int    []int{0, 1, 2}    3    3

// slice 可以重新切片,创建一个新的 slice 值指向相同的数组
s := []int{0, 1, 2, 3, 4}
fmt.Println(s[1,3])    // [1 2]    (截取从开始索引到结束索引-1 之间的片段)
fmt.Println(s[:4])    // [0 1 2 3]
fmt.Println(s[1:])    // [1 2 3 4]
fmt.Println(s[1:1])    // []

// 向slice中添加元素
s := make([]string, 3)
s = append(s, "a")


// map 在使用之前必须用 make 来创建(不是 new);一个值为 nil 的 map 是空的,并且不能赋值
var m map[int]int
m[0] = 0    // × runtime error: assignment to entry in nil map
fmt.Printf("type: %T\n", m)    // map[int]int
fmt.Printf("value: %#v\n", m)    // map[int]int(nil)
fmt.Printf("value: %v\n", m)    // map[]
fmt.Println("is nil: ", nil == m)    // true
fmt.Println("length: ", len(m))    // 0,if m is nil, len(m) is zero.

var m map[int]int = make(map[int]int)
m[0] = 0    // 插入或修改元素
fmt.Printf("type: %T\n", m)        // map[int]int
fmt.Printf("value: %#v\n", m)        // map[int]int(0:0)
fmt.Printf("value: %v\n", m)        // map[0:0]
fmt.Println("is nil: ", nil == m)    // false
fmt.Println("length: ", len(m))        // 1

m = map[int]int{
0:0,
1:1,    // 最后的逗号是必须的
}
m = map[string]S{
"a":S{0,1},
"b":{2,3},    // 类型名称可省略
}
a := m["a"]    // 取值
a, ok := m["a"]    // 取值, 并通过ok(bool)判断key对应的元素是否存在.
delete(m, "a")    // 删除key对应的元素.

// 结构体(struct)就是一个字段的集合, type 定义跟其字面意思相符
type S struct {
    A int
    B, c string
}
type (
    A struct {
        s *S
    }
    B struct {
        A    // 组合
    }
)
// 结构体文法表示通过结构体字段的值作为列表来新分配一个结构体。
var s S = S{0, "1", "2"}
// 使用 Name: 语法可以仅列出部分字段。(字段名的顺序无关。)
var s S = S{A: 0, B: "1"}
var s S = S{}
// 特殊的前缀 & 构造了指向结构体文法的指针。
var s *S = &S{0, "1", "2"}

// 表达式 new(T) 分配了一个零初始化的 T 值,并返回指向它的指针
var s *S = new(S)
// 有指针,但是没有指针运算,结构体字段使用点号来访问
// 结构体字段可以通过结构体指针来访问。通过指针间接的访问是透明的
fmt.Println(s.A)
fmt.Println((*s).A)

// TODO interface
type IF interface {
    a()
}

// TODO chanel

// TODO error

// if 语句 小括号 ( )是可选的,而 { } 是必须的。
if (i < 0)        // 编译错误.
    println(i)

if i < 0        // 编译错误.
    println(i)

if (i < 0) {    // 编译通过.
    println(i)
}
if i < 0 {
    println(i)
else {
    println(i)
}

// 可以在条件之前执行一个简单的语句,由这个语句定义的变量的作用域仅在 if/else 范围之内
if (i := 0; i < 1) {    // 编译错误.
    println(i)
}

if i := 0; (i < 1) {    // 编译通过.
    println(i)
}

if i := 0; i < 0 {    // 使用gofmt格式化代码会自动移除代码中不必要的小括号( )
    println(i)
else if i == 0 {
    println(i)
else {
    println(i)
}

// if语句作用域范围内定义的变量会覆盖外部同名变量,(与方法函数内局部变量覆盖全局变量相同)
a, b := 0, 1
if a, b := 3, 4; a > 1 && b > 2 {
    println(a, b)    // 3 4
}
println(a, b)    // 0 1


// 只有一种循环结构,for 循环。可以让前置、后置语句为空,或者全为空
for i := 0; i < 10; i++ {}
for i := 0; i < 10; {}
for ; i < 10; i++ {}
for ; i < 10; {}
for i < 10 {}
for ; ; {}
for {}

// 小括号 ( )是可选的,而 { } 是必须的。
for (i := 0; i < 10; i++) {}    // 编译错误.
for i := 0; (i < 10); i++ {}    // 编译通过.
for (i < 10) {}    // 编译通过.

// TODO continue

// TODO for range

// TODO switch
// TODO fallthrough break
// TODO type assertion

// TODO select

// TODO goto

// 函数可以没有参数或接受多个参数
func f() {}
func f(a int) {}
func f(a int, b byte) {}
func f(a int) {}    // 可变参数
func f(a int, b bool, c string) {}
// 函数可以返回任意数量的返回值
func f() int {
    return 0
}
func f() intstring {
    return 0, "A"
}
// 函数返回结果参数,可以像变量那样命名和使用
func f() a int, b string {
    a = 1
    b = "B"
    return    // 或者 return a, b
}

// 当两个或多个连续的函数命名参数是同一类型,则除了最后一个类型之外,其他都可以省略
func f(a,b,c int) {}
func f() a,b,c int {}
func f(a,b,c int) x,y,z int {}

// 函数也是值,可以将函数赋值给变量
var f (func(i intint) = func(i intint {
    return i
}
fmt.Println(f(3))    // 3
var f func() int = func() int {
    return 0
}
fmt.Println(f())    // 0
var f func() = func() {}
var f = func() {}
f := func() {}

// TODO defer

// TODO 方法

// TODO 内建函数
append 
cap 
close 
complex 
copy 
delete 
imag 
len 
make 
new 
panic 
print 
println 
real 
recover

// TODO 并发
go func() {}

posted @ 2013-08-02 16:15 oathleo 阅读(2420) | 评论 (0)编辑 收藏

写程序离不了文件操作,这里总结下go语言文件操作。

一、建立与打开

建立文件函数:

func Create(name string) (file *File, err Error)

func NewFile(fd int, name string) *File

具体见官网:http://golang.org/pkg/os/#Create

 

打开文件函数:

func Open(name string) (file *File, err Error)

func OpenFile(name string, flag int, perm uint32) (file *File, err Error)

具体见官网:http://golang.org/pkg/os/#Open

 

二、写文件

写文件函数:

func (file *File) Write(b []byte) (n int, err Error)

func (file *File) WriteAt(b []byte, off int64) (n int, err Error)

func (file *File) WriteString(s string) (ret int, err Error)

具体见官网:http://golang.org/pkg/os/#File.Write 

写文件示例代码:

package main import (         "os"         "fmt" ) func main() {         userFile := "test.txt"         fout,err := os.Create(userFile)         defer fout.Close()         if err != nil {                 fmt.Println(userFile,err)                 return         }         for i:= 0;i<10;i++ {                 fout.WriteString("Just a test!\r\n")                 fout.Write([]byte("Just a test!\r\n"))         } }

三、读文件

读文件函数:

func (file *File) Read(b []byte) (n int, err Error)

func (file *File) ReadAt(b []byte, off int64) (n int, err Error)

具体见官网:http://golang.org/pkg/os/#File.Read

读文件示例代码:

package main import (         "os"         "fmt" ) func main() {         userFile := "test.txt"         fin,err := os.Open(userFile)         defer fin.Close()         if err != nil {                 fmt.Println(userFile,err)                 return         }         buf := make([]byte, 1024)         for{                 n, _ := fin.Read(buf)                 if 0 == n { break }                 os.Stdout.Write(buf[:n])         } }

四、删除文件

函数:

func Remove(name string) Error

posted @ 2013-08-02 10:43 oathleo 阅读(263) | 评论 (0)编辑 收藏

windows下字节序和网络的相反

func readInt32(conn net.Conn) int32 {
    num_byte := make([]byte, 4)
    conn.Read(num_byte)
    var value int32 = 0
//    //windows
//    byte2 := num_byte[2]
//    byte3 := num_byte[3]
//    num_byte[3] = num_byte[0]
//    num_byte[0] = byte3
//    num_byte[2] = num_byte[1]
//    num_byte[1] = byte2
//    //windows

    
//windows
    num_byte[0],num_byte[1],num_byte[2],num_byte[3] = num_byte[3],num_byte[2],num_byte[1],num_byte[0]

    for i := 0; i < 4; i++ {
        shift := uint32((4 - 1 - i) * 8)
        value = value + (int32(num_byte[i])&0x000000FF)<<shift
    }
    return value
}

posted @ 2013-08-02 10:13 oathleo 阅读(494) | 评论 (0)编辑 收藏

golang socket 读取长数据

 1 func read(conn net.Conn, length int) ([]byte, error) {
 2     data := make([]byte, length)
 3     buf_size := 8
 4     buf := make([]byte, buf_size)
 5     i := 0
 6     for {
 7         if length < buf_size {
 8             remain := make([]byte, length)
 9             _, err := conn.Read(remain)
10             if err != nil {
11                 return nil, err
12             }
13             copy(data[i:(i+length)], remain[:])
14             return data, nil
15         } else {
16             _, err := conn.Read(buf)
17             if err != nil {
18                 return nil, err
19             }
20             copy(data[i:(i+buf_size)], buf[:])
21             i += buf_size
22         }
23         length -= buf_size
24     }
25     return data, nil
26 }

上面的 _, err := conn.Read(buf) 不能确保读完,所以修复成下面的代码
func read(conn net.Conn, length int) ([]byte, error) {
    data := make([]byte, length)
    buf_size := 1024
    buf := make([]byte, buf_size)
    i := 0
    for {
        if length < buf_size {
            if length == 0 {
                return data, nil
            }
            remain := make([]byte, length)
            r, err := conn.Read(remain)
            if err != nil {
                return nil, err
            }
            copy(data[i:(i+r)], remain[0:r])
            i += r
            length -= r
        } else {
            r, err := conn.Read(buf)
            if err != nil {
                return nil, err
            }
            copy(data[i:(i+r)], buf[0:r])
            i += r
            length -= r
        }

    }
    return data, nil
}



posted @ 2013-08-02 10:11 oathleo 阅读(1176) | 评论 (0)编辑 收藏

   118	// Read implements the Conn Read method.
   119	func (c *conn) Read(b []byte) (int, error) {
   120		if !c.ok() {
   121			return 0, syscall.EINVAL
   122		}
   123		return c.fd.Read(b)
   124	}


   b []byte 参数类型 是切片!

初始化

切片可以通过数组来初始化,也可以通过内置函数make()初始化 .初始化时len=cap,在追加元素时如果容量cap不足时将按len的2倍扩容 查看示例代码在线运行示例代码

  • s :=[] int {1,2,3 } 
    直接初始化切片,[]表示是切片类型,{1,2,3}初始化值依次是1,2,3.其cap=len=3
  • s := arr[:] 
    初始化切片s,是数组arr的引用
  • s := arr[startIndex:endIndex] 
    将arr中从下标startIndex到endIndex-1 下的元素创建为一个新的切片
  • s := arr[startIndex:] 
    缺省endIndex时将表示一直到arr的最后一个元素
  • s := arr[:endIndex] 
    缺省startIndex时将表示从arr的第一个元素开始
  • s1 := s[startIndex:endIndex] 
    通过切片s初始化切片s1
  • s :=make([]int,len,cap) 
    通过内置函数make()初始化切片s,[]int 标识为其元素类型为int的切片

posted @ 2013-07-31 16:15 oathleo 阅读(281) | 评论 (0)编辑 收藏

恐慌(Panic)和恢复(Recover)
Go 没有像Java 那样的异常机制,例如你无法像在Java 中那样抛出一个异常。作为替
代,它使用了恐慌和恢复(panic-and-recover)机制。一定要记得,这应当作为最后的
手段被使用,你的代码中应当没有,或者很少的令人恐慌的东西。这是个强大的工具,
明智的使用它。那么,应该如何使用它呢。
下面的描述来自于[7]:
Panic
是一个内建函数,可以中断原有的控制流程,进入一个令人恐慌的流程中。当函
数F 调用panic,函数F 的执行被中断,并且F 中的延迟函数会正常执行,然
后F 返回到调用它的地方。在调用的地方,F 的行为就像调用了panic。这一过
程继续向上,直到程序崩溃时的所有goroutine 返回。
恐慌可以直接调用panic 产生。也可以由运行时错误产生,例如访问越界的数
组。
Recover
是一个内建的函数,可以让进入令人恐慌的流程中的goroutine 恢复过来。recover
仅在延迟函数中有效。
在正常的执行过程中,调用recover 会返回nil 并且没有其他任何效果。如果
当前的goroutine 陷入恐慌,调用recover 可以捕获到panic 的输入值,并且
恢复正常的执行。

posted @ 2013-07-30 10:59 oathleo 阅读(431) | 评论 (0)编辑 收藏

     摘要: o语言从诞生到普及已经三年了,先行者大都是Web开发的背景,也有了一些普及型的书籍,可系统开发背景的人在学习这些书籍的时候,总有语焉不详的感觉,网上也有若干流传甚广的文章,可其中或多或少总有些与事实不符的技术描述。希望这篇文章能为比较缺少系统编程背景的Web开发人员介绍一下goroutine背后的系统知识。1. 操作系统与运行库2. 并发与并行 (Concurrency and Paralleli...  阅读全文

posted @ 2013-07-30 08:58 oathleo 阅读(778) | 评论 (0)编辑 收藏

const Ln2= 0.693147180559945309417232121458\             176568075500134360255254120680009 const Log2E= 1/Ln2 // this is a precise reciprocal const Billion = 1e9 // float constant const hardEight = (1 << 100) >> 97 

根据上面的例子我们可以看到,反斜杠 \ 可以在常量表达式中作为多行的连接符使用。


格式化说明符

在格式化字符串里,%d 用于格式化整数(%x 和 %X 用于格式化 16 进制表示的数字),%g 用于格式化浮点型(%f 输出浮点数,%e 输出科学计数表示法),%0d 用于规定输出定长的整数,其中开头的数字 0 是必须的。

%n.mg 用于表示数字 n 并精确到小数点后 m 位,除了使用 g 之外,还可以使用 e 或者 f,例如:使用格式化字符串 %5.2e 来输出 3.4 的结果为3.40e+00

posted @ 2013-07-30 08:45 oathleo 阅读(175) | 评论 (0)编辑 收藏

包是结构化代码的一种方式:每个程序都由包(通常简称为 pkg)的概念组成,可以使用自身的包或者从其它包中导入内容。

如同其它一些编程语言中的类库或命名空间的概念,每个 Go 文件都属于且仅属于一个包。一个包可以由许多以 .go 为扩展名的源文件组成,因此文件名和包名一般来说都是不相同的。

你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package mainpackage main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。


如果需要多个包,它们可以被分别导入:

import "fmt" import "os" 

或:

import “fmt”; import “os” 

但是还有更短且更优雅的方法(被称为因式分解关键字,该方法同样适用于 const、var 和 type 的声明或定义):

import (     "fmt"     "os" )

可见性规则

当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 private )。


你可以通过使用包的别名来解决包名之间的名称冲突,或者说根据你的个人喜好对包名进行重新设置,如:import fm "fmt"。下面的代码展示了如何使用包的别名:

Example 4.2 alias.go

package main import fm "fmt" // alias3  func main() {     fm.Println("hello, world") }

函数里的代码(函数体)使用大括号 { } 括起来。

左大括号 { 必须与方法的声明放在同一行,这是编译器的强制规定,否则你在使用 gofmt 时就会出现build-error: syntax error: unexpected semicolon or newline before { 这样的错误提示。


一个函数可以拥有多返回值,返回类型之间需要使用逗号分割,并使用小括号 ( ) 将它们括起来,如:func FunctionName (a typea, b typeb) (t1 type1, t2 type2)

posted @ 2013-07-30 08:44 oathleo 阅读(198) | 评论 (0)编辑 收藏


  • Shorthand for writing Vector3(0, 0, 1)
    Vector3(0, 0, 1)的简码,也就是向z轴。
  • Shorthand for writing Vector3(0, 1, 0)
    Vector3(0, 1, 0)的简码,也就是向y轴。
  • Shorthand for writing Vector3(1, 0, 0)
    Vector3(1, 0, 0)的简码,也就是向x轴。 
transform.Rotate(Vector3.forward *Time.deltaTime * RotateSpeed);


Vector3.forward代表以Z轴为轴旋转

Z轴 forward 代表往前
X轴代表右 right
Y轴代表往上up



posted @ 2013-07-04 17:04 oathleo 阅读(286) | 评论 (0)编辑 收藏

Java路径中的空格问题
1、 URLTest.class.getResource("/").getPath();
    URLTest.class.getResource("/").getFile();
    URLTest.class.getClassLoader().getResource("").getPath();
    Thread.currentThread().getContextClassLoader().getResource("").getPath();等多种相似方式获得的路径,不能被FileReader()和FileWriter()直接应用,原因是URL对空格,特殊字符(%,#,[]等)和中文进行了编码处理。如果文件中URLTest.class.getResource("/").getPath();必须以"/"开头然后再加文件名,而URLTest.class.getClassLoader().getResource("").getPath();不用加"/"可以直接添加文件名。

路径中包含空格时,如果空格变为"%20"有如下处理方法:
1)使用repaceAll("%20",' ')替换,但只能解决空格问题,如果路径中包含其他特殊字符和中文就不能解决问题。
2)使用URLDecoder.decode(str,"UTF-8")解码,但是只能解决一部分,若路径中含有+,也是不能解决的,原因是URL并不是完全用URLEncoder.encode(str,"UTF-8")编码的,+号被解码后,则变成空格。
3)解决所有的问题,用URLTest.class.getClassLoader().getResource("").toURI().getPath();,但是需要处理URISyntaxException异常,比较麻烦一些。

2、new URL();的参数可以为正确的URI,或者为URI格式的字符串;若字符串是非完整的URI格式,则创建失败。java.net.URI返回的路径中的空格以“空格”的形式出现方法为Thread.currentThread().getContextClassLoader().getResource("").toURI().getPath();但是Thread.currentThread().getContextClassLoader().getResource("").toURI().toString();则会以“%20”的形式出现。java.net.URL返回的一切路径中的空格都是以“%20”的形式出现。URL/URI返回的路径分隔符都是“/”(控制台输出"/")。


3、new File(String filePath);接受正确URI格式的参数和带“空格”(非%20)的正确相对/绝对字符串路径,否则即使给的路径是正确的也会出现找不到文件的异常。File返回的路径分隔符都为“\”(控制台输出"\"),对于存在的文件返回的路径字符串,空格都以"空格"出现,而不存在的路径new出的file,getPath()返回的路径中的空格,仍是new File(String filePath)的参数中原有的形式,即若filePath中是空格的getPath()返回的仍是空格,是“%20”的仍是“%20”。File.toURI() 会将file的路径名中的“空格”转化为“%20”,然后在路径前加protocol:"file:/",而File.toURL()只会在file路径 前简单的加上protocol:"file:/",而不会将“空格”转化为“%20”,原来的无论是“空格”还是“%20”都只会原样保留。


实际使用中遇到的问题总结如下:
1、相对路径(即相对于当前用户目录的相对路径)均可通过以下方式获得(不论是一般的java项目还是web项目) String relativelyPath=System.getProperty("user.dir"); 对于一般的java项目中的文件是相对于项目的根目录,而对于web项目中的文件路径,可能是服务器的某个路径,同时不同的web服务器也不同 (tomcat是相对于 tomcat安装目录\bin)。为此,个人认为,在web项目中,最好不要使用“相对于当前用户目录的相对路径”。然而默认情况下,java.io 包中的类总是根据当前用户目录来分析相对路径名。此目录由系统属性 user.dir 指定,通常是 Java 虚拟机的调用目录。这就是说,在使用java.io包中的类时,最好不要使用相对路径。否则,虽然在SE程序中可能还算正常,但是到了EE程序中,可能会出现问题。

2、web项目根目录获取
1)建立一个servlet,在其init()方法中添加如下代码
ServletContext context = this.getServletContext(); 
String strs = context.getRealPath("/"); 
2)利用httpServletRequest,得到相应的项目路径
String pathUrl = request.getSession().getServletContext().getRealPath("/");

posted @ 2013-05-27 17:00 oathleo 阅读(301) | 评论 (0)编辑 收藏

iosched 里的DashboardLayout 在scroll里好像有点问题,一个类就事情,没时间调了,自己写了个

1 1 import android.content.Context;
 2 import android.view.View;
 3 import android.widget.LinearLayout;
 4 
 5 public class AutoTableLayout extends LinearLayout {
 6 
 7     private int mMaxChildWidth = 0;
 8     private int mMaxChildHeight = 0;
 9 
10     //列数
11     private int column = 0;
12     //是否自定义列数
13     private boolean isCustomColumn = false;
14     
15     public AutoTableLayout(Context context) {
16         super(context, null);
17     }
18 
19     public AutoTableLayout(Context context, int col) {
20         super(context, null);
21         column = col;
22         isCustomColumn = true;
23     }
24 
25     @Override
26     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
27         mMaxChildWidth = 0;
28         mMaxChildHeight = 0;
29 
30         final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST);
31         final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST);
32 
33         final int count = getChildCount();
34         for (int i = 0; i < count; i++) {
35             final View child = getChildAt(i);
36             if (child.getVisibility() == GONE) {
37                 continue;
38             }
39 
40             child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
41 
42             mMaxChildWidth = Math.max(mMaxChildWidth, child.getMeasuredWidth());
43             mMaxChildHeight = Math.max(mMaxChildHeight, child.getMeasuredHeight());
44         }
45 
46         int width = resolveSize(mMaxChildWidth, widthMeasureSpec);
47 
48         // 每行个数
49         if (!isCustomColumn) {
50             column = (int) Math.floor((double) width / mMaxChildWidth);
51         }
52          
53         int row = (int) Math.ceil((double) count / column);
54 
55         int height = mMaxChildHeight * row;
56         setMeasuredDimension(width, height);
57 
58     }
59 
60     @Override
61     protected void onLayout(boolean changed, int l, int t, int r, int b) {
62         int width = r - l;
63         int height = b - t;
64         
65         final int count = getChildCount();
66         
67         int left, top;
68         int col, row;
69         
70         int gap = (width - column * mMaxChildWidth) / (column + 1);
71         
72         for (int i = 0; i < count; i++) {
73             final View child = getChildAt(i);
74 
75             row = (int) Math.floor( (double)i / column);
76             col = i % column;
77 
78             left = l + (col + 1) * gap + col * mMaxChildWidth;
79             top = t + row * mMaxChildHeight;
80             
81             
82             child.layout(left, top, left + mMaxChildWidth, top + mMaxChildHeight);
83         }
84     }
85 
86 }

posted @ 2013-03-12 13:33 oathleo 阅读(1553) | 评论 (0)编辑 收藏

Objective-C 类声明,定义,实例,初始化

Objective-C中,调用方法被称为发送消息 ,通知对象执行某种操作。语法如下:[shape draw]

一、类声明(接口):

@interface TestCoop : NSObject {
    int iMonth;
    int iYear;
    int iDay;
}

- (void) setYear: (int) iYear;
- (void) primalSetData: (int)iYear :(int)iMonth :(int)iDay;
- (void) setData: (int)Year iMonth:(int)iMonth iDay:(int)iDay;
- (void) displayDateInfo;

@end

1、前面的短线/- 表示这是Objective-C方法的声明,用来区分函数原型(C语言中)与(Objective—C中)方法声明的方式。短线后面是方法的返回类型/比如( void) ,位于圆括号中。

1.1 注意,方法的声明在括号后面,@end之前 {}区域里只有变量的定义,这点和C++很不一样。

2、返回类型后面自然是函数名字,和C语言一样的,不同的是参数声明方法

2.1、无参数的函数后面不需要加括号和冒号,直接是函数名结束加分号,比如: - (void) displayDateInfo;

2.2、有参数的后面加冒号和参数类型名字,比如:

- (void) setDay: (int) iDay; //单个参数
- (void) primalSetData: (int)iYear :(int)iMonth :(int)iDay;//多个参数

objective还提供一种中缀符的语法,方法的名称和参数都是和在一起的:

参数前面多加一个标识符,通常和变量名一样,如下:

- (void) setData: (int)Year iMonth:(int)iMonth iDay:(int)iDay;//多个参数

苹果推荐使用第二种方法,虽然繁琐点。

二、类实现:

@implementation TestCoop
- (void) displayDateInfo{
    NSLog(@"Today is: %d.%d.%d\n", iYear, iMonth, iDay);
}

- (void) setYear: (int) year{
    iYear = year;
}

- (void) primalSetData: (int)year :(int)month :(int)day{
    iYear = year;
    iMonth = month;
    iDay = day;    
}

- (void) setData: (int)year iMonth:(int)month iDay:(int)day{
    iYear = year;
    iMonth = month;
    iDay = day;
}

1、注意:类的方法实现部分函数参数不能和声明部分一样,就是不能和类变量同名,否则会隐藏初始变量。

比如:- (void) setYear: (int) year{ //right
    iYear = year;
}

改成和声明时一样的话,如下:- (void) setYear: (int) iYear{ //error
    iYear = iYear;
}

明显出问题了,xcode编译会报warnging,就是初始变量被隐藏,其实本质就是变量作用域的问题,你局部变量和类变量名字一样,

当然访问不到了。

根由:声明的时候Objective-C喜欢用类变量的名字来代替函数参数名,不知道为啥,真是个纠结的问题。(要是从声明的时候就不用,就OK了,也不用到定义时再去改,不知道苹果那样做的理由)。

三、实例化对象

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    // insert code here...
    //NSLog(@"%d-,%s %@\n", 12, "hel123lo", @"123");
    
    TestCoop *ptest = [TestCoop new]; 
    [ptest primalSetData :2009 :03 :05];
    [ptest displayDateInfo];
    [ptest setData:2010 iMonth:06 iDay:06];
    [ptest displayDateInfo];
    [ptest setYear:1987];
    [ptest displayDateInfo];
    [pool drain];
    return 0;
}

运行后会输出如下信息:

Today is: 2009.3.5

Today is: 2010.6.6

Today is: 1987.6.6

通过向需要创建对象的类发送new消息,可以创建各个对象。

然后向对象发送各种消息来操作对象。

//类的初始化

不过,cocoa习惯使用alloc和init来创建对象,而不是new

使用alloc来分配内存,并使用init来初始化,会将这块内存全部清0,bool型为NO,int型为0,指针为nil

上面的创建对象代码改成如下:

TestCoop *ptest = [[TestCoop alloc] init];

 

posted @ 2013-02-26 10:30 oathleo 阅读(619) | 评论 (0)编辑 收藏

解决刷新rom后log功能默认屏蔽问题:
Logger
C:\Users\Leo>adb shell
shell@android:/ $ su
su
 
1|shell@android:/ # mount -o remount, rw /system
mount -o remount, rw /system
shell@android:/ # echo ANDROIDLOGGER >> /system/etc/tweaks.conf
echo ANDROIDLOGGER >> /system/etc/tweaks.conf
shell@android:/ # mount -o remount, ro /system
mount -o remount, ro /system
shell@android:/ #

posted @ 2013-02-21 13:47 oathleo 阅读(283) | 评论 (0)编辑 收藏

一.Java源码在用Ant脚本打成jar之后,再被调用时,Eclipse代码提示中方法的参数名称是无意义的(arg0、arg1)

解决办法:使用ibm/eclipse的编译器

二.使用ibm/eclipse的编译器也会有一些方法 参数语法提示名称是无意义
估计可能是ibm的java编译器的bug, 
只要方法中含有synchronized 代码块
就会导致这种情况
有兴趣的同学可以研究下

解决办法:把相应代码块提取到方法,让方法synchronized



posted @ 2013-01-17 09:39 oathleo 阅读(2088) | 评论 (1)编辑 收藏

MappedByteBuffer是java nio引入的文件内存映射方案,读写性能极高。NIO最主要的就是实现了对异步操作的支持。其中一种通过把一个套接字通道(SocketChannel)注册到一个选择器(Selector)中,不时调用后者的选择(select)方法就能返回满足的选择键(SelectionKey),键中包含了SOCKET事件信息。这就是select模型。
    SocketChannel的读写是通过一个类叫ByteBuffer(java.nio.ByteBuffer)来操作的.这个类本身的设计是不错的,比直接操作byte[]方便多了. ByteBuffer有两种模式:直接/间接.间接模式最典型(也只有这么一种)的就是HeapByteBuffer,即操作堆内存 (byte[]).但是内存毕竟有限,如果我要发送一个1G的文件怎么办?不可能真的去分配1G的内存.这时就必须使用"直接"模式,即 MappedByteBuffer,文件映射.
     先中断一下,谈谈操作系统的内存管理.一般操作系统的内存分两部分:物理内存;虚拟内存.虚拟内存一般使用的是页面映像文件,即硬盘中的某个(某些)特殊的文件.操作系统负责页面文件内容的读写,这个过程叫"页面中断/切换". MappedByteBuffer也是类似的,你可以把整个文件(不管文件有多大)看成是一个ByteBuffer.MappedByteBuffer 只是一种特殊的 ByteBuffer ,即是ByteBuffer的子类。 MappedByteBuffer 将文件直接映射到内存(这里的内存指的是虚拟内存,并不是物理内存)。通常,可以映射整个文件,如果文件比较大的话可以分段进行映射,只要指定文件的那个部分就可以。

三种方式:
              FileChannel提供了map方法来把文件影射为内存映像文件: MappedByteBuffer map(int mode,long position,long size); 可以把文件的从position开始的size大小的区域映射为内存映像文件,mode指出了 可访问该内存映像文件的方式:READ_ONLY,READ_WRITE,PRIVATE.                     
a. READ_ONLY,(只读): 试图修改得到的缓冲区将导致抛出 ReadOnlyBufferException.(MapMode.READ_ONLY)
 b. READ_WRITE(读/写): 对得到的缓冲区的更改最终将传播到文件;该更改对映射到同一文件的其他程序不一定是可见的。 (MapMode.READ_WRITE)
c. PRIVATE(专用): 对得到的缓冲区的更改不会传播到文件,并且该更改对映射到同一文件的其他程序也不是可见的;相反,会创建缓冲区已修改部分的专用副本。 (MapMode.PRIVATE)

三个方法:

a. fore();缓冲区是READ_WRITE模式下,此方法对缓冲区内容的修改强行写入文件
b. load()将缓冲区的内容载入内存,并返回该缓冲区的引用
c. isLoaded()如果缓冲区的内容在物理内存中,则返回真,否则返回假

三个特性:

    调用信道的map()方法后,即可将文件的某一部分或全部映射到内存中,映射内存缓冲区是个直接缓冲区,继承自ByteBuffer,但相对于ByteBuffer,它有更多的优点:

a. 读取快
b. 写入快
c. 随时随地写入

下面来看代码:

package study;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class MapMemeryBuffer {

    public static void main(String[] args) throws Exception {
        ByteBuffer byteBuf = ByteBuffer.allocate(1024 * 14 * 1024);
        byte[] bbb = new byte[14 * 1024 * 1024];
        FileInputStream fis = new FileInputStream("e://data/other/UltraEdit_17.00.0.1035_SC.exe");
        FileOutputStream fos = new FileOutputStream("e://data/other/outFile.txt");
        FileChannel fc = fis.getChannel();
        long timeStar = System.currentTimeMillis();// 得到当前的时间
        fc.read(byteBuf);// 1 读取
        //MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
        System.out.println(fc.size()/1024);
        long timeEnd = System.currentTimeMillis();// 得到当前的时间
        System.out.println("Read time :" + (timeEnd - timeStar) + "ms");
        timeStar = System.currentTimeMillis();
        fos.write(bbb);//2.写入
        //mbb.flip();
        timeEnd = System.currentTimeMillis();
        System.out.println("Write time :" + (timeEnd - timeStar) + "ms");
        fos.flush();
        fc.close();
        fis.close();
    }

}

运行结果:
14235
Read time :24ms
Write time :21ms
我们把标注1和2语句注释掉,换成它们下面的被注释的那条语句,再来看运行效果。
14235
Read time :2ms
Write time :0ms
可以看出速度有了很大的提升。MappedByteBuffer的确快,但也存在一些问题,主要就是内存占用和文件关闭等不确定问题。被MappedByteBuffer打开的文件只有在垃圾收集时才会被关闭,而这个点是不确定的。在javadoc里是这么说的:
A mapped byte buffer and the file mapping that it represents remain valid until the buffer itself 
is garbage-collected.

这里提供一种解决方案:
AccessController.doPrivileged(new PrivilegedAction() {
  public Object run() {
    try {
      Method getCleanerMethod = buffer.getClass().getMethod("cleaner", new Class[0]);
      getCleanerMethod.setAccessible(true);
      sun.misc.Cleaner cleaner = (sun.misc.Cleaner)
      getCleanerMethod.invoke(byteBuffer, new Object[0]);
      cleaner.clean();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }
});

posted @ 2013-01-05 10:49 oathleo 阅读(1117) | 评论 (0)编辑 收藏

NIO

     摘要: java.nio.ByteBuffer-------------------------------Capacity 缓冲区最大容量Limit 当前最大使用量,或者说是有效数据的EOF位置。Position 指向当前位置的指针-----------------------------------假设一个缓冲区容量是10,开始指针指向0,即position=0。然后写入...  阅读全文

posted @ 2013-01-04 11:18 oathleo 阅读(268) | 评论 (0)编辑 收藏

下面2段代码是测试代码,IE9下测试
都有泄漏,非IE浏览器没问题。困惑


每秒eval,400个方法调用;200多K的内存泄漏,

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>eval 测试</title>
        <script>

    
var afunction = function(_name,_mask){
         
return false;
    }
    
    
var bfunction = function(_color){
    }
    
    
var cfunction = function(_color){
    }

var _action = function(){

    
for(var i=0;i<40;i++){
    
     
         
var _script = "if(afunction('111','222')) bfunction('0xCDCD00'); else if(afunction('111','222')) bfunction('0xCDCD00'); else if(afunction('111','222')) bfunction('0xCDCD00'); else if(afunction('111','222')) bfunction('0xCDCD00'); else if(afunction('111','222')) bfunction('0xCDCD00');";
         _script 
+= "if(afunction('222','333')) cfunction('0xCDCD00'); else if(afunction('222','333')) cfunction('0xCDCD00');  else if(afunction('222','333')) cfunction('0xCDCD00'); else if(afunction('222','333')) cfunction('0xCDCD00'); else if(afunction('222','333')) cfunction('0xCDCD00');";
         
var _func = new Function(_script);
          _func();
        
    }
 
}

window.onload 
= function() {
    setInterval(_action,
1000);
};

</script>

    </head>
    <body>
        
    </body>
</html>
2.



<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>eval 测试</title>
        <script>

var _action = function(){

    
var afunction = function(_name,_mask){
         
return false;
    }
    
    
var bfunction = function(_color){
    }
    
    
var cfunction = function(_color){
    }
    
    
for(var i=0;i<40;i++){
         
var _script = "if(afunction('111','222')) bfunction('0xCDCD00'); else if(afunction('111','222')) bfunction('0xCDCD00'); else if(afunction('111','222')) bfunction('0xCDCD00'); else if(afunction('111','222')) bfunction('0xCDCD00'); else if(afunction('111','222')) bfunction('0xCDCD00');";
         _script 
+= "if(afunction('222','333')) cfunction('0xCDCD00'); else if(afunction('222','333')) cfunction('0xCDCD00');  else if(afunction('222','333')) cfunction('0xCDCD00'); else if(afunction('222','333')) cfunction('0xCDCD00'); else if(afunction('222','333')) cfunction('0xCDCD00');";
         eval(_script);
    }
 
}

window.onload 
= function() {
    setInterval(_action,
1000);
};

</script>

    </head>
    <body>
        
    </body>
</html>

posted @ 2012-08-15 16:53 oathleo 阅读(1722) | 评论 (1)编辑 收藏

HTML5的canvas需要firefox, safari, chrome, opera或者IE9. 对低于9的IE版本,该游戏使用ExplorerCanvas库来模拟,虽然视觉效果差一些但也可以使用.简单写写canvas兼容低版本(<9)IE的经验.

Canvas是HTML5新增加的元素, 可以方便的画图. Firefox, safari, chrome, opera的最近版本以及IE9都支持. IE8及以下不支持HTML5, 但是ExplorerCanvas库(http://excanvas.sourceforge.net/)调用IE内部功能提供了几乎相同的API. ExplorerCanvas不支持字体, 所以为了使用文字, 还需要使用canvas-text库(http://code.google.com/p/canvas-text/).

使用ExplorerCanvas及canvas-text, 需要在HTML header里包括:  
  <script type="text/javascript" src="javascript/excanvas/excanvas.js"></script>
  <script type="text/javascript" src="javascript/excanvas/canvas.text.js"></script>
  <script type="text/javascript" src="javascript/excanvas/faces/optimer-normal-normal.js"></script>

如果同一页HTML要兼容低版本IE和其它支持HTML5的浏览器, 可以用如下的语法选择性加入低版本IE需要的部分:  
  <!--[if IE]>
  <script type="text/javascript" src="javascript/excanvas/excanvas.js"></script>
  <script type="text/javascript" src="javascript/excanvas/canvas.text.js"></script>
  <script type="text/javascript" src="javascript/excanvas/faces/optimer-normal-normal.js"></script>
  <![endif]-->  

下面的部分包括在HTML的BODY里, canvas元素的后面:
  <!--[if ! IE]>--> <script type="text/javascript" src="javascript/mycode.js"></script> <!--<![endif]-->
  <!--[if IE]> <script type="text/javascript" src="javascript/mycode.ie.js"></script> <![endif]-->

下面是mycode.ie.js不同于mycode.js的部分.  

1. addEventListener -> attachEvent
别的浏览器用addEventListener. IE用attachEvent. 对于事件名, IE要多加一个"on". 比如IE用"onmousedown", 别的浏览器用"mousedown".  

2. 为了兼容手机, 鼠标事件为触屏事件取代, 所以mousedown/mouseup/mousemove改用如下的事件: touchstart/touchend/touchmove.

3. event.pageX -> pageX(event)
别的浏览器直接用event.pageX. IE完全不同, 所以另外自定义一个函数pageX(event)来达到相同效果:
function pageX(e) {
  if (e.pageX) return e.pageX;
  else if (e.clientX)
  return e.clientX + (document.documentElement.scrollLeft ?
  document.documentElement.scrollLeft : document.body.scrollLeft);
  else return null;
}

4. in event handlers, this.offsetLeft/Top -> vCanvas.offsetLeft/Top
别的浏览器this指代事件发生的元素, 这里是canvas. IE的this指代window, 所以要专门指明vCanvas.offsetLeft/Top.

5. onmouseout在IE里行为不稳定, 所以应避免使用, 或者改用onmouseleave.

6. 辨认鼠标的左右键, 别的浏览器用event.which, IE用event.button.

7. DIV元素的半透明效果,别的浏览器用 style="background-color:rgba(255,255,255,0.75);", IE用style="background-color: white; opacity:0.75;filter:alpha(opacity=75);"  

8. 定义元素高度和宽度时,IE常要指明单位px,别的浏览器不用. 比如:
  <!--[if ! IE]>-->  
  <table id="Toolbar" border="0" cellpadding="2" cellspacing="0" bgcolor="#ffffff" style="font-size:12px; width:320;">
  <!--<![endif]-->

  <!--[if IE]>  
  <table id="Toolbar" border="0" cellpadding="2" cellspacing="0" bgcolor="#ffffff" style="font-size:12px; width:320px;">
  <![endif]-->

9. 另外IE引擎慢一些, 所以别的浏览器里运行流畅的canvas事件, 在IE里要简略一些来保证运行速度.

posted @ 2012-08-10 11:52 oathleo 阅读(481) | 评论 (0)编辑 收藏

1.目前使用全刷策略,即每秒全刷整张图(xml格式),复杂图形通讯量在30K左右(gzip压缩),桌面浏览器:FF、Google Chrome 运行CPU占用3%左右
2.移动设备测试效果同1
3.桌面IE8下使用excanvas插件,可以打开看但效率很低,无法实现秒级刷新(IE9下效果未知)
 
使用canvas已可开发出非IE浏览器实时图形,适合桌面和移动系统
桌面IE8及以下,仍然没有高效的图形展示方案
如客户端局部刷新,应该能提高通讯、展示效率,但大大提升开发难度,但如想IE8下实现秒级刷新,估计只能依靠优秀的局部刷新技术来实现



2

posted @ 2012-08-03 08:56 oathleo 阅读(1095) | 评论 (0)编辑 收藏

1.canvas draw椭圆 通过 scale 
2.arc 前必须beginPath 
        canvas_context.save();
        canvas_context.scale(1, _scale);
        canvas_context.beginPath();
        canvas_context.arc(_centerX, _centerY, parseInt(_bounds[2] * 0.5), 0,(Math.PI/180)*360, true);
     
        canvas_context.restore();

posted @ 2012-07-31 10:21 oathleo 阅读(821) | 评论 (0)编辑 收藏

visio本身的格式不用浪费时间了,太复杂,即使是它明文的,读起来也是吃力的要命

所以嘛,绕着来,visio可以转svg,svg这么通用的格式,就好读取多了,可以自己读,也可以找第三方

这里使用最常见的batik,读的真心不错!自己再从batik里面读取,方便多了

因为是公司的东西,所以只能发点截图了

visio原图



读取batik里的对象,再转格式后展示的效果


posted @ 2012-03-23 16:54 oathleo 阅读(2005) | 评论 (0)编辑 收藏

友人出的新书:恭喜并强烈推荐下 《Ext江湖》,
http://product.china-pub.com/194667

摘录一段别人的评价:
本书每一章节思路清晰、重点突出,文风朴实、目标明确,具有很强的针对性、实用性;本书每一样例以开发者角度,循序渐进,从浅入深一步一步娓娓道来;Ext江湖,处处充满惊喜,处处埋藏绝技,它就是欧莱雅,你值得拥有!

posted @ 2011-12-22 13:47 oathleo 阅读(1733) | 评论 (4)编辑 收藏

 
仿射变换可以理解为
・对坐标进行放缩,旋转,平移后取得新坐标的值。
・经过对坐标轴的放缩,旋转,平移后原坐标在在新坐标领域中的值。
 
如上图所示,XY坐标系坐标轴旋转θ,坐标原点移动(x0,y0)。
XY坐标系中的坐标(X,Y),则求新坐标系xy中的坐标值的方程组为:
 
X = X・cosθ - Y・sinθ + x0
Y = X・sinθ + Y・cosθ + y0
 
写成矩阵形式为
 
| x |              | cosθ   sinθ |   | x0 |
|   | = | X Y | * |               | + |    |
| y |              | -sinθ cosθ |   | y0 |
 
为将原点移动的值放入矩阵,则可以加入一个不影响原方程组的解的冗余方程。于是可以写成
 
X = X・cosθ - Y・sinθ + x0
Y = X・sinθ + Y・cosθ + y0
1 = X・0     + Y・0     + 1
 
写成矩阵形式为
| x |                 | cosθ   sinθ   0|
| y | = | X Y 1 | * | -sinθ cosθ   0|
| 1 |                 | x0      y0      1|
 
这个矩阵就是Helmert变换矩阵。
 
考虑到新坐标系对于原坐标系在x,y两个坐标轴上的放缩率,可分别表示为λx和λy,则Helmert变换方程组可以修改为
 
X = (λx)X・cosθ - (λy)Y・sinθ + x0
Y = (λx)X・sinθ + (λy)Y・cosθ + y0
 
同样按照前述方法写成三阶矩阵为
 
| x |                 | (λx)cosθ   (λx)sinθ   0|
| y | = | X Y 1 | * | (λy)-sinθ (λy)cosθ   0|
| 1 |                 |  x0           y0          1|
 
这个矩阵就是affine变换矩阵,仿射矩阵。

posted @ 2011-12-20 11:21 oathleo 阅读(390) | 评论 (0)编辑 收藏

abstract 该类

posted @ 2011-12-12 16:57 oathleo 阅读(254) | 评论 (0)编辑 收藏

12月4日傍晚,中国农业大学经济管理学院副教授葛长银发了一条微博,“请大家注意年终奖临界点,宁可少千元不要超一元”,并举出例子,
比如年终奖为 18000元,那么要缴纳540元的税,
如果按年终奖为18001元,则需要多纳税1155.1元,即1695.1元。
同理,54001元的年终奖比 54000元多纳4950.2元;
发108001元比108000元多纳24390.25元;
发420001元比420000元多纳19250.3元;
发 660001元比660000元多纳30250.35元;
发960001元比960000元多纳88000.45元。

posted @ 2011-12-07 13:52 oathleo 阅读(305) | 评论 (1)编辑 收藏

1.遇到的问题:flex全屏下,使用
http://www.blogjava.net/oathleo/archive/2011/11/29/365125.html
的方法,无法解决右键菜单自定义了

2.解决的问题
flex里使用了flex ---》eval js  ---》回调flex对象注册方法
其中js回调 flex对象上注册方法时
IE下可以直接使用  objectID.方法名  来调用,FF下不行

原来FF下是使用document.getElementById('"+ objectID +"') 来找到flex对象的,IE也兼容该方法

posted @ 2011-12-05 17:09 oathleo 阅读(1457) | 评论 (2)编辑 收藏

实现第一步,屏蔽默认菜单后:
http://www.blogjava.net/oathleo/archive/2011/11/28/365009.html
接下来就是实现自定义菜单了

先看结果:


就实现了两层,没有考虑多层菜单,菜单项用简单的button实现,感觉还行

主要的代码如下:
        private var titleWindow:Group;
        
private var pointNameGroupMenu:VGroup;
        
private var secondMenu:VGroup;
        
        
public function hiddenPopupMenu():void{
            
if(titleWindow != null){
                PopUpManager.removePopUp(titleWindow);
                pointNameGroupMenu 
= null;
                secondMenu 
= null;
            }
        }
        
private function showPopupMenu(allInterestPointNames:HashSet,physical_x:int,physical_y:int):void {
             
if(allInterestPointNames.size == 1){
                 titleWindow 
= prepareDetailMenu(physical_x,physical_y);
             }
else{
                 titleWindow 
= new Group();   
                 titleWindow.x 
= physical_x;
                 titleWindow.y 
= physical_y;
                 
                 pointNameGroupMenu 
= new VGroup();   
                 pointNameGroupMenu.gap 
= 0;
                 pointNameGroupMenu.horizontalAlign 
= "contentJustify";
                 
                 titleWindow.addElement(pointNameGroupMenu);
                 allInterestPointNames.forEach(function(_node:String):
void{
                     var _point_name:Button 
= new Button();
                     _point_name.label 
= _node;
                     pointNameGroupMenu.addElement(_point_name);
                     _point_name.addEventListener(MouseEvent.MOUSE_OVER,showSecondMenu);
                 });
             }
             PopUpManager.addPopUp(titleWindow, viewer, 
false);   
        }
        
        
private function prepareDetailMenu(_x:int,_y:int):VGroup{
            var detailGroup:VGroup 
= new VGroup();   
            detailGroup.gap 
= 0;
            detailGroup.horizontalAlign 
= "contentJustify";
            detailGroup.x 
= _x;
            detailGroup.y 
= _y;
            
            var _button_point_info:Button 
= new Button();
            _button_point_info.label 
= ResourceUtil.getString("gview_popup_pointinfo");
            detailGroup.addElement(_button_point_info);
            
            var _button_point_trend:Button 
= new Button();
            _button_point_trend.label 
= ResourceUtil.getString("gview_popup_trend");
            detailGroup.addElement(_button_point_trend);
            
            
return detailGroup;
        }
        
        
private function showSecondMenu(evt:MouseEvent):void {
            var _evt_target:Button 
= Button(evt.target);
            var _index:
int = pointNameGroupMenu.getChildIndex(_evt_target);
            
if(secondMenu == null){
                secondMenu 
= prepareDetailMenu(pointNameGroupMenu.measuredWidth,_evt_target.height * _index);
                titleWindow.addElement(secondMenu);
            }
else{
                secondMenu.y 
= _evt_target.height * _index;
            }
        }

posted @ 2011-11-29 16:35 oathleo 阅读(1515) | 评论 (0)编辑 收藏

不要试图改变flash插件自带的右键菜单,没有办法解决
自带的右键菜单坏处大大
1.不能去掉默认的几项(关于)
2.不能实现多层

只能使用js屏蔽掉默认右键事件,然后弹出自己的右键菜单来实现
搜索了半天,找了个可行的方案,实现第一步:
1.屏蔽默认菜单,并响应右键事件

var RightClick = {
    
/**
     *  Constructor
     
*/ 
    init: function () {
        
this.FlashObjectID = "customRightClick";
        
this.FlashContainerID = "flashcontent";
        
this.Cache = this.FlashObjectID;
        
if(window.addEventListener){
             window.addEventListener(
"mousedown"this.onGeckoMouse(), true);
        } 
else {
            document.getElementById(
this.FlashContainerID).onmouseup = function() { document.getElementById(RightClick.FlashContainerID).releaseCapture(); }
            document.oncontextmenu 
= function(){ if(window.event.srcElement.id == RightClick.FlashObjectID) { return false; } else { RightClick.Cache = "nan"; }}
            document.getElementById(
this.FlashContainerID).onmousedown = RightClick.onIEMouse;
        }
    },
    
/**
     * GECKO / WEBKIT event overkill
     * 
@param {Object} eventObject
     
*/
    killEvents: function(eventObject) {
        
if(eventObject) {
            
if (eventObject.stopPropagation) eventObject.stopPropagation();
            
if (eventObject.preventDefault) eventObject.preventDefault();
            
if (eventObject.preventCapture) eventObject.preventCapture();
               
if (eventObject.preventBubble) eventObject.preventBubble();
        }
    },
    
/**
     * GECKO / WEBKIT call right click
     * 
@param {Object} ev
     
*/
    onGeckoMouse: function(ev) {
          
return function(ev) {
        
if (ev.button != 0) {
            RightClick.killEvents(ev);
            
if(ev.target.id == RightClick.FlashObjectID && RightClick.Cache == RightClick.FlashObjectID) {
                RightClick.call();
            }
            RightClick.Cache 
= ev.target.id;
        }
      }
    },
    
/**
     * IE call right click
     * 
@param {Object} ev
     
*/
    onIEMouse: function() {
          
if (event.button > 1) {
            
if(window.event.srcElement.id == RightClick.FlashObjectID && RightClick.Cache == RightClick.FlashObjectID) {
                RightClick.call(); 
            }
            document.getElementById(RightClick.FlashContainerID).setCapture();
            
if(window.event.srcElement.id)
            RightClick.Cache 
= window.event.srcElement.id;
        }
    },
    
/**
     * Main call to Flash External Interface
     * 'flexview_rightClick'
     
*/
    call: function() {
        document.getElementById(
this.FlashObjectID).flexview_rightClick();
    }
}


    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
<html>
    
<head>
    
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    
<title>TEST</title>
    
    
<script type="text/javascript" src="swfobject.js"></script>
    
<script type="text/javascript" src="rightClick.js"></script>

    
    
</head>
    
<body onload="RightClick.init();">
        
<div id="flashcontent">Flash Player 10 required</div>
        
<script type="text/javascript">
           var so 
= new SWFObject("RightClickAS3.swf""customRightClick""560""420""9""#CCCCCC");
            so.addParam(
"quality""high");
            so.addParam(
"name""customRightClick");
            so.addParam(
"id""customRightClick");
            so.addParam(
"AllowScriptAccess""always");
            so.addParam(
"wmode""opaque");
            so.addParam(
"menu""false");
            so.addVariable(
"variable1""value1");
            so.write(
"flashcontent");
        
</script>
    
</body>
    
</html>
   


package com
{
    
import flash.display.*;
    
import flash.external.ExternalInterface;
    
public class RightClick extends Sprite
    {
        
public function RightClick()
        {
            var methodName:String 
= "flexview_rightClick";
            var method:Function 
= onRightClick;
            ExternalInterface.addCallback(methodName, method);
        }
        
private function onRightClick():void {
            var mx:
int = stage.mouseX;
            var my:
int = stage.mouseY;
            trace(mx 
+ ":" + my);
            
if(my> 0 && my <stage.stageHeight && mx> 0 && mx <stage.stageWidth) {
                
// YOUR CODE HERE
            }
        }
    }
}

posted @ 2011-11-28 17:01 oathleo 阅读(2287) | 评论 (0)编辑 收藏

网上也烂了,自己做 还是浪费一天

教程就不写了,直接写经验

1.平台
flash builder4 + eclipse-jee-galileo (也就是3.5,jee集成了web插件,反正用的不多)

官网下的flash builder4 安装时,选内置的eclipse,死活建不了BlazeDS项目。没心思研究了,以后就按照这个平台来吧。

直接使用这个平台建flex项目,设定server,直接生成,简单

2.AS里
RemoteObject 在sdk里面竟然有2个....
mx.rpc.remoting.RemoteObject api里调用,无法成功
mx.rpc.remoting.mxml.RemoteObject 成功

3.java数组直接amf成 object

4.as的hashset ,拔了个开源的,不错
a3lbmonkeybrain.brainstem.collections

posted @ 2011-11-04 17:05 oathleo 阅读(1847) | 评论 (3)编辑 收藏


当我了解到Flex4那些对我诸多裨益的新特性后, 我便决定转而使用它。刚开始的时候,我试图利用在Flex前作中的认识和既有经验来快速进入状态。但很快我便发现有时即使面对一些显而易见的问题我也不得 不求助于API文档或者运行一些示例程序来弄清这种问题的来龙去脉。根据以往经验,Flex3 的Halo在处理显示列表的时候隐藏了大量的实现细节和不良设计。然而一旦你开始使用新的Spark架构后,你就得以近距离的面对这些实现细节—Halo 究竟在私底下干了什么,而且你会体会到为什么说Spark对于显示列表的处理更为“直白”。

“elements”是一个关键性的问题。elements是何物?它同child是否是一回事?刚开始的时候我曾武断的认为elements不 过是children的另一种说法。通过反复梳理组件中所有的elements和children,我发觉在新的容器类(也包括一些经过改良的传统容器) 某些似乎是理所当然应该具备的方法消失了。如果没有getElements(),我该如何获取elements的数目呢?我能否把 getChildren() 的返回结果作为IVisualElement来对待。这令我十分纠结。

困扰的我于是开始认真阅读学习API文档,Flex的源码以及相关的博客文章。我也曾尝试解读一些博主发布的关于Flex4新特性的幻灯片。然而事实证明脱离讲解而孤立的看幻灯片作用相当有限。

最后,我拼凑了一些言简意赅的示例。这些示例将带领我了解有关elements的全新知识,告诉我那些在新的Spark容器背后发生的故事。

言归正传,首先从问题开始。问题一,“应该如何获得Spark 容器的全部elements?”我曾想当然的认为是通过一个类似Flex3中的getChildren() 的方法。然而实际上我们需要通过两个Property来达到这个目的:numElements & numChildren 。可以通过对numElements计数的循环语句配合getElementAt() 来实现遍历容器elements或特定访问。这种方式还比较直观。问题二,“element和child的区别何在?”,让我们来看看两者的差异。

语义上,element简单的说就是实现了IVisualElement接口的任意型别。child是指扩展了DisplayObject类的任 意型别。判断某个组件是element还是child亦或两者都是的关键在于以下几点。UIComponent(所有Flex组件的基类:译者注)是由 DisplayObject扩展而来,故所有UIComponent都是DisplayObject,也就是说UIComponent都是 children。UIComponent同时也实现了IVisualElement接口,因而所有的UIComponent也可以被作为 elements看待。但这并不是说所有的DisplayObjects(文中所言的DisplayObject一般指扩展于DisplayObject 的子类,译者注)都是elements。容器中的DisplayObject对象是该无疑是容器的child。而只有当此DisplayObject对象 同时也实现了IVisualElement接口时它才是容器的element。那么对容器而言,DisplayObject什么情况下是child,什么 情况下又是element?通过示例来认识这个问题。

在首个示例中,我们使用了传统的Halo容器(这里我们使用的Panel)。Panel扩展与DisplayObject类,所以它可以使用 addChild() 方法。进一步而言,Panel也是Container类的子类(mx.core.Container实现了 IVisualElementContainer接口),它具有addElement() 方法。Container类的IVisualElementContainer接口实现只是基于显示列表API的门面,所以理论上它和同样实现了 IVisualElementContainer接口的新式Spark容器具有相同的方法集合。



于是看起来我们可以任意添加children或element到容器中了。事实却不是这样。并非任意型别的element都能被添加(此处 element泛指实现了IVisualElement接口的类)容器中。视觉元素(VisualElements)和图形元素 (GraphicElements)有一些区别视觉元素(VisualElements)实现了IVisualElement接口,而图形元素 (GraphicElements)实现的是IVisualElement接口的子接口IGraphicElement。IGraphicElement 接口扩展的新特性为容器获取信息提供了额外渠道。某些elements(图形元素是其中之一)无法直接添加至Halo的Panel编译器会告知“这样的对 象需事先包装进一个Group容器中”(实际上错误提示应该是在运行时出现,不关编译器什么事:译者注)。原因马上揭晓。

接下来的示例中,Panel中有若干个UIComponent,其中包括另一个Halo Panel,一个Spark Panel,几个Halo Button和几个Spark Button,以及一个包含有子组件的SkinnableContainer(注意: 包含于SkinnableContainer的组件是只属于SkinnableContainer的children,不是上级容器Panel的 children)。所有组件都继承于DisplayObject,所以它们都是“children”。点击“show children”后可以清楚的了解这一点。进一步而言,所有的组件也都是“element”,因为UIComponent实现了 IVisualElement接口。

看下一个示例。这次我们探讨的容器上Spark Group。与前Halo Panel类似,Group继承于DisplayObjectContainer,它具有addChild() 方法,它同时也实现了IVisualElement接口,所以我们可以用addElement() 方法来IVisualElement对象(elements)。而且Group也接受图形元素(GraphicElements),比如 spark.primitives.Rect。要知道Rect是无法直接添加到Halo Panel中的。Group是怎么做到这一点的?原因就在于Group知道如何使用一种优化的方式来呈现图形元素(GraphicElements)。什 么意思?往下读。

相对于典型的视觉元素(VisualElements),图形元素(GraphicElements)与容器的关系更为紧密。其关键在于 IGraphicElement接口。上面曾经提到,这个扩展于IVisualElement的接口(此即图形元素(GraphicElements)可 以通过Group的addElement() 方法来添加至其上的原因所在)。然而由于图形元素(GraphicElements)不是DisplayObject,所以他们在被“投映”到某个作为他 父对象的DisplayObject前是无法被显示出来的。基于这个原因,当添加一个“Rectangle”到Group时,需要有 DisplayObject来绘制这个Rectangle。更有效率一点的做法是Group尽可能的复用同一个DisplayObject来绘制多个图形 元素(GraphicElements)。容器可以使用任何实现了ISharedDisplayObject接口的DisplayObject来绘制图形 元素(GraphicElements)。第一个示例中的Halo Panel无法使用这种方式来绘制图形元素(GraphicElements),编译器会报错:“必须将其包装至一个合适的容器中”。而Group支持这 种优化方式,所以能添加图形元素(GraphicElements)。

另外需要注意的一点是,有些图形元素(GraphicElements)的绘制由Group提供DisplayObject来完成,也有的是自行 创建专属的DisplayObject来完成绘制。IGraphicElement接口甚至允许把对象自己创建的DisplayObject交由容器管理 (换而言之就是以child形态添加的DisplayObject会以IGraphicElement的面貌来绘制自己)。

这意味着什么?这意味着在接下来的示例中,children的数目和elements的数目是不一样的。这个示例使用了与第一个示例相同的组件集 合外,还增加了4个矩形图形元素(GraphicElements)。所有子对象皆为IVisualElement,但不是都可以称为children。 几个矩形是图形元素(GraphicElements),它们并不继承于DisplayObject。Group不在乎这点,它知道添加 DisplayObject来绘制这些图形元素(GraphicElements)。由于几个矩形的尺寸和角度有所不同,所以Group会创建2个新的 DisplayObject来绘制这4个矩形。很酷吧!



现在来看示例三。我们用一个SkinnableContainer替换先前的Group。SkinnableContainer有和先前相同的子 组件集,它还能利用Skin来增强视觉效果。Skin是SkinnableContainer唯一的child。SkinnableContainer的 默认Skin类由一个矩形和一个被称为ContentGroup的Group组成。该Group的作用在于规划出容器内组件的添加位置。

这个示例证明了这样的事实,即使SkinnableContainer拥有10个elements,但它只有唯一的child:它自己的 Skin。而且这个Skin也只有唯一的child:名为ContentGroup的Group组件。你也许会感到奇怪:为什么Skin的 children不是2个:其一是ContentGroup,另一个是用于绘制作为边框的Rectangle的DisplayObject?这是因为 Skin类继承自Group类,而Group只在它确实需要绘制其包容的图形元素(GraphicElements)时才会添加 DisplayObject,目前的情况下不需要。Skin类具备直接在其上绘制Rect图形元素(GraphicElements)的能力,这归功于 Skin类的上级类Group实现了ISharedDisplayObject接口。这意味着它在需要时能作为共享的DisplayObject来绘制图 形元素(GraphicElements)。Skin负责管理用于呈现图形元素(GraphicElements)的DisplayObject,在当前 示例中,Skin自己就是用于绘制的DisplayObject!如果你的自定义Skin中有其它的Rectangle,并将该Skin赋予 SkinnableContainer,这种情况下Skin会判断是否需要更多的DisplayObject来绘制额外的Rectangle。这时你可能 会发现在Skin的children列表中有更多的child。

值得注意的是,示例中SkinnableContainer,它的Skin以及Skin的ContentGroup这三者的element列表的 数目是相同的。通过SkinnableContainer的源码可以知道,numElement的值实际上来源于与之对应的 CurrentContentGroup的numElement。所以基本上对SkinnableContainer的elements的检索是被重定向 到它的ContentGroup上的。SkinnableContainer的Skin也有类似行为。它继承于Group,Group的 numElement的值取自其内部的mxmlContent属性。该属性是一个保存了Group可视内容children的数组。这两个属性与 Panel的RawChildren属性十分相似,它用于返回Panel上的所有children而不是getChildren()方法返回的仅仅你添加 到Panel上的那些。



通过以上阅读,也许起不到拨云见日的效果。但可以让你明白厘清以下七个类/接口的继承结构和相互关系是十分有必要的:
1. DisplayObject
2. UIComponent
3. Container
4. IVisualElement
5. IGraphicElement
6. IVisualElementContainer
7. ISharedDisplayObject

一旦你掌握它们之间的关系,你就能明白elements 和children的不同。可以肯定的是我在某些问题的认识和阐述上存在很多谬误之处。如果你发现了这样的问题望不吝赐教,在评论处写下您的正确观点吧。

posted @ 2011-10-14 11:05 oathleo 阅读(821) | 评论 (0)编辑 收藏

请保留:
http://www.blogjava.net/oathleo/archive/2011/09/23/android_Fruit_Ninja.html


android手势加上了,比如左右滑动
但是用户经常不能感受到是否滑动了,
水果忍者刀锋效果/光刀效果就相当不错

网上搜了下,大多是ios的实现,想想原理可能不是很复杂,就实现了个最简单的。
原理
1.在背景view上再加一层view专门负责draw刀锋
2.刀锋就是随着手势move,动态画shape
3.接受到事件得dispatchTouchEvent,否则下面的组件无法获得事件了
4.下面的组件事件等无需更改,互不耦合
5.一个类实现,不涉及其他第三方
6.只实现了一个最简单的形状,水果忍者里面实现了很多复杂形状,可以在这个基础上进行扩展
效果如图



代码:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.MotionEvent;
import android.view.View;



/**
 * 
 * 模仿水果忍者刀锋效果
 * 
@author leooath@gmail.com
 *
 
*/
public class GestureView extends View {

    
private Paint paint;

    
private float startX = Float.NaN;
    
private float startY = Float.NaN;
    
private float endX = Float.NaN;
    
private float endY = Float.NaN;

    
//下层view
    private View viewer;
    
private static final int gestureColor = Color.rgb(153153153);
    
private static final int alpha = 220;
    
private static final int alpha_full = 255;
    
//刀锋长度
    private static final int shape_length = 40;
    
//刀锋截短时间
    private static final int shape_cut_time = 150;
    
    
public GestureView(Context context, View viewer) {
        
super(context);
        
this.viewer = viewer;
        paint 
= new Paint();
        paint.setStyle(Paint.Style.FILL);
    }

    
public void draw(Canvas canvas) {
        
super.draw(canvas);
        
if (!Float.isNaN(startX) && !Float.isNaN(endY)) {
            
float gap = ViewUtils.getGap(startX, startY, endX, endY);
            
float w = gap / 10;
            
//背景shape外侧点高度
            float h = w > 7 ? 7 : w;
            
//填充shape外侧点高度
            float h2 = h * 2 / 3

            
double length = Math.pow(Math.pow(w, 2+ Math.pow((h), 2), 0.5);
            
double length2 = Math.pow(Math.pow(w, 2+ Math.pow((h2), 2), 0.5);
            
            
double ang1_1 = Math.atan((endY - startY) / (endX - startX));
            
double ang1_2 = Math.atan(h / w);
            
double angle1_1 = ang1_1 + ang1_2;
            
double angle1_2 = ang1_1 - ang1_2;
            
            
double ang2_2 = Math.atan(h2 / w);
            
double angle2_1 = ang1_1 + ang2_2;
            
double angle2_2 = ang1_1 - ang2_2;
            
if (endX > startX) {
                
float xx1 = endX - (float) (length * Math.cos(angle1_1));
                
float yy1 = endY - (float) (length * Math.sin(angle1_1));
                
float xx2 = endX - (float) (length * Math.cos(angle1_2));
                
float yy2 = endY - (float) (length * Math.sin(angle1_2));

                
float xx12 = endX - (float) (length2 * Math.cos(angle2_1));
                
float yy12 = endY - (float) (length2 * Math.sin(angle2_1));
                
float xx22 = endX - (float) (length2 * Math.cos(angle2_2));
                
float yy22 = endY - (float) (length2 * Math.sin(angle2_2));
                
                Path backPath 
= new Path();
                backPath.moveTo(startX, startY);
                backPath.lineTo(xx1, yy1);
                backPath.lineTo(endX, endY);
                backPath.lineTo(xx2, yy2);
                backPath.close();
                
                Path fillPath 
= new Path();
                fillPath.moveTo(startX, startY);
                fillPath.lineTo(xx12, yy12);
                fillPath.lineTo(endX, endY);
                fillPath.lineTo(xx22, yy22);
                fillPath.close();

                paint.setColor(gestureColor);
                paint.setAlpha(alpha);
                canvas.drawPath(backPath, paint);
                
                paint.setColor(Color.WHITE);
                paint.setAlpha(alpha_full);
                canvas.drawPath(fillPath, paint);
            } 
else {
                
float xx1 = endX + (float) (length * Math.cos(angle1_1));
                
float yy1 = endY + (float) (length * Math.sin(angle1_1));
                
float xx2 = endX + (float) (length * Math.cos(angle1_2));
                
float yy2 = endY + (float) (length * Math.sin(angle1_2));

                
float xx12 = endX + (float) (length2 * Math.cos(angle2_1));
                
float yy12 = endY + (float) (length2 * Math.sin(angle2_1));
                
float xx22 = endX + (float) (length2 * Math.cos(angle2_2));
                
float yy22 = endY + (float) (length2 * Math.sin(angle2_2));
                
                Path backPath 
= new Path();
                backPath.moveTo(startX, startY);
                backPath.lineTo(xx1, yy1);
                backPath.lineTo(endX, endY);
                backPath.lineTo(xx2, yy2);
                backPath.close();

                Path fillPath 
= new Path();
                fillPath.moveTo(startX, startY);
                fillPath.lineTo(xx12, yy12);
                fillPath.lineTo(endX, endY);
                fillPath.lineTo(xx22, yy22);
                fillPath.close();

                paint.setColor(gestureColor);
                paint.setAlpha(alpha);
                canvas.drawPath(backPath, paint);
                
                paint.setColor(Color.WHITE);
                paint.setAlpha(alpha_full);
                canvas.drawPath(fillPath, paint);
            }
        }
    }

    
public boolean onTouchEvent(android.view.MotionEvent event) {
        
if(event.getPointerCount() == 1){
            
int action = event.getAction();
            
if (MotionEvent.ACTION_DOWN == action) {
                startX 
= event.getX();
                startY 
= event.getY();
            } 
else if (MotionEvent.ACTION_MOVE == action) {
                endX 
= event.getX();
                endY 
= event.getY();
                
                
//刀锋截短时间,则截短至一半
                if ((event.getEventTime() - event.getDownTime()) > shape_cut_time) {
                    
if(Math.abs(endX - startX) > shape_length && Math.abs(endY - startY) > shape_length){
                        startX 
= (float) (startX + (endX - startX) * 0.5);
                        startY 
= (float) (startY + (endY - startY) * 0.5);
                    }
                }

                invalidate();
            } 
else if (MotionEvent.ACTION_UP == action) {
                startX 
= Float.NaN;
                startY 
= Float.NaN;
                endX 
= Float.NaN;
                endY 
= Float.NaN;
                invalidate();
            }
        }
        
//该view消费了event,所以下层的view必须dispatchTouchEvent才能获得事件
        MotionEvent newEvent = MotionEvent.obtain(event);
        viewer.dispatchTouchEvent(newEvent);
        
return true;
    }

}

posted @ 2011-09-23 11:29 oathleo 阅读(3948) | 评论 (5)编辑 收藏

对于View来说,事件的返回值是关注的,down时返回true,才能接受up的事件
对于SurfaceView,事件返回值貌似没有什么作用

        setOnTouchListener(new OnTouchListener() {
            
public boolean onTouch(View v, MotionEvent event) {
                System.out.println(
"touch");
                
return true;
            }
        });

有兴趣的朋友可以试试上面的代码

posted @ 2011-09-19 16:31 oathleo 阅读(1556) | 评论 (0)编辑 收藏

对于工业生产现场来说,过程实时数据变化很快,数据存储量很大,如果每个数据都存储,在经历不长时间后就会占据大量磁盘空间。一般来说,工业生产的很多数 据是线性变化的,或者是符合某种规律变化的,如果数据库能够根据某些条件进行判断,将某些可忽略的数据,不进行存储,而当需要查找该数据时,可以通过线性 或步进插值计算出来,就可以大幅度提高存储效率,同时节约磁盘空间。

    上述描述的情况就是在线数据压缩。所谓数据压缩,就是丢弃那些对于在准确重现现场设备(以下称为测点)历史曲线时不是必需的测点数据。

    当今,非常流行的数据压缩算法是由美国OSI软件公司研发的旋转门压缩算法,此算法已经成功地运用在了PI实时数据库系统当中,此算法主要针对的对象是浮点数数据类型的数据。

    旋转门压缩算法分析:

  • 部分原文:

    With the swinging door algorithm, a value is stored if a straight line drawn between the last stored value and the next value does not come within the compression deviation specification of all the intermediate points. Two slopes are required to carry out this test. The following figure shows the slopes as they are initialized after a value is stored:

在线数据压缩算法分析

 

Figure1 – Swinging Door slopes after recording a value

    The dotted lines are the two slopes. Let the compression deviation specification be 8. One of the lines is drawn from the last recorded value plus 8 through whichever value maximizes the slope of the line. This is the top dotted line in Figure 1. The other dotted line is drawn from the last recorded value minus 8 through whichever value minimizes the slope of the line. The third line is drawn between the last recorded value and the new value. This is the solid line in Figure 1. The previous value is recorded if the slope of the top dotted line is greater than the slope of the solid line or the slope of the solid line is greater than the slope of the bottom dotted line.

    The algorithm ensures that each discarded value falls within the compression deviation specification of the solid line. The compression deviation specification is also the maximum error in a trend of archived values. The next figure shows the lines after four more values have been received.

    The next figure shows the arrival of a value which causes the previous value to be recorded.

在线数据压缩算法分析

 

Figure 2 – Recording a new value

  • 中文解释:

    对于旋转门压缩算法来说,先由上一保存数据项和当前数据项来画出一条直线(在二维坐标图上),如果待保存数据项不在当前数据项和上一保存数据项的压缩偏差范围之内,则待保存数据项被保存。实验中还需要两条斜线(旋转门)。图1(Figure 1)中显示了这两个旋转门,传入系统的第一个测点数据项会直接被保存,否则因为数据库中没有被保存的测点数据项就无法确定旋转门了。

    压缩偏差是旋转门压缩算法中的重要参数,它是人为设定的绝对误差值,可以简单的理解为在绝对误差范围内,数据被压缩掉,在绝对误差范围外,数据不被压缩。

    另外,算法的实现还需要计算以下几个斜率:

   (1)上斜率 K1 =(当前数据项数值 -(上一保存数据项数值 - 压缩偏差))/(当前数据项时间 - 上一保存数据项时间)

   (2)下斜率 K2 =(当前数据项数值 -(上一保存数据项数值 + 压缩偏差))/(当前数据项时间 - 上一保存数据项时间)

   (3)中间斜率K =(当前数据项数值 - 待保存数据项数值)/(当前数据项时间 - 待保存数据项时间)

    通过计算压缩变量上一保存数据项和当前数据项与待保存数据项的斜率来进行压缩控制。即:

    如果 K2KK1,待保存数据项被压缩。

    如果 K<K2或者K>K1,待保存数据项被存储。

 

算法实现流程如下:

1.第一个数据项处理:直接存入数据库。

2.第二个数据项处理:计算前后两数据项的上下两个斜率,并将上下斜率作为后续判断的依据。

3.两个数据项以上处理:计算上中下斜率,进行判断:(1)如果没有通过旋转门压缩检测,把上一个数据项信息保存,并将新的上下斜率保存作为后续判断的依据;(2)如果通过旋转门压缩检测,则不需要保存。

4.循环执行第三步中的压缩条件判断。




#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <math.h>
static int maxnum = 3600;
void main(int argc,char **argv[])
{
  int now=0, start=0; 
  FILE *fd, *fd1;
 
  fd = fopen("test", "r");
  fd1 = fopen("test.zip", "w");
 
  float E=10.01;
  float mem, mem_old;
  float upgate; /*定义上门*/ 
  float downgate; /*定义下门*/ 
  float k1; /*k1表示上门和过程数据间的斜率*/ 
  float k2; /*k2表示下门和过程数据间的斜率*/ 
 
  fread(&mem, sizeof(float), 1, fd);
  mem_old = mem;
 
  for(;;) {
   if(now == maxnum-1) {
       fwrite(&mem, sizeof(float), 1, fd1);
       break;
    }
   fwrite(&mem, sizeof(float), 1, fd1);
    start = now;
    upgate=mem+E; 
    downgate=mem-E; 
    k1=-10000; 
    k2=-10000; 
    for(;;) {
     now++;
     mem_old = mem;
     fread(&mem, sizeof(float), 1, fd);
     if(fabs(mem-upgate)>0.001){
      if((mem-upgate)/(now -start)>k1) k1=(mem-upgate)/(now-start); 
       else {
        now=now++;
        fwrite(&mem_old, sizeof(float), 1, fd1);
        break;
       }
      }
      if(fabs(mem-downgate)>0.001){
        if((downgate-mem)/(now-start)>k2) k2=(downgate-mem)/(now-start); 
       else {
        now=now++;
        fwrite(&mem_old, sizeof(float), 1, fd1);
        break;
       }     
      } 
   if(now == maxnum-1) {
        break;
      }
    }

posted @ 2011-09-14 13:46 oathleo 阅读(5575) | 评论 (0)编辑 收藏

http://cnbeta.com/articles/154387.htm



世上最伟大的十个公式,薛定谔方程排名第六,质能方程排名第五

leoliyuan发布于 2011-09-08 08:49:56|4126 次阅读 字体: 打印预览 分享至新浪微博 转贴到开心网 分享到校内人人网 添加到Google书签

cnBeta 科学探索

英国科学期刊《物理世界》曾让读者投票评选了“最伟大的公式”,最终榜上有名的十个公式既有无人不知的1+1=2,又有著名的E=mc2;既有简单的-圆周公式,又有复杂的欧拉公式……

从什么时候起我们开始厌恶数学?这些东西原本如此美丽,如此精妙。这个地球上有多少伟大的智慧曾耗尽一生,才最终写下一个等号。每当你解不开方程的时候,不妨换一个角度想,暂且放下对理科的厌恶和对考试的痛恨。因为你正在见证的,是科学的美丽与人类的尊严。

No.10 圆的周长公式(The Length of the Circumference of a Circle)

 

 

这公式贼牛逼了,初中学到现在。目前,人类已经能得到圆周率的2061亿位精度。还是挺无聊的。现代科技领域使用的-圆周率值,有十几位已经足够了。如果用 35位精度的-圆周率值,来计算一个能把太阳系包起来的一个圆的周长,误差还不到质子直径的百万分之一。现在的人计算圆周率,多数是为了验证计算机的计算 能力,还有就是为了兴趣。

 

No.9 傅立叶变换(The Fourier Transform)

 

 

这个挺专业的,一般人完全不明白。不多作解释。简要地说没有这个式子没有今天的电子计算机,所以你能在这里上网除了感谢党感谢政府还要感谢这个完全看不懂的式子。另外傅立叶虽然姓傅,但是法国人。

 

No.8 德布罗意方程组(The de Broglie Relations)

 

 

这个东西也挺牛逼的,高中物理学到光学的话很多概念跟它是远亲。简要地说德布罗意这人觉得电子不仅是一个粒子,也是一种波,它还有 “波长”。于是搞啊搞就有了这个物质波方程,表达了波长、能量等等之间的关系。同时他获得了1929年诺贝尔物理学奖。

 

No.7 1+1=2

这个公式不需要名称,不需要翻译,不需要解释。

 

No.6 薛定谔方程(The Schr&ouml;dinger Equation)


 

也是一般人完全不明白的。因此我摘录官方评价:“薛定谔方程是世界原子物理学文献中应用最广泛、影响最大的公式。”由于对量子力学的杰出贡献,薛定谔获得1933年诺贝尔物理奖。

另外薛定谔虽然姓薛,但是奥地利人。

 

No.5 质能方程(Mass–energy Equivalence)

 

 

好像从来没有一个科学界的公式有如此广泛的意义。在物理学“奇迹年”1905年,由一个叫做爱因斯坦的年轻人提出。同年他还发表了《论动体的电动力学》——俗称狭义相对论。

这个公式告诉我们,爱因斯坦是牛逼的,能量和质量是可以互换的。副产品:原子弹。

 

No.4 勾股定理/毕达哥拉斯定理(Pythagorean Theorem)

 

 

做数学不可能没用到过吧,不多讲了。

 

No.3 牛顿第二定律(Newton's Second Law of Motion)

 

 

有史以来最伟大的没有之一的科学家在有史以来最伟大没有之一的科学巨作《自然哲学的数学原理》当中的被认为是经典物理学中最伟大的没有之一的核心定律。动力的所有基本方程都可由它通过微积分推导出来。对于学过高中物理的人,没什么好多讲了。

 

No.2 欧拉公式(Euler's Identity)

 

 

这 个公式是上帝写的么?到了最后几名,创造者个个神人。欧拉是历史上最多产的数学家,也是各领域(包含数学的所有分支及力学、光学、音响学、水利、天文、化 学、医药等)最多著作的学者。数学史上称十八世纪为“欧拉时代”。欧拉出生于瑞士,31岁丧失了右眼的视力,59岁双眼失明,但他性格乐观,有惊人的记忆 力及集中力。他一生谦逊,很少用自己的名字给他发现的东西命名。不过还是命名了一个最重要的一个常数——e。

关 于e,以前有一个笑话说:在一家精神病院里,有个病患整天对着别人说,“我微分你、我微分你。”也不知为什么,这些病患都有一点简单的微积分概念,总以为 有一天自己会像一般多项式函数般,被微分到变成零而消失,因此对他避之不及,然而某天他却遇上了一个不为所动的人,他很意外,而这个人淡淡地对他说,“我 是e的x次方。”

这个公式的巧妙之处在于,它没有任何多余的内容,将数学中最基本的e、i、pie放在了同一个式子中,同时加入了数学也是哲学中最重要的0和1,再以简单的加号相连。

高斯曾经说:“一个人第一次看到这个公式而不感到它的魅力,他不可能成为数学家。”

 

No.1 麦克斯韦方程组(The Maxwell's Equations)

积分形式:

 

微分形式:

 

任何一个能把这几个公式看懂的人,一定会感到背后有凉风——如果没有上帝,怎么解释如此完美的方程?这组公式融合了电的高斯定律、磁的高斯定律、法拉第定律 以及安培定律。比较谦虚的评价是:“一般地,宇宙间任何的电磁现象,皆可由此方程组解释。”到后来麦克斯韦仅靠纸笔演算,就从这组公式预言了电磁波的存 在。我们不是总喜欢编一些故事,比如爱因斯坦小时候因为某一刺激从而走上了发奋学习、报效祖国的道路么?事实上,这个刺激就是你看到的这个方程组。也正是 因为这个方程组完美统一了整个电磁场,让爱因斯坦始终想要以同样的方式统一引力场,并将宏观与微观的两种力放在同一组式子中:即著名的“大一统理论”。爱 因斯坦直到去世都没有走出这个隧道,而如果一旦走出去,我们将会在隧道另一头看到上帝本人。

posted @ 2011-09-08 09:22 oathleo 阅读(2319) | 评论 (3)编辑 收藏

        <activity android:name=".LoginActivity" android:label="@string/app_name" android:launchMode="singleTask">

launchmode4种模式:
1,standard:
如果从A跳到A,intent5次,task里5个activity;
2,single Top:
如果从A 跳B,再从B跳A,如果此时栈顶为A,则不创建新实例,直接把Intent给A,但如果栈顶不是A,则还要创建A的实例
3,singleTask
如果从A跳B,再从B跳A,无论是否栈顶栈底,只要A在,则将Intent给A,不会创建A的新实例;
4,singleInstance
不同于前3种模式,前3种只是在同一个task的,而实例化的策略不同。这种模式下的activity会单独存在一个task下。
现成的例子是google地图。比如我有一个应用是导游方面的,其中调用的google地图Activity。那么现在我比如按home(后台 activity onstop,back是finish)键,然后到应用列表中打开google地图,你会发现显示的就是刚才的地图,实际上是同一个Activity。
如果使用上面三种模式,是无法实现这个需求的。google地图应用中有多个上下文Activity,比如路线查询等的,导游应用也有一些上下文Activity。在各自应用中回退要回退到各自的上下文Activity中。
总结:
1 2:会创建新实例
3 4:不会创建新实例
123:activity的taskid相同
4:activity的taskid不同。被分到单独一个task中

posted @ 2011-09-02 13:11 oathleo 阅读(315) | 评论 (0)编辑 收藏

    popupWindow.setWidth(LayoutParams.WRAP_CONTENT);               
    popupWindow.setHeight(LayoutParams.WRAP_CONTENT);         
    

view自适应
                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
                LinearLayout linearLayout 
= new LinearLayout(c);
                linearLayout.setLayoutParams(params);


使用:
  mPop.showAtLocation((View) v.getParent(), Gravity.TOP | Gravity.LEFT, 25250);

以上面一句为例:第一个参数是指PopupWindow显示在哪一个View之上.后面三个参数控制PopupWindow显示的位置,此处表明PopupWindow显示在距左上角x252个像素,y50个像素.

posted @ 2011-09-02 11:23 oathleo 阅读(4577) | 评论 (0)编辑 收藏

屏幕大小
1、不同的layout

      Android手机屏幕大小不一,有480x320,640x360,800x480.怎样才能让App自动适应不同的屏幕呢? 其实很简单,只需要在res目录下创建不同的layout文件夹,比如:layout-640x360,layout-800x480,所有的 layout文件在编译之后都会写入R.java里,而系统会根据屏幕的大小自己选择合适的layout进行使用。

2、hdpi、mdpi、ldpi

      前的版本中,只有一个drawable,而2.1版本中有drawable-mdpi、drawable-ldpi、drawable-hdpi三个,这三个主要是为了支持多分辨率。

drawable- hdpi、drawable- mdpi、drawable-ldpi的区别:

1.drawable-hdpi里面存放高分辨率的图片,如WVGA (480x800),FWVGA (480x854)
2.drawable-mdpi里面存放中等分辨率的图片,如HVGA (320x480)
3.drawable-ldpi里面存放低分辨率的图片,如QVGA (240x320)
系统会根据机器的分辨率来分别到这几个文件夹里面去找对应的图片。在开发程序时为了兼容不同平台不同屏幕,建议各自文件夹根据需求均存放不同版本图片。

屏幕方向
1、横屏竖屏自动切换

      可以在res目录下建立layout-port和layout-land两个目录,里面分别放置竖屏和横屏两种布局文件,这样在手机屏幕方向变化的时候系统会自动调用相应的布局文件,避免一种布局文件无法满足两种屏幕显示的问题。

2、禁用自动切换

只需要在AndroidManifest.xml文件中加入android:screenOrientation属性限制。

•Android:screenOrientation="landscape"  //是限制此页面横屏显示
•Android:screenOrientation="portrait"      //是限制此页面数竖屏显示
字体自适应大小
方法1:

首先根据不同分辨率获取不同字体大小。
在RES里创建
values-480x320/strings.xml 里面设置<dimen name="Text_size">30px</dimen>

values-800x400/strings.xml 里面设置<dimen name="Text_size">30px</dimen>

分别代表480X320 和 800X400分辨率情况下 字号为30px和40px;

在java文件中这样调用

int sizeOfText = (int) this.getResources().getDimension(R.dimen.Text_size);

方法2:

在视图的 onsizechanged里获取视图宽度,一般情况下默认宽度是320,所以计算一个缩放比率rate = (float) w/320   w是实际宽度
然后在设置字体尺寸时 paint.setTextSize((int)(8*rate));   8是在分辨率宽为320 下需要设置的字体大小实际字体大小 = 默认字体大小 x  rate

posted @ 2011-09-02 09:28 oathleo 阅读(1242) | 评论 (0)编辑 收藏

首先内部存储路径为/data/data/youPackageName/,下面讲解的各路径都是基于你自己的应用的内部存储路径下。所有内部存储中保存的文件在用户卸载应用的时候会被删除。

一、 files
1. Context.getFilesDir(),该方法返回/data/data/youPackageName/files的File对象。
2. Context.openFileInput()与Context.openFileOutput(),只能读取和写入files下的文件,返回的是FileInputStream和FileOutputStream对象。
3. Context.fileList(),返回files下所有的文件名,返回的是String[]对象。
4. Context.deleteFile(String),删除files下指定名称的文件。

二、cache
1. Context.getCacheDir(),该方法返回/data/data/youPackageName/cache的File对象。

三、custom dir

getDir(String name, int mode),返回/data/data/youPackageName/下的指定名称的文件夹File对象,如果该文件夹不存在则用指定名称创建一个新的文件夹。



有了数据存储 API,您可以使用内部存储器存储数据。信息可以是私有的,您可以有选择地让其他应用程序对之具有读或写的访问权限。本节介绍这个存储私有数据的 API,它使用 android.content.Context.openFileInput、openFileOutput 和 getCacheDir() 来高速缓存数据,而不是永久地存储。

清单 20 中的代码片段展示了如何从内部私有存储器读取数据。使得存储器为私有的方法是对 openFileOutput() 使用MODE_PRIVATE。


清单 20. 从本地私有存储器读取数据

/**
 * Writes content to internal storage making the content private to 
 * the application. The method can be easily changed to take the MODE 
 * as argument and let the caller dictate the visibility: 
 * MODE_PRIVATE, MODE_WORLD_WRITEABLE, MODE_WORLD_READABLE, etc.
 * 
 * 
@param filename - the name of the file to create
 * 
@param content - the content to write
 
*/
public void writeInternalStoragePrivate(
        String filename, 
byte[] content) {
    
try {
        
//MODE_PRIVATE creates/replaces a file and makes 
        
//  it private to your application. Other modes:
        
//    MODE_WORLD_WRITEABLE
        
//    MODE_WORLD_READABLE
        
//    MODE_APPEND
        FileOutputStream fos = 
           openFileOutput(filename, Context.MODE_PRIVATE);
        fos.write(content);
        fos.close();
    } 
catch (FileNotFoundException e) {
        e.printStackTrace();
    } 
catch (IOException e) {
        e.printStackTrace();
    }
}


清单 21 中的代码片段展示了如何从内部私有存储器读取数据;注意 openFileInput() 的使用。


清单 21. 从内部私有存储器读取数据

/**
 * Reads a file from internal storage
 * 
@param filename the file to read from
 * 
@return the file content
 
*/
public byte[] readInternalStoragePrivate(String filename) {
    
int len = 1024;
    
byte[] buffer = new byte[len];
    
try {
        FileInputStream fis 
= openFileInput(filename);
        ByteArrayOutputStream baos 
= new ByteArrayOutputStream();
        
int nrb = fis.read(buffer, 0, len); // read up to len bytes
        while (nrb != -1) {
            baos.write(buffer, 
0, nrb);
            nrb 
= fis.read(buffer, 0, len);
        }
        buffer 
= baos.toByteArray();
        fis.close();
    } 
catch (FileNotFoundException e) {
        e.printStackTrace();
    } 
catch (IOException e) {
        e.printStackTrace();
    }
    
return buffer;
}


清单 22 展示了如何从内部私有存储器删除数据。


清单 22. 从本地私有存储器删除数据

    
/**
 * Delete internal private file
 * @param filename - the filename to delete
 */
public void deleteInternalStoragePrivate(String filename) {
    File file = getFileStreamPath(filename);
    if (file != null) {
        file.delete();
    }
}


现在可以来看为公共数据使用外部存储器了。

回页首

为公共数据使用设备的外部存储器

有了数据存储 API,您可以使用外部存储器存储数据。信息可以是私有的,您可以有选择地让其他应用程序对之具有读或写的访问权限。本节您将对此 API 进行编程,以便使用包括getExternalStorageState()、getExternalFilesDir()、getExternalStorageDirectory() 和getExternalStoragePublicDirectory() 在内的很多 API 来存储公共数据。您为公共数据使用下面的路径:/Android/data/<package_name>/files/。

在使用外部存储器之前,必须看看它是否可用,是否可写。下面两个代码片段展示了测试这些条件的帮助器方法。清单 23 测试外部存储器是否可用。


清单 23. 测试外部存储器是否可用

    
/**
 * Helper Method to Test if external Storage is Available
 */
public boolean isExternalStorageAvailable() {
    boolean state = false;
    String extStorageState = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(extStorageState)) {
        state = true;
    }
    return state;
}


清单 24 测试外部存储器是否只可读。


清单 24. 测试外部存储器是否只可读

    
/**
 * Helper Method to Test if external Storage is read only
 */
public boolean isExternalStorageReadOnly() {
    boolean state = false;
    String extStorageState = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState)) {
        state = true;
    }
    return state;
}


清单 25 展示了如何写到外部存储器,以存储公共数据。


清单 25. 写到外部内存

    
/**
 * Write to external public directory
 * @param filename - the filename to write to
 * @param content - the content to write
 */
public void writeToExternalStoragePublic(String filename, byte[] content) {

    // API Level 7 or lower, use getExternalStorageDirectory()
    //  to open a File that represents the root of the external
    // storage, but writing to root is not recommended, and instead
    // application should write to application-specific directory, as shown below.

    String packageName = this.getPackageName();
    String path = "/Android/data/" + packageName + "/files/";

    if (isExternalStorageAvailable() &&
       !isExternalStorageReadOnly()) {
        try {
            File file = new File(path, filename);
            file.mkdirs();
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(content);
            fos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


清单 26 展示了如何从外部存储器读取数据。


清单 26. 从外部内存读取数据

    
/**
 * Reads a file from internal storage
 * @param filename - the filename to read from
 * @return the file contents
 */
public byte[] readExternallStoragePublic(String filename) {
    int len = 1024;
    byte[] buffer = new byte[len];
    String packageName = this.getPackageName();
    String path = "/Android/data/" + packageName + "/files/";

    if (!isExternalStorageReadOnly()) {     
        try {
            File file = new File(path, filename);            
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int nrb = fis.read(buffer, 0, len); //read up to len bytes
            while (nrb != -1) {
                baos.write(buffer, 0, nrb);
                nrb = fis.read(buffer, 0, len);
            }
            buffer = baos.toByteArray();
            fis.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return buffer;
}


清单 27 中的代码片段展示了如何从外部内存删除文件。


清单 27. 从外部内存删除文件

    
/**
 * Delete external public file
 * @param filename - the filename to write to
 */
void deleteExternalStoragePublicFile(String filename) {
    String packageName = this.getPackageName();
    String path = "/Android/data/" + packageName + "/files/"+filename;
    File file = new File(path, filename);
    if (file != null) {
        file.delete();
    }
}


处理外部存储器需要特殊的权限 WRITE_EXTERNAL_STORAGE,它通过 AndroidManifest.xml 请求得到(参见 清单 28)。


清单 28. WRITE_EXTERNAL_STORAGE

    
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>


外部存储 API 通过根据文件类型(比如 Pictures、Ringtones)将文件存储在预先确定的目录中,允许您公共地存储文件。本文没有介绍这种方法,但是您应该熟悉它。此外,记住外部存储器中的文件任何时候都可能消失。

回页首

相关的方法

如果您具有不需要长期永久保存的临时文件,那么可以将这些文件存储在高速缓存中。高速缓存是一种特殊的内存,可以用于存储中小型数据(少于兆字节),但是您一定要知道,取决于有多少内存可用,高速缓存的内容任何时候都可能被清除。

清单 29 展示了一个帮助器方法,它返回到内部内存中高速缓存的路径。


清单 29. 检索到内部内存高速缓存的路径

    
/**
 * Helper method to retrieve the absolute path to the application
 * specific internal cache directory on the file system. These files
 * will be ones that get deleted when the application is uninstalled or when
 * the device runs low on storage. There is no guarantee when these
 * files will be deleted.
 *
 * Note: This uses a Level 8+ API.
 *
 * @return the absolute path to the application specific cache
 * directory
 */
public String getInternalCacheDirectory() {
    String cacheDirPath = null;
    File cacheDir = getCacheDir();
    if (cacheDir != null) {
        cacheDirPath = cacheDir.getPath();
    }
    return cacheDirPath;        
}


清单 30 展示了一个帮助器方法,它返回到外部内存中高速缓存的路径。


清单 30. 检索到外部内存高速缓存的路径

    
/**
 * Helper method to retrieve the absolute path to the application
 * specific external cache directory on the file system. These files
 * will be ones that get deleted when the application is uninstalled or when
 * the device runs low on storage. There is no guarantee when these
 * files will be deleted.
 *
 * Note: This uses a Level 8+ API.
 *
 * @return the absolute path to the application specific cache
 * directory
 */
public String getExternalCacheDirectory() {
    String extCacheDirPath = null;
    File cacheDir = getExternalCacheDir();
    if (cacheDir != null) {
        extCacheDirPath = cacheDir.getPath();
    }
    return extCacheDirPath;     
}

 


通过使用示例应用程序,您现在应该很好地理解了如何为公共数据使用设备的外部存储器。

posted @ 2011-08-31 13:17 oathleo 阅读(2920) | 评论 (0)编辑 收藏

WebView对Javascript的支持也很强,google一个Java和Javascript互调的例子  
整个Eclipse ADT工程例子中都有,这里重点分析一下代码:
Java代码  收藏代码
  1. public class WebViewDemo extends Activity {  
  2.     private WebView mWebView;  
  3.     private Handler mHandler = new Handler();  
  4.   
  5.     public void onCreate(Bundle icicle) {  
  6.         super.onCreate(icicle);  
  7.         setContentView(R.layout.webviewdemo);  
  8.         mWebView = (WebView) findViewById(R.id.webview);  
  9.         WebSettings webSettings = mWebView.getSettings();  
  10.         webSettings.setJavaScriptEnabled(true);  
  11.         mWebView.addJavascriptInterface(new Object() {  
  12.             public void clickOnAndroid() {  
  13.                 mHandler.post(new Runnable() {  
  14.                     public void run() {  
  15.                         mWebView.loadUrl("javascript:wave()");  
  16.                     }  
  17.                 });  
  18.             }  
  19.         }, "demo");  
  20.         mWebView.loadUrl("file:///android_asset/demo.html");  
  21.     }  
  22. }  

这 里的重点是addJavascriptInterface(Object obj,String interfaceName)方法,该方法将一个java对象绑定到一个javascript对象中,javascript对象名就是 interfaceName,作用域是Global。这样初始化webview后,在webview加载的页面中就可以直接通过 javascript:window.demo访问到绑定的java对象了。来看看在html中是怎样调用的:

Html代码  收藏代码
  1. <html>  
  2.         <script language="javascript">  
  3.                 function wave() {  
  4.                     document.getElementById("droid").src="android_waving.png";  
  5.                 }  
  6.         </script>  
  7.         <body>  
  8.             <a onClick="window.demo.clickOnAndroid()">  
  9.                                 <img id="droid" src="android_normal.png"/><br>  
  10.                                 Click me!  
  11.             </a>  
  12.         </body>  
  13. </html>  

 这样在javascript中就可以调用java对象的clickOnAndroid()方法了,wave()方法是java中调用javascript的例子。

这里还有几个知识点:

1) 为了让WebView从apk文件中加载assets,Android SDK提供了一个schema,前缀为"file:///android_asset/"。WebView遇到这样的schema,就去当前包中的 assets目录中找内容。如上面的"file:///android_asset/demo.html"

2)addJavascriptInterface方法中要绑定的Java对象及方法要运行另外的线程中,不能运行在构造他的线程中,这也是使用Handler的目的。

posted @ 2011-08-25 15:36 oathleo 阅读(994) | 评论 (0)编辑 收藏

    <property name="proguard-home" value="D:/proguard4.4/lib"/>
    
<property name="android-jar" value="D:\android3.0\android-sdk_r12-windows\android-sdk-windows\platforms\android-8\android.jar"/>
//指定 proguard 地址和 android地址


<java jar="${proguard-home}/proguard.jar" fork="true" failonerror="true">
            
<jvmarg value="-Dmaximum.inlined.code.length=32" />
            
<arg value="-injars ${target_temp_jar}" />
            
<arg value="-outjars ${target_jar}" />
            
//第三方包
            <arg value="-libraryjars ${android-jar}" />
            
<arg value="-libraryjars lib/android_script.jar" />

            
<!--  <arg value="-libraryjars ${external-libs}/*.jar"/>-->
            
<arg value="-dontpreverify" />
            
<arg value="-dontoptimize" />
            
<arg value="-dontusemixedcaseclassnames" />
            
<arg value="-repackageclasses ''" />
            
<arg value="-allowaccessmodification" />
            
            
<!--保护public字段-->
            
<arg value="-keepclassmembers public class * { public protected *; }" />
            
<!--保护泛型-->
            
<arg value="-keepattributes Signature" />

            
<arg value="-keep public class com.xxxcore.*" />
            
<arg value="-keep public class com.xxxviewer.**" />
 
            
<arg value="-optimizationpasses 7" />
            
<arg value="-verbose" />
            
<arg value="-dontskipnonpubliclibraryclasses" />
            
<arg value="-dontskipnonpubliclibraryclassmembers" />
        
</java>

        
<signjar jar="${target_jar}" keystore="${sign.keystore}" alias="${sign.alias}" keypass="${sign.keypass}" storepass="${sign.storepass}"/>
        
<delete file="${target_temp_jar}" />
    
</target>




参数:

-include {filename}    从给定的文件中读取配置参数

-basedirectory {directoryname}    指定基础目录为以后相对的档案名称

-injars {class_path}    指定要处理的应用程序jar,war,ear和目录

-outjars {class_path}    指定处理完后要输出的jar,war,ear和目录的名称

-libraryjars {classpath}    指定要处理的应用程序jar,war,ear和目录所需要的程序库文件

-dontskipnonpubliclibraryclasses    指定不去忽略非公共的库类。

-dontskipnonpubliclibraryclassmembers    指定不去忽略包可见的库类的成员。


保留选项
-keep {Modifier} {class_specification}    保护指定的类文件和类的成员

-keepclassmembers {modifier} {class_specification}    保护指定类的成员,如果此类受到保护他们会保护的更好

-keepclasseswithmembers {class_specification}    保护指定的类和类的成员,但条件是所有指定的类和类成员是要存在。

-keepnames {class_specification}    保护指定的类和类的成员的名称(如果他们不会压缩步骤中删除)

-keepclassmembernames {class_specification}    保护指定的类的成员的名称(如果他们不会压缩步骤中删除)

-keepclasseswithmembernames {class_specification}    保护指定的类和类的成员的名称,如果所有指定的类成员出席(在压缩步骤之后)

-printseeds {filename}    列出类和类的成员-keep选项的清单,标准输出到给定的文件

压缩
-dontshrink    不压缩输入的类文件

-printusage {filename}

-whyareyoukeeping {class_specification}    

优化
-dontoptimize    不优化输入的类文件

-assumenosideeffects {class_specification}    优化时假设指定的方法,没有任何副作用

-allowaccessmodification    优化时允许访问并修改有修饰符的类和类的成员

混淆
-dontobfuscate    不混淆输入的类文件

-printmapping {filename}

-applymapping {filename}    重用映射增加混淆

-obfuscationdictionary {filename}    使用给定文件中的关键字作为要混淆方法的名称

-overloadaggressively    混淆时应用侵入式重载

-useuniqueclassmembernames    确定统一的混淆类的成员名称来增加混淆

-flattenpackagehierarchy {package_name}    重新包装所有重命名的包并放在给定的单一包中

-repackageclass {package_name}    重新包装所有重命名的类文件中放在给定的单一包中

-dontusemixedcaseclassnames    混淆时不会产生形形色色的类名

-keepattributes {attribute_name,}    保护给定的可选属性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses.

-renamesourcefileattribute {string}    设置源文件中给定的字符串常量

posted @ 2011-08-24 14:39 oathleo 阅读(2495) | 评论 (0)编辑 收藏

注意
1.onDown 多指事件仍然响应成单指
2.onScroll滑动时触发,e1只能获得一个点 ,而e2却能获得多点。(搞不清楚为什么怎么设计)
3.想在view上加 GestureListener
可以使用下面的代码:
public class ViewerInnerTouchListener implements OnTouchListener {

    
private GestureDetector gestureDetector;

    
public ViewerInnerTouchListener(GAViewer viewer) {
        gestureDetector 
= new GestureDetector(new GestureListener(viewer));
    }

    
public boolean onTouch(View v, MotionEvent event) {
        gestureDetector.onTouchEvent(event);
        
return true;
    }

}

    setOnTouchListener(
new ViewerInnerTouchListener(this));

判断手势:
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        
if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
            Log.i(
"onFling""onFling");
            
return true// Right to left
        } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
            
return false// Left to right
        }
        
if (e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {
            
return false// Bottom to top
        } else if (e2.getY() - e1.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {
            
return false// Top to bottom
        }
        
return false;
    }


GestureListener 的几个方法要理解
     //Touch down时触发,不论是touch (包括long) ,scroll
     public boolean onDown(MotionEvent e) {
     return false;
     }
    
     //Touch了还没有滑动时触发
     //(与onDown,onLongPress比较
     //onDown只要Touch down一定立刻触发。
     public void onShowPress(MotionEvent e) {
     }
    
     //Touch了不移动一直Touch down时触发
     //Touchdown后过一会没有滑动先触发onShowPress再是onLongPress。
     public void onLongPress(MotionEvent e) {
     }
    
     //上面这两个函数都是在touch down后又没有滑动(onScroll),又没有长按(onLongPress),然后Touchup时触发。
     /**
     * 点击一下非常快的(不滑动)Touchup: onDown->onSingleTapUp->onSingleTapConfirmed
     *
     点击一下稍微慢点的(不滑动)Touchup:onDown->onShowPress->onSingleTapUp->onSingleTapConfirmed
     * 点击longpress ,onScroll 时 不触发 onSingleTapUp
     */
     public boolean onSingleTapUp(MotionEvent e) {
     Log.i("onSingleTapUp", "onSingleTapUp");
     return false;
     }
    
     //Touch了滑动时触发
     public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
     float distanceY) {
     return true;
     }
    
     //Touch了滑动一点距离后,up时触发
     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
     float velocityY) {
     return true;
     }

posted @ 2011-08-21 11:59 oathleo 阅读(3238) | 评论 (0)编辑 收藏

之 前一直没有搞懂android:padding和android:layout_margin的区别,其实概念很简单,padding是站在父view的 角度描述问题,它规定它里面的内容必须与这个父view边界的距离。margin则是站在自己的角度描述问题,规定自己和其他(上下左右)的view之间 的距离,如果同一级只有一个view,那么它的效果基本上就和padding一样了

posted @ 2011-08-18 16:33 oathleo 阅读(306) | 评论 (0)编辑 收藏

layout在xml里是无法使用findView 找到的

只能使用:
View menu = inflater.inflate(R.layout.main_left_layout, null);

获得
LayoutInflater 的方法:
1.Activity
LayoutInflater inflater = getLayoutInflater(); 
2.
LayoutInflater inflater = LayoutInflater.from(context);



posted @ 2011-08-16 12:53 oathleo 阅读(227) | 评论 (0)编辑 收藏

1、XML资源文件可以被AAPT打包进应用程序包,如果需要被打包,放置在/res/xml目录下,如果不需要被打包,放置在/res/raw下。

2、对/res/xml的支持

以读取/res/xml/test.xml为例

Resources res=activity.getResources();

XmlResourceParser xpp=res.getxml(R.xml.test);

inet eventType=xpp.getEventType();

再根据evenType的类型,判断读取了什么内容,比如说,读到了文档的开头,XmlPullParser.START_DOCUMENT等

使用xpp.getName()取得标志名称,使用xpp.getText()取得文本内容

最后

eventType=xpp.next();来读取下一行内容

3、对/res/raw的支持

以读取/res/raw/test.txt为例

Resources r=activity.getResources();

InputStream is=r.openRawResource(R.raw.test);

4、资产

/assets不会在R.java中生成资源ID,必须指定文件路径才能读取它们。文件路径是以/assets开头的相对路径。

AssetManger am=activity.getAssets();

InputStream is=am.open("test.txt");

posted @ 2011-08-08 11:24 oathleo 阅读(485) | 评论 (0)编辑 收藏

     摘要: 在Android 2.3状态栏中添加menu,home和back快捷键的方法 1、准备资源,修改XML文准备几张图,这里我们准备添加home back和menu图标,就需要准备6张图,三张普通状态,三张按下的高亮状态图标:stat_home.pngstat_home_pressed.pngstat_back.pngstat_back_pressed.pngstat_menu.pngstat_men...  阅读全文

posted @ 2011-08-05 15:45 oathleo 阅读(1120) | 评论 (0)编辑 收藏

和奇怪,调试模式下的SAX和script
效率巨慢,而运行模式下,好很多,大概快5-10倍。

另外script包会编译一个print方法,这个过程耗时很多,严重影响效率
去掉并做些优化后
500条脚本,执行从1s缩减到200ms

代码精简如下:
RhinoScriptEngine.java
    Scriptable getRuntimeScope(ScriptContext ctxt) {
        
if (ctxt == null) {
            
throw new NullPointerException("null script context");
        }

        
// we create a scope for the given ScriptContext
        Scriptable newScope = new ExternalScriptable(ctxt, indexedProps);

        
// Set the prototype of newScope to be 'topLevel' so that
        
// JavaScript standard objects are visible from the scope.
        newScope.setPrototype(topLevel);

        
// define "context" variable in the new scope
        newScope.put("context", newScope, ctxt);

        
// define "print", "println" functions in the new scope
        //去掉下面几行
//        Context cx = enterContext();
//        try {
//            cx.evaluateString(newScope, printSource, "print", 1, null);
//        } finally {
//            cx.exit();
//        }
        return newScope;
    }

posted @ 2011-08-03 14:18 oathleo 阅读(1500) | 评论 (0)编辑 收藏

script包源码包括:
sun\script\javascript
script

org\mozilla\javascript

其中
org\mozilla\javascript
是真正的javascript实现 源码1M多

一起打包完大概860K

posted @ 2011-08-01 11:08 oathleo 阅读(1938) | 评论 (3)编辑 收藏

     摘要:   中文: http://www.chinaup.org/docs/toolbox/performance.html 英文: /android-sdk/docs/guide/guide_toc.html   尽量避免创建对象 使用自身方法 使用虚拟优于使用接口 使用静态优于使用虚拟 避免内部使用Setter和Getter 缓冲属性调用 声明Final常量 慎重使...  阅读全文

posted @ 2011-07-31 08:31 oathleo 阅读(450) | 评论 (0)编辑 收藏

遇到的情况
AsyncTask
protected GAViewer doInBackground(Activity... params) {
    ......
    GAViewer viewer = new GAViewer(result, drawActivity.getApplicationContext());
    return viewer;
}

产生
Can't create handler inside thread that has not called Looper.prepare()
异常

原因估计
1.viewer 是个 SurfaceView ,而doInBackground是不允许操作UI的
2.drawActivity.getApplicationContext() 已经操作了UI ?maybe

posted @ 2011-07-30 10:04 oathleo 阅读(4251) | 评论 (1)编辑 收藏

3000行的多层次XML,
环境2.2,Xoom

XmlPullParser  2000ms 以上
SAXParser       200ms 不到

原因不知道~暂时没空深层研究了
 

posted @ 2011-07-30 10:00 oathleo 阅读(1517) | 评论 (2)编辑 收藏

高级画布绘图(3)

DashPathEffect  可以使用DashPathEffect来创建一个虚线的轮廓(短横线/小圆点),而不是使用实线。你还可以指定任意的虚/实线段的重复模式。

DiscretePathEffect  与DashPathEffect相似,但是添加了随机性。当绘制它的时候,需要指定每一段的长度和与原始路径的偏离度。

PathDashPathEffect  这种效果可以定义一个新的形状(路径)并将其用作原始路径的轮廓标记。

下面的效果可以在一个Paint中组合使用多个Path Effect。

SumPathEffect  顺序地在一条路径中添加两种效果,这样每一种效果都可以应用到原始路径中,而且两种结果可以结合起来。

ComposePathEffect  将两种效果组合起来应用,先使用第一种效果,然后在这种效果的基础上应用第二种效果。

对象形状的PathEffect的改变会影响到形状的区域。这就能够保证应用到相同形状的填充效果将会绘制到新的边界中。

使用setPathEffect方法可以把PathEffect应用到Paint对象中,如下所示:

  1. borderPaint.setPathEffect(new CornerPathEffect(5)); 

PathEffect API示例给出了如何应用每一种效果的指导说明。

修改Xfermode

可以通过修改Paint的Xfermode来影响在Canvas已有的图像上面绘制新的颜色的方式。

在正常的情况下,在已有的图像上绘图将会在其上面添加一层新的形状。如果新的Paint是完全不透明的,那么它将完全遮挡住下面的Paint;如果它是部分透明的,那么它将会被染上下面的颜色。

下面的Xfermode子类可以改变这种行为:

AvoidXfermode  指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图)。

PixelXorXfermode  当覆盖已有的颜色时,应用一个简单的像素XOR操作。

PorterDuffXfermode  这是一个非常强大的转换模式,使用它,可以使用图像合成的16条Porter-Duff规则的任意一条来控制Paint如何与已有的Canvas图像进行交互。

要应用转换模式,可以使用setXferMode方法,如下所示:

  1. AvoidXfermode avoid = new AvoidXfermode(Color.BLUE, 10, AvoidXfermode.Mode. AVOID);  
  2. borderPen.setXfermode(avoid); 

3. 使用抗锯齿效果提高Paint质量

在绘制一个新的Paint对象时,可以通过传递给它一些标记来影响它被渲染的方式。ANTI_ALIAS_FLAG是其中一种很有趣的标记,它可以保证在绘制斜线的时候使用抗锯齿效果来平滑该斜线的外观。

在绘制文本的时候,抗锯齿效果尤为重要,因为经过抗锯齿效果处理之后的文本非常容易阅读。要创建更加平滑的文本效果,可以应用SUBPIXEL_TEXT_FLAG,它将会应用子像素抗锯齿效果。

也可以手工地使用setSubpixelText和setAntiAlias方法来设置这些标记,如下所示:

  1. myPaint.setSubpixelText(true);  
  2. myPaint.setAntiAlias(true); 

4. 2D图形的硬件加速

在当前这个到处都是2D图形爱好者的时代,Android允许你使用硬件加速来渲染你的应用程序。

如果设备可以使用硬件加速,那么通过设置这个标记可以让活动中的每一个View都能使用硬件渲染。尽管减少了系统处理程序的负载,但在极大地提高了图像处理速度的同时,硬件加速也带来了相应的负面效果。

使用requestWindowFeature方法,可以在你的活动中应用Window.FEATURE_OPENGL标记来打开硬件加速,如下所示:

  1. myActivity.requestWindowFeature(Window.FEATURE_OPENGL); 

遗憾的是,天上不会掉馅饼,这次也不例外。

并不是Android中所有的2D绘图基本图形都被硬件支持(特别是前面描述的大部分PathEffect)。

与此同时,由于整个活动实际上是作为一个Canvas进行渲染的,所以对任何View的无效请求都将会导致整个活动被重新绘制。

5. Canvas绘图最佳实践经验

2D自绘操作是非常耗费处理程序资源的;低效的绘图方法会阻塞GUI线程,并且会对应用程序的响应造成不利的影响。对于那些只有一个处理程序的资源受限的环境来说,这一点就更加现实了。

这里需要注意onDraw方法的资源消耗以及CPU周期的耗费,这样才能保证不会把一个看起来很吸引人的应用程序变得完全没有响应。

目前有很多技术可以帮助将与自绘控件相关的资源消耗最小化。我们关心的不是一般的原则,而是某些Android特定的注意事项,从而保证你可以创建外观时尚、而且能够保持交互的活动(注意,以下这个列表并不完整):

考虑硬件加速  OpenGL硬件加速对2D图形的支持是非常好的,所以你总是应该考虑它是否适合你的活动。另一种比较优秀的方法是只用一个单独的View和迅速的、耗时的更新来组成活动。一定要保证你使用的基本图形能够被硬件支持。

考虑大小和方向  当在设计View和布局的时候,一定要保证考虑(和测试)它们在不同的分辨率和大小下的外观。

只创建一次静态对象  在Android中对象的创建是相当昂贵的。因此,在可能的地方,应用只创建一次像Paint对象、Path和Shader这样的绘图对象,而不是在View每次无效的时候都重新创建它们。

记住onDraw是很消耗资源的  执行onDraw方法是很消耗资源的处理,它会强制Android执行多个图片组合和位图构建操作。下面有几点建议可以让你修改Canvas的外观,而不用重新绘制它:

使用Canvas转换  可以使用像rotate和translate这样的转换,来简化Canvas中元素复杂的相关位置。例如,相比放置和旋转一个表盘周围的每一个文本元素,你可以简单地将canvas旋转22.5?,然后在相同的位置绘制文本。

使用动画  可以考虑使用动画来执行View的预设置的转换,而不是手动地重新绘制它。在活动的View中可以执行缩放、旋转和转换动画,并可以提供一种能够有效利用资源的方式来提供缩放、旋转或者抖动效果。

考虑使用位图和9 Patch  如果View使用了静态背景,那么你应该考虑使用一个图片,如位图或者9 patch,而不是手动地重新绘制。

posted @ 2011-07-26 11:35 oathleo 阅读(429) | 评论 (0)编辑 收藏

11.4.3  高级画布绘图(2)

提示:

图11-1中没有包含的是ComposerShader,它可以创建多个Shader和BitmapShader的组合,从而可以在一个位图图像的基础上创建一个绘图刷。

要在绘图的时候使用一个Shader,可以使用setShader方法将其应用到一个Paint中,如下面的代码所示:

  1. Paint shaderPaint = new Paint();  
  2. shaderPaint.setShader(myLinearGradient); 

你使用这个Paint所绘制的任何东西都将使用你指定的Shader进行填充,而不是使用Paint本身的颜色进行填充。

定义渐变Shader

如上所示,使用渐变Shader可以让你使用交替改变的颜色来填充图片;你可以将颜色渐变定义为两种颜色的简单交替,如下所示:

  1. int colorFrom = Color.BLACK;  
  2. int colorTo = Color.WHITE;  
  3.  
  4. LinearGradient linearGradientShader = new LinearGradient(x1, y1, x2, y2,  
  5.                                                          colorFrom,  
  6.                                                          colorTo,  
  7.                                                          TileMode.CLAMP); 

或者,你还可以定义更复杂的按照设定比例进行分布的颜色序列,如下面的RadialGradientShader例子所示:

  1. int[] gradientColors = new int[3];  
  2. gradientColors[0] = Color.GREEN;  
  3. gradientColors[1] = Color.YELLOW;  
  4. gradientColors[2] = Color.RED;  
  5.  
  6. float[] gradientPositions = new float[3];  
  7. gradientPositions[0] = 0.0f;  
  8. gradientPositions[1] = 0.5f;  
  9. gradientPositions[2] = 1.0f;  
  10.  
  11. RadialGradient radialGradientShader=new RadialGradient(centerX,centerY, radius,  
  12.                                                          gradientColors,  
  13.                                                          gradientPositions,  
  14.                                                          TileMode.CLAMP); 

每一种渐变Shader(线性的、辐射形的和扫描状的)都可以使用以上这两种技术来定义渐变填充。

使用Shader TileModes

渐变Shader的画刷大小既可以显式地使用有边界的矩形来定义,也可以使用中心点和半径长度来定义。Bitmap Shader可以通过它的位图大小来决定它的画刷大小。

如果Shader画刷所定义的区域比要填充的区域小,那么TileMode将会决定如何处理剩余的区域:

CLAMP  使用Shader的边界颜色来填充剩余的空间。

MIRROR  在水平和垂直方向上拉伸Shader图像,这样每一个图像就都能与上一个缝合了。

REPEAT  在水平和垂直方向上重复Shader图像,但不拉伸它。

使用MaskFilter

MaskFilter类可以为Paint分配边缘效果。

对MaskFilter的扩展可以对一个Paint边缘的alpha通道应用转换。Android包含了下面几种MaskFilter:

BlurMaskFilter   指定了一个模糊的样式和半径来处理Paint的边缘。

EmbossMaskFilter  指定了光源的方向和环境光强度来添加浮雕效果。

要应用一个MaskFilter,可以使用setMaskFilter方法,并传递给它一个MaskFilter对象。下面的例子是对一个已经存在的Paint应用一个EmbossMaskFilter:

  1. // 设置光源的方向  
  2. float[] direction = new float[]{ 1, 1, 1 };  
  3. //设置环境光亮度  
  4. float light = 0.4f;  
  5. // 选择要应用的反射等级  
  6. float specular = 6;  
  7. // 向mask应用一定级别的模糊  
  8. float blur = 3.5f;  
  9. EmbossMaskFilter emboss=new EmbossMaskFilter(direction,light,specular,blur);  
  10.  
  11. // 应用mask  
  12. myPaint.setMaskFilter(emboss); 

SDK中包含的FingerPaint API demo是说明如何使用MaskFilter的一个非常好的例子。它展示了这两种filter的效果。

使用ColorFilter

MaskFilter是对一个Paint的alpha通道的转换,而ColorFilter则是对每一个RGB通道应用转换。所有由ColorFilter所派生的类在执行它们的转换时,都会忽略alpha通道。

Android包含三个ColorFilter:

ColorMatrixColorFilter  可以指定一个4×5的ColorMatrix并将其应用到一个Paint中。ColorMatrixes通常在程序中用于对图像进行处理,而且由于它们支持使用矩阵相乘的方法来执行链接转换,所以它们很有用。

LightingColorFilter  乘以第一个颜色的RGB通道,然后加上第二个颜色。每一次转换的结果都限制在0到255之间。

PorterDuffColorFilter  可以使用数字图像合成的16条Porter-Duff 规则中的任意一条来向Paint应用一个指定的颜色。

使用setColorFilter方法应用ColorFilter,如下所示:

myPaint.setColorFilter(new LightingColorFilter(Color.BLUE, Color.RED));

API中的ColorMatrixSample是说明如何使用ColorFilter和Color Matrix的非常好的例子。

使用PathEffect

到目前为止,所有的效应都会影响到Paint填充图像的方式;PathEffect是用来控制绘制轮廓(线条)的方式。

PathEffect对于绘制Path基本图形特别有用,但是它们也可以应用到任何Paint中从而影响线条绘制的方式。

使用PathEffect,可以改变一个形状的边角的外观并且控制轮廓的外表。Android包含了多个PathEffect,包括:

CornerPathEffect  可以使用圆角来代替尖锐的角从而对基本图形的形状尖锐的边角进行平滑。

posted @ 2011-07-26 11:33 oathleo 阅读(281) | 评论 (0)编辑 收藏

11.4.3  高级画布绘图(1)

我们已经在第4章中介绍了Canvas,在那里,已经学习了如何创建自己的View。在第7章中也使用了Canvas来为MapView标注覆盖。

画布(Canvas)是图形编程中一个很普通的概念,通常由三个基本的绘图组件组成:

Canvas  提供了绘图方法,可以向底层的位图绘制基本图形。

Paint  也称为"刷子",Paint可以指定如何将基本图形绘制到位图上。

Bitmap  绘图的表面。

这一章中描述的大部分高级技术都涉及到了对Paint对象的变化和修改,从而可以向那些平面的光栅图片添加深度和纹理。

Android绘图API支持透明度、渐变填充、圆边矩形和抗锯齿。遗憾的是,由于资源限制,它还不支持矢量图形,它使用的是传统光栅样式的重新绘图。

这种光栅方法的结果是提高了效率,但是改变一个Paint对象不会影响已经画好的基本图形,它只会影响新的元素。

提示:

如果你拥有Windows开发背景,那么Android的2D绘图能力大致相当于GDI+的能力。

1. 可以画什么?

Canvas类封装了用作绘图表面的位图;它还提供了draw*方法来实现设计。

下面的列表提供了对可用的基本图形的简要说明,但并没有深入地探讨每一个draw方法的详细内容:

drawARGB / drawRGB / drawColor  使用单一的颜色填充画布。

drawArc  在一个矩形区域的两个角之间绘制一个弧。

drawBitmap  在画布上绘制一个位图。可以通过指定目标大小或者使用一个矩阵来改变目标位图的外观。

drawBitmapMesh  使用一个mesh(网)来绘制一个位图,它可以通过移动网中的点来操作目标的外观。

drawCircle  以给定的点为圆心,绘制一个指定半径的圆。

drawLine(s)  在两个点之间画一条(多条)直线。

drawOval  以指定的矩形为边界,画一个椭圆。

drawPaint  使用指定的Paint填充整个Canvas

drawPath  绘制指定的Path。Path对象经常用来保存一个对象中基本图形的集合。

drawPicture  在指定的矩形中绘制一个Picture对象。

drawPosText  绘制指定了每一个字符的偏移量的文本字符串。

drawRect  绘制一个矩形。

drawRoundRect  绘制一个圆角矩形。

drawText  在Canvas上绘制一个文本串。文本的字体、大小和渲染属性都设置在用来渲染文本的Paint对象中。

drawTextOnPath  在一个指定的path上绘制文本。

drawVertices  绘制一系列三角形面片,通过一系列顶点来指定它们。

这些绘图方法中的每一个都需要指定一个Paint对象来渲染它。在下面的部分中,将学习如何创建和修改Paint对象,从而在绘图中完成大部分工作。

2. 从Paint中完成工作

Paint类相当于一个笔刷和调色板。它可以选择如何使用上面描述的draw方法来渲染绘制在画布上的基本图形。通过修改Paint对象,可以在绘 图的时候控制颜色、样式、字体和特殊效果。最简单地,setColor可以让你选择一个Paint的颜色,而Paint对象的样式(使用setStyle 控制)则可以决定是绘制绘图对象的轮廓(STROKE),还是只填充每一部分(FILL),或者是两者都做(STROKE_AND_FILL)

除了这些简单的控制之外,Paint类还支持透明度,另外,它也可以通过使用各种各样的阴影、过滤器和效果进行修改,从而提供由更丰富的、复杂的画笔和颜料组成的调色板。

Android SDK包含了一些非常好的实例,它们说明了Paint类中可用的大部分功能。你可以在API demos的graphics子目录中找到它们:

  1. [sdk root folder]\samples\ApiDemos\src\com\android\samples\graphics 

在下面的部分中,将学习和使用其中的部分功能。这些部分只是简单地罗列了它们能实现的效果(例如渐变和边缘浮雕),而没有详细地列出所有可能的情况。

使用透明度

Android中的所有颜色都包含了一个不透明组件(alpha通道)。

当创建一个颜色的时候,可以使用argb或者parseColor方法来定义它的alpha值,如下所示:

  1. // 使用红色,并让它50%透明  
  2. int opacity = 127;  
  3. int intColor = Color.argb(opacity, 255, 0, 0);  
  4. int parsedColor = Color.parseColor("#7FFF0000"); 

或者,也可以使用setAlpha方法来设置已存在的Paint对象的透明度:

  1. // 让颜色50%透明  
  2. int opacity = 127;  
  3. myPaint.setAlpha(opacity); 

创建一个不是100%透明的颜色意味着,使用它绘制的任何基本图形都将是部分透明的--也就是说,在它下面绘制的所有基本图形都是部分可见的。

可以在任何使用了颜色的类或者方法中使用透明效果,包括Paint、Shader和Mask Filter。

Shader介绍

Shader类的派生类可以创建允许使用多种固体颜色填充绘图对象的Paint。

对Shader最常见的使用是定义渐变填充;渐变是在2D图像中添加深度和纹理的最佳方式之一。Android包含了一个Bitmap Shader和一个Compose Shader,同时,还包含了三个渐变的Shader。

试图用语言来描述绘图的效果本来就是没有意义的,所以看一下图11-1就应该可以知道每一种Shader是如何工作的。图中从左到右依次代表的是LinearGradient、RadialGradient和 SweepGradient.

 
(点击查看大图)图11-1

posted @ 2011-07-26 11:14 oathleo 阅读(335) | 评论 (0)编辑 收藏

    大家好,今天和大家分享的是Android中渲染图像和图形的类,这也是我第一次在Linux上写Android程序,呵呵,感觉还不错!

    切入正题:Shader有几个直接子类:

    BitmapShader    : 图像渲染

    LinearGradient  : 线性渐变

    RadialGradient  : 环形渐变

    SweepGradient   : 扫描渐变---围绕一个中心点扫描渐变就像电影里那种雷达扫描

    ComposeShader   : 组合渲染

    先看效果图:


    先保存好你要在BitmapShader中显示的图片.

     

    看代码(代码中带有注释):

    我采用的还是SurefaceView框架,

     

    1. package com.ldj.helloshader;  
    2. import android.content.Context;  
    3. import android.graphics.*;  
    4. import android.graphics.Shader.TileMode;  
    5. import android.graphics.drawable.BitmapDrawable;  
    6. import android.graphics.drawable.ShapeDrawable;  
    7. import android.graphics.drawable.shapes.OvalShape;  
    8. import android.view.*;  
    9. public class ShaderView extends SurfaceView implements SurfaceHolder.Callback,Runnable{  
    10.     //声明渐变的颜色数组  
    11.     private int[] color =   
    12.         new int[]{Color.GREEN,Color.GRAY,Color.MAGENTA,Color.RED,Color.WHITE};  
    13.     private boolean loop = false;  
    14.     private SurfaceHolder surfaceHolder;  
    15.       
    16.     private Bitmap bitPic = null;  
    17.       
    18.     int bitPicWidth = 0;  
    19.     int bitPicHeight = 0;  
    20.       
    21.     //声明一个图片渲染  
    22.     BitmapShader bitmapShader = null;  
    23.     //声明一个线性渐变  
    24.     LinearGradient linearGradient = null;  
    25.     //声明一个环形渐变  
    26.     RadialGradient radialGradient = null;  
    27.     //声明一个扫描渐变  
    28.     //-围绕一个中心点扫描渐变就像电影里那种雷达扫描  
    29.     SweepGradient sweepGradient = null;  
    30.     //声明一个组合渲染  
    31.     ComposeShader composeShader = null;  
    32.     //定义画笔  
    33.     Paint paint = null;  
    34.     //利用这个类也可以实现绘制图像的功能  
    35.     ShapeDrawable shapeDrawable = null;  
    36.       
    37.     public ShaderView(Context context) {  
    38.         super(context);  
    39.         surfaceHolder = this.getHolder();  
    40.         //增加回调  
    41.         surfaceHolder.addCallback(this);  
    42.         loop = true;  
    43.         paint = new Paint();  
    44.         //获取图像资源  
    45.         bitPic =   
    46.             ((BitmapDrawable)this.getResources().getDrawable(R.drawable.screenshot))  
    47.             .getBitmap();  
    48.         //将图片的长和高的值赋给变量  
    49.         bitPicWidth = bitPic.getWidth();  
    50.         bitPicHeight = bitPic.getHeight();  
    51.         /* 
    52.          * ~~~BitmapShader(Bitmap,TileMode,TileMode)~~~ 
    53.          */  
    54.         bitmapShader = new BitmapShader(bitPic, TileMode.REPEAT, TileMode.MIRROR);  
    55.         /* 
    56.          * ~~~LinearGradient(x0,y0,x1,y1,int[Color],float[],TileMode)~~~ 
    57.          */  
    58.         linearGradient = new LinearGradient(0,0,100,100,color,null,TileMode.REPEAT);  
    59.         /* 
    60.          * ~~~RadialGradient~~~ 
    61.          */  
    62.         radialGradient = new RadialGradient(160,240,66,color,null,TileMode.MIRROR);  
    63.         /* 
    64.          * ~~~SweepGradient~~~ 
    65.          */  
    66.         sweepGradient = new SweepGradient(100,350,color,null);  
    67.         //~~~ComposeShader(shaderA,shaderB,Mode)~~~  
    68.         //组合线性和环形两种渐变,当然其他的也可以的  
    69.         composeShader   
    70.             = new ComposeShader(linearGradient,radialGradient,PorterDuff.Mode.DARKEN);  
    71.     }  
    72.     @Override  
    73.     public void run() {  
    74.         while(loop) {  
    75.             draw();  
    76.             try {  
    77.                 Thread.sleep(100);  
    78.             } catch (InterruptedException e) {  
    79.                 e.printStackTrace();  
    80.             }  
    81.         }  
    82.     }  
    83.     @Override  
    84.     public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {  
    85.     }  
    86.     @Override  
    87.     public void surfaceCreated(SurfaceHolder arg0) {  
    88.         new Thread(this).start();  
    89.     }  
    90.     @Override  
    91.     public void surfaceDestroyed(SurfaceHolder arg0) {  
    92.         loop = false;  
    93.     }  
    94.       
    95.     private void draw() {  
    96.         Canvas canvas = surfaceHolder.lockCanvas();  
    97.         /* 
    98.          * ~~~BitmapShader 
    99.          */  
    100.         //构造形状为椭圆的shapeDrawable对象  
    101.         shapeDrawable = new ShapeDrawable(new OvalShape());  
    102.         //设置显示的图片  
    103.         shapeDrawable.getPaint().setShader(bitmapShader);  
    104.         //设置显示的长和高  
    105.         shapeDrawable.setBounds(0, 0, bitPicWidth, bitPicHeight);  
    106.         //绘制图像  
    107.         shapeDrawable.draw(canvas);  
    108.         //~~~LinearGradient~~~  
    109.         //设置画笔的渲染类型  
    110.         paint.setShader(linearGradient);  
    111.         canvas.drawRect(0, bitPicHeight, 320, 150, paint);  
    112.         //~~~RadialGradient~~~  
    113.         paint.setShader(radialGradient);  
    114.         canvas.drawCircle(160, 240, 66, paint);  
    115.         //~~~SweepGradient  
    116.         paint.setShader(sweepGradient);  
    117.         canvas.drawCircle(100, 350, 66, paint);  
    118.         //~~~ComposeShader~~~  
    119.         paint.setShader(composeShader);  
    120.         canvas.drawRect(bitPicWidth, 320, 320, 480, paint);  
    121.         surfaceHolder.unlockCanvasAndPost(canvas);  
    122.     }  
    123. }  

     

    总结:

    配色弄的不是很好看,大家可别见怪,大体来说渲染图像或图形三步:

    首先是声明渲染或渐变类。

    然后将画笔setShader为声明的类。

    最后绘制的时候用此画笔即可。

    好了,今天到这里了,谢谢大家阅读。


posted @ 2011-07-25 11:41 oathleo 阅读(1204) | 评论 (0)编辑 收藏

 void  setARGB(int a, int r, int g, int b)  设置Paint对象颜色,参数一为alpha透明通道

void  setAlpha(int a)  设置alpha不透明度,范围为0~255

void  setAntiAlias(boolean aa)  //是否抗锯齿

void  setColor(int color)  //设置颜色,这里Android内部定义的有Color类包含了一些常见颜色定义
 .
void  setFakeBoldText(boolean fakeBoldText)  //设置伪粗体文本
  
void  setLinearText(boolean linearText)  //设置线性文本
 
PathEffect  setPathEffect(PathEffect effect)  //设置路径效果
 
Rasterizer  setRasterizer(Rasterizer rasterizer) //设置光栅化
 
Shader  setShader(Shader shader)  //设置阴影 

void  setTextAlign(Paint.Align align)  //设置文本对齐

void  setTextScaleX(float scaleX)  //设置文本缩放倍数,1.0f为原始
 
void  setTextSize(float textSize)  //设置字体大小
 
Typeface  setTypeface(Typeface typeface)  //设置字体,Typeface包含了字体的类型,粗细,还有倾斜、颜色等。

 void  setUnderlineText(boolean underlineText)  //设置下划线


Paint paint = new Paint();
 
       paint.setAntiAlias(true);          //防锯齿
        paint.setDither(true);            //防抖动
        paint.setStyle(Paint.Style.STROKE);          //画笔类型 STROKE空心 FILL 实心

posted @ 2011-07-25 10:52 oathleo 阅读(2526) | 评论 (0)编辑 收藏

触发
 android.view.SurfaceHolder.Callback
1.surfaceDestroyed
2.surfaceCreated
3.surfaceChanged

posted @ 2011-07-21 15:18 oathleo 阅读(445) | 评论 (0)编辑 收藏


在android中context可以作很多操作,但是最主要的功能是加载和访问资源。在android中有两种context,
一种是 application context,一种是activity context,通常我们在各种类和方法间传递的是activity context。
比如一个activity的onCreate:
protected void onCreate(Bundle state) {
        super.onCreate(state);

        TextView label = new TextView(this); //传递context给view control
        label.setText("Leaks are bad");

        setContentView(label);
}
把activity context传递给view,意味着view拥有一个指向activity的引用,进而引用activity占有的资源:view hierachy, resource等。
这样如果context发生内存泄露的话,就会泄露很多内存。
这里泄露的意思是gc没有办法回收activity的内存。

Leaking an entire activity是很容易的一件事。

当屏幕旋转的时候,系统会销毁当前的activity,保存状态信息,再创建一个新的。

比如我们写了一个应用程序,它需要加载一个很大的图片,我们不希望每次旋转屏 幕的时候都销毁这个图片,重新加载。
实现这个要求的简单想法就是定义一个静态的Drawable,这样Activity 类创建销毁它始终保存在内存中。
实现类似:
public class myactivity extends Activity {
        private static Drawable sBackground;
        protected void onCreate(Bundle state) {
                super.onCreate(state);

                TextView label = new TextView(this);
                label.setText("Leaks are bad");

                if (sBackground == null) {
                        sBackground = getDrawable(R.drawable.large_bitmap);
                }
        label.setBackgroundDrawable(sBackground);//drawable attached to a view

        setContentView(label);
        }
}
这段程序看起来很简单,但是却问题很大。当屏幕旋转的时候会有leak(即gc没法销毁activity)。
我们刚才说过,屏幕旋转的时候系统会销毁当前的activity。但是当drawable和view关联后,drawable保存了view的 reference,即sBackground保存了label的引用,
而label保存了activity的引用。既然drawable不能销毁,它所 引用和间接引用的都不能销毁,这样系统就没有办法销毁当前的activity,于是造成了内存泄露。
gc对这种类型的内存泄露是无能为力的。

避免这种内存泄露的方法是避免activity中的任何对象的生命周期长过activity,避免由于对象对 activity的引用导致activity不能正常被销毁。
我们可以使用application context。application context伴随application的一生,与activity的生命周期无关。
application context可以通过Context.getApplicationContext或者Activity.getApplication方法获取。

避免context相关的内存泄露,记住以下几点:
1. 不要让生命周期长的对象引用activity context,即保证引用activity的对象要与activity本身生命周期是一样的
2. 对于生命周期长的对象,可以使用application context
3. 避免非静态的内部类,尽量使用静态类,避免生命周期问题,注意内部类对外部对象引用导致的生命周期变化

posted @ 2011-07-21 14:57 oathleo 阅读(699) | 评论 (0)编辑 收藏

http://blog.csdn.net/hellogv/article/details/5986835
  上一篇简 单介绍了SurfaceView的基本使用,这次就介绍SurfaceView与多线程的混搭。SurfaceView与多线程混搭,是为了防止动画闪烁 而实现的一种多线程应用。android的多线程用法与JAVA的多线程用法完全一样,本文不做多线程方面的介绍了。直接讲解SurfaceView与多 线程的混合使用,即开一条线程专门读取图片,另外一条线程专门绘图。

        本文程序运行截图如下,左边是开单个线程读取并绘图,右边是开两个线程,一个专门读取图片,一个专门绘图:

对 比一下,右边动画的帧速明显比左边的快,左右两者都没使用Thread.sleep()。为什么要开两个线程一个读一个画,而不去开两个线程像左边那样都 “边读边画”呢?因为SurfaceView每次绘图都会锁定Canvas,也就是说同一片区域这次没画完下次就不能画,因此要提高动画播放的效率,就得开一条线程专门画图,开另外一条线程做预处理的工作。

main.xml的源码:

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent" android:layout_height="fill_parent"  
  4.     android:orientation="vertical">  
  5.   
  6.     <LinearLayout android:id="@+id/LinearLayout01"  
  7.         android:layout_width="wrap_content" android:layout_height="wrap_content">  
  8.         <Button android:id="@+id/Button01" android:layout_width="wrap_content"  
  9.             android:layout_height="wrap_content" android:text="单个独立线程"></Button>  
  10.         <Button android:id="@+id/Button02" android:layout_width="wrap_content"  
  11.             android:layout_height="wrap_content" android:text="两个独立线程"></Button>  
  12.     </LinearLayout>  
  13.     <SurfaceView android:id="@+id/SurfaceView01"  
  14.         android:layout_width="fill_parent" android:layout_height="fill_parent"></SurfaceView>  
  15. </LinearLayout>  

本文程序的源码:

 

  1. package com.testSurfaceView;  
  2.   
  3. import java.lang.reflect.Field;  
  4. import java.util.ArrayList;  
  5. import android.app.Activity;  
  6. import android.graphics.Bitmap;  
  7. import android.graphics.BitmapFactory;  
  8. import android.graphics.Canvas;  
  9. import android.graphics.Paint;  
  10. import android.graphics.Rect;  
  11. import android.os.Bundle;  
  12. import android.util.Log;  
  13. import android.view.SurfaceHolder;  
  14. import android.view.SurfaceView;  
  15. import android.view.View;  
  16. import android.widget.Button;  
  17.   
  18. public class testSurfaceView extends Activity {  
  19.     /** Called when the activity is first created. */  
  20.     Button btnSingleThread, btnDoubleThread;  
  21.     SurfaceView sfv;  
  22.     SurfaceHolder sfh;  
  23.     ArrayList<Integer> imgList = new ArrayList<Integer>();  
  24.     int imgWidth, imgHeight;  
  25.     Bitmap bitmap;//独立线程读取,独立线程绘图  
  26.   
  27.     @Override  
  28.     public void onCreate(Bundle savedInstanceState) {  
  29.         super.onCreate(savedInstanceState);  
  30.         setContentView(R.layout.main);  
  31.   
  32.         btnSingleThread = (Button) this.findViewById(R.id.Button01);  
  33.         btnDoubleThread = (Button) this.findViewById(R.id.Button02);  
  34.         btnSingleThread.setOnClickListener(new ClickEvent());  
  35.         btnDoubleThread.setOnClickListener(new ClickEvent());  
  36.         sfv = (SurfaceView) this.findViewById(R.id.SurfaceView01);  
  37.         sfh = sfv.getHolder();  
  38.         sfh.addCallback(new MyCallBack());// 自动运行surfaceCreated以及surfaceChanged  
  39.     }  
  40.   
  41.     class ClickEvent implements View.OnClickListener {  
  42.   
  43.         @Override  
  44.         public void onClick(View v) {  
  45.   
  46.             if (v == btnSingleThread) {  
  47.                 new Load_DrawImage(0, 0).start();//开一条线程读取并绘图  
  48.             } else if (v == btnDoubleThread) {  
  49.                 new LoadImage().start();//开一条线程读取  
  50.                 new DrawImage(imgWidth + 10, 0).start();//开一条线程绘图  
  51.             }  
  52.   
  53.         }  
  54.   
  55.     }  
  56.   
  57.     class MyCallBack implements SurfaceHolder.Callback {  
  58.   
  59.         @Override  
  60.         public void surfaceChanged(SurfaceHolder holder, int format, int width,  
  61.                 int height) {  
  62.             Log.i("Surface:", "Change");  
  63.   
  64.         }  
  65.   
  66.         @Override  
  67.         public void surfaceCreated(SurfaceHolder holder) {  
  68.             Log.i("Surface:", "Create");  
  69.   
  70.             // 用反射机制来获取资源中的图片ID和尺寸  
  71.             Field[] fields = R.drawable.class.getDeclaredFields();  
  72.             for (Field field : fields) {  
  73.                 if (!"icon".equals(field.getName()))// 除了icon之外的图片  
  74.                 {  
  75.                     int index = 0;  
  76.                     try {  
  77.                         index = field.getInt(R.drawable.class);  
  78.                     } catch (IllegalArgumentException e) {  
  79.                         // TODO Auto-generated catch block  
  80.                         e.printStackTrace();  
  81.                     } catch (IllegalAccessException e) {  
  82.                         // TODO Auto-generated catch block  
  83.                         e.printStackTrace();  
  84.                     }  
  85.                     // 保存图片ID  
  86.                     imgList.add(index);  
  87.                 }  
  88.             }  
  89.             // 取得图像大小  
  90.             Bitmap bmImg = BitmapFactory.decodeResource(getResources(),  
  91.                     imgList.get(0));  
  92.             imgWidth = bmImg.getWidth();  
  93.             imgHeight = bmImg.getHeight();  
  94.         }  
  95.   
  96.         @Override  
  97.         public void surfaceDestroyed(SurfaceHolder holder) {  
  98.             Log.i("Surface:", "Destroy");  
  99.   
  100.         }  
  101.   
  102.     }  
  103.   
  104.     /* 
  105.      * 读取并显示图片的线程 
  106.      */  
  107.     class Load_DrawImage extends Thread {  
  108.         int x, y;  
  109.         int imgIndex = 0;  
  110.   
  111.         public Load_DrawImage(int x, int y) {  
  112.             this.x = x;  
  113.             this.y = y;  
  114.         }  
  115.   
  116.         public void run() {  
  117.             while (true) {  
  118.                 Canvas c = sfh.lockCanvas(new Rect(this.x, this.y, this.x  
  119.                         + imgWidth, this.y + imgHeight));  
  120.                 Bitmap bmImg = BitmapFactory.decodeResource(getResources(),  
  121.                         imgList.get(imgIndex));  
  122.                 c.drawBitmap(bmImg, this.x, this.y, new Paint());  
  123.                 imgIndex++;  
  124.                 if (imgIndex == imgList.size())  
  125.                     imgIndex = 0;  
  126.   
  127.                 sfh.unlockCanvasAndPost(c);// 更新屏幕显示内容  
  128.             }  
  129.         }  
  130.     };  
  131.   
  132.     /* 
  133.      * 只负责绘图的线程 
  134.      */  
  135.     class DrawImage extends Thread {  
  136.         int x, y;  
  137.   
  138.         public DrawImage(int x, int y) {  
  139.             this.x = x;  
  140.             this.y = y;  
  141.         }  
  142.   
  143.         public void run() {  
  144.             while (true) {  
  145.                 if (bitmap != null) {//如果图像有效  
  146.                     Canvas c = sfh.lockCanvas(new Rect(this.x, this.y, this.x  
  147.                             + imgWidth, this.y + imgHeight));  
  148.   
  149.                     c.drawBitmap(bitmap, this.x, this.y, new Paint());  
  150.   
  151.                     sfh.unlockCanvasAndPost(c);// 更新屏幕显示内容  
  152.                 }  
  153.             }  
  154.         }  
  155.     };  
  156.   
  157.     /* 
  158.      * 只负责读取图片的线程 
  159.      */  
  160.     class LoadImage extends Thread {  
  161.         int imgIndex = 0;  
  162.   
  163.         public void run() {  
  164.             while (true) {  
  165.                 bitmap = BitmapFactory.decodeResource(getResources(),  
  166.                         imgList.get(imgIndex));  
  167.                 imgIndex++;  
  168.                 if (imgIndex == imgList.size())//如果到尽头则重新读取  
  169.                     imgIndex = 0;  
  170.             }  
  171.         }  
  172.     };  
  173. }  


posted @ 2011-07-21 10:11 oathleo 阅读(455) | 评论 (0)编辑 收藏

Android提高第五篇之Service

分类: Android提高 2010-11-08 11:48 5360人阅读 评论(11) 收藏 举报

本文来自http://blog.csdn.net/hellogv/ ,引用必须注明出处!

        上次介绍了Activity以及Intent的使用, 这次就介绍Service,如果把Activity比喻为前台程序,那么Service就是后台程序,Service的整个生命周期都只会在后台执行。 Service跟Activity一样也由Intent调用。在工程里想要添加一个Service,先新建继承Service的类,然后到 AndroidManifest.xml -> Application ->Application Nodes中的Service标签中添加。

         Service要由Activity通过startService 或者 bindService来启动,Intent负责传递参数。先贴出本文程序运行截图:

 

本文主要讲解Service的调用,以及其生命周期。

上图是startService之后再stopService的Service状态变化。

上图是bindService之后再unbindService的Service状态变化。

       startService与bindService都可以启动Service,那么它们之间有什么区别呢?它们两者的区别就是使Service的周期改变。由 startService启动的Service必须要有stopService来结束Service,不调用stopService则会造成 Activity结束了而Service还运行着。bindService启动的Service可以由unbindService来结束,也可以在 Activity结束之后(onDestroy)自动结束。

 上图是startService之后再Activity.finish()的Service状态变化,Service还在跑着。

上图是bindService之后再Activity.finish()的Service状态变化,Service最后自动unbindService。

main.xml代码:

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical" android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent">  
  5.     <Button android:layout_width="wrap_content"  
  6.         android:layout_height="wrap_content" android:id="@+id/btnStartMyService"  
  7.         android:text="StartMyService"></Button>  
  8.     <Button android:layout_width="wrap_content"  
  9.         android:layout_height="wrap_content" android:id="@+id/btnStopMyService"  
  10.         android:text="StopMyService"></Button>  
  11.     <Button android:layout_width="wrap_content"  
  12.         android:layout_height="wrap_content" android:id="@+id/btnBindMyService"  
  13.         android:text="BindMyService"></Button>  
  14.     <Button android:layout_width="wrap_content"  
  15.         android:layout_height="wrap_content" android:id="@+id/btnUnbindMyService"  
  16.         android:text="UnbindMyService"></Button>  
  17.     <Button android:layout_width="wrap_content"  
  18.         android:layout_height="wrap_content" android:id="@+id/btnExit"  
  19.         android:text="退出程序"></Button>  
  20. </LinearLayout>  

testService.java的源码:

  1. package com.testService;  
  2.   
  3. import android.app.Activity;  
  4. import android.app.Service;  
  5. import android.content.ComponentName;  
  6. import android.content.Intent;  
  7. import android.content.ServiceConnection;  
  8. import android.os.Bundle;  
  9. import android.os.IBinder;  
  10. import android.util.Log;  
  11. import android.view.View;  
  12. import android.widget.Button;  
  13.   
  14. public class testService extends Activity {  
  15.     Button btnStartMyService,btnStopMyService,btnBindMyService,btnUnbindMyService,btnExit;  
  16.     @Override  
  17.     public void onCreate(Bundle savedInstanceState) {  
  18.         super.onCreate(savedInstanceState);  
  19.         setContentView(R.layout.main);  
  20.         btnStartMyService=(Button)this.findViewById(R.id.btnStartMyService);  
  21.         btnStartMyService.setOnClickListener(new ClickEvent());  
  22.           
  23.         btnStopMyService=(Button)this.findViewById(R.id.btnStopMyService);  
  24.         btnStopMyService.setOnClickListener(new ClickEvent());  
  25.           
  26.         btnBindMyService=(Button)this.findViewById(R.id.btnBindMyService);  
  27.         btnBindMyService.setOnClickListener(new ClickEvent());  
  28.           
  29.         btnUnbindMyService=(Button)this.findViewById(R.id.btnUnbindMyService);  
  30.         btnUnbindMyService.setOnClickListener(new ClickEvent());   
  31.           
  32.         btnExit=(Button)this.findViewById(R.id.btnExit);  
  33.         btnExit.setOnClickListener(new ClickEvent());  
  34.     }  
  35.     @Override  
  36.     public void onDestroy()  
  37.     {  
  38.         super.onDestroy();  
  39.         Log.e("Activity","onDestroy");  
  40.     }  
  41.       
  42.     private ServiceConnection _connection = new ServiceConnection() {    
  43.         @Override  
  44.         public void onServiceConnected(ComponentName arg0, IBinder arg1) {  
  45.             // TODO Auto-generated method stub  
  46.         }  
  47.   
  48.         @Override  
  49.         public void onServiceDisconnected(ComponentName name) {  
  50.             // TODO Auto-generated method stub  
  51.         }    
  52.     };    
  53.     class ClickEvent implements View.OnClickListener{  
  54.   
  55.         @Override  
  56.         public void onClick(View v) {  
  57.             Intent intent=new Intent(testService.this,MyService.class);  
  58.             if(v==btnStartMyService){  
  59.                 testService.this.startService(intent);  
  60.             }  
  61.             else if(v==btnStopMyService){  
  62.                 testService.this.stopService(intent);  
  63.             }  
  64.             else if(v==btnBindMyService){  
  65.                 testService.this.bindService(intent, _connection, Service.BIND_AUTO_CREATE);  
  66.             }  
  67.             else if(v==btnUnbindMyService){  
  68.                 if(MyService.ServiceState=="onBind")//Service绑定了之后才能解绑  
  69.                     testService.this.unbindService(_connection);  
  70.             }  
  71.             else if(v==btnExit)  
  72.             {  
  73.                 testService.this.finish();  
  74.             }  
  75.               
  76.         }  
  77.           
  78.     }  
  79. }  

MyService.java的源码:

  1. package com.testService;  
  2.   
  3. import android.app.Service;  
  4. import android.content.Intent;  
  5. import android.os.IBinder;  
  6. import android.util.Log;  
  7.   
  8. public class MyService extends Service {  
  9.     static public String ServiceState="";  
  10.     @Override  
  11.     public IBinder onBind(Intent arg0) {  
  12.         Log.e("Service", "onBind");  
  13.         ServiceState="onBind";  
  14.         return null;  
  15.     }  
  16.     @Override  
  17.     public boolean onUnbind(Intent intent){  
  18.         super.onUnbind(intent);  
  19.         Log.e("Service", "onUnbind");  
  20.         ServiceState="onUnbind";  
  21.         return false;  
  22.           
  23.     }  
  24.     @Override  
  25.     public void onCreate(){  
  26.         super.onCreate();  
  27.         Log.e("Service", "onCreate");  
  28.         ServiceState="onCreate";  
  29.     }  
  30.     @Override  
  31.     public void onDestroy(){  
  32.         super.onDestroy();  
  33.         Log.e("Service", "onDestroy");  
  34.         ServiceState="onDestroy";  
  35.     }  
  36.     @Override  
  37.     public void onStart(Intent intent,int startid){  
  38.         super.onStart(intent, startid);  
  39.         Log.e("Service", "onStart");  
  40.         ServiceState="onStart";  
  41.     }  
  42.   
  43. }  


posted @ 2011-07-21 10:10 oathleo 阅读(200) | 评论 (0)编辑 收藏

Android入门第十六篇之Style与Theme

分类: Android入门 2011-01-11 11:16 10361人阅读 评论(28) 收藏 举报

 本文来自http://blog.csdn.net/hellogv/ ,引用必须注明出处!

       越来越多互联网企业都在Android平台上部署其客户端,为了提升用户体验,这些客户端都做得布局合理而且美观.......Android的Style设计就是提升用户体验的关键之一。Android上的Style分为了两个方面:

  1. Theme是针对窗体级别的,改变窗体样式;
  2. Style是针对窗体元素级别的,改变指定控件或者Layout的样式。

Android 系统的themes.xml和style.xml(位于/base/core/res/res/values/)包含了很多系统定义好的style,建议 在里面挑个合适的,然后再继承修改。以下属性是在Themes中比较常见的,源自Android系统本身的themes.xml:

  1. <!-- Window attributes -->  
  2. <item name="windowBackground">@android:drawable/screen_background_dark</item>  
  3. <item name="windowFrame">@null</item>  
  4. <item name="windowNoTitle">false</item>  
  5. <item name="windowFullscreen">false</item>  
  6. <item name="windowIsFloating">false</item>  
  7. <item name="windowContentOverlay">@android:drawable/title_bar_shadow</item>  
  8. <item name="windowTitleStyle">@android:style/WindowTitle</item>  
  9. <item name="windowTitleSize">25dip</item>  
  10. <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground</item>  
  11. <item name="android:windowAnimationStyle">@android:style/Animation.Activity</item>  

至于控件的Style设计就范围大多了,看看Eclipse的Android控件属性编辑器[Properties]就大概知道有哪些条目, 而Android内置的style.xml也只是定义每个控件的默认样式而已....不过控件的style不建议大改,耐看的style更能让用户长时间 使用软件。另外,控件的Style在很多情况下都用到9.png,学习9.png就必须到/base/core/res/res/drawable- hdpi里面看看,里面有很多系统内置的9.png。

PS:为了研究Android的Style和Theme,强烈建议下载Android的base.git!

接下来看看本文程序的效果图:

本文程序的themes.xml代码如下,自定义了WindowTitle,:

 

<?xml version="1.0" encoding="UTF-8"?>
<resources>
 <!--继承Android内置的Theme.Light,位于/base/core/res/res/values/themes.xml -->
 <style name="Theme" parent="android:Theme.Light">
  <item name="android:windowFullscreen">true</item>
  <item name="android:windowTitleSize">60dip</item>
  <item name="android:windowTitleStyle">@style/WindowTitle</item>
 </style>

 <style name="WindowTitle" parent="android:WindowTitle">
  <item name="android:singleLine">true</item>
  <item name="android:shadowColor">#BB000000</item>
  <item name="android:shadowRadius">2.75</item>
 </style>
</resources>

 

 

要为Activity使用theme,要么使用代码 setTheme(R.style.Theme),要么在Application Manifest里面设置

本文程序的styles.xml代码如下,background默认使用的是9.png,xml定义在/base/core/res/res/drawable/之下:

 

 

<?xml version="1.0" encoding="UTF-8"?>
<resources>
 <style name="TextView">
  <item name="android:textSize">18sp</item>
  <item name="android:textColor">#008</item>
  <item name="android:shadowColor">@android:color/black</item>
  <item name="android:shadowRadius">2.0</item>
 </style>

 <style name="EditText">
  <item name="android:shadowColor">@android:color/black</item>
  <item name="android:shadowRadius">1.0</item>
  <item name="android:background">@android:drawable/btn_default</item>
  <item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
 </style>

    <style name="Button">
        <item name="android:background">@android:drawable/edit_text</item>
        <item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
    </style>
</resources>

 

main.xml代码如下:

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical" android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent">  
  5.     <TextView android:layout_width="fill_parent"  
  6.         android:layout_height="wrap_content" android:text="@string/hello"  
  7.         style="@style/TextView" />  
  8.     <EditText android:id="@+id/EditText01" android:layout_height="wrap_content"  
  9.         style="@style/EditText" android:layout_width="fill_parent"  
  10.         android:text="类似Button的EditText"></EditText>  
  11.     <EditText android:id="@+id/EditText02" android:layout_height="wrap_content"  
  12.         android:layout_width="fill_parent" android:text="普通的EditText"></EditText>  
  13.     <Button android:id="@+id/Button01" android:layout_height="wrap_content"  
  14.         style="@style/Button" android:layout_width="fill_parent" android:text="类似EditText的Button"></Button>  
  15. </LinearLayout>  


posted @ 2011-07-21 10:04 oathleo 阅读(295) | 评论 (0)编辑 收藏

android中使用2D动画 — SurfaceView

 

通过之前介绍的如何自定义View, 我们知道使用它可以做一些简单的动画效果。它通过不断循环的执行View.onDraw方法,每次执行都对内部显示的图形做一些调整,我们假设 onDraw方法每秒执行20次,这样就会形成一个20帧的补间动画效果。但是现实情况是你无法简单的控制View.onDraw的执行帧数,这边说的执 行帧数是指每秒View.onDraw方法被执行多少次,这是为什么呢?首先我们知道,onDraw方法是由系统帮我们调用的,我们是通过调用View的 invalidate方法通知系统需要重新绘制View,然后它就会调用View.onDraw方法。这些都是由系统帮我们实现的,所以我们很难精确去定 义View.onDraw的执行帧数,这个就是为什么我们这边要了解SurfaceView了,它能弥补View的一些不足。

首先我们先写一个自定义View实现动画效果,AnimateViewActivity.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
42
43
44
45
46
47
48
package com.android777.demo.uicontroller.graphics;
 
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.View;
 
public class AnimateViewActivity extends Activity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        setContentView(new AnimateView(this));
    }
 
    class AnimateView extends View{
 
        float radius = 10;
        Paint paint;
 
        public AnimateView(Context context) {
            super(context);
            paint = new Paint();
            paint.setColor(Color.YELLOW);
            paint.setStyle(Paint.Style.STROKE);
        }
 
        @Override
        protected void onDraw(Canvas canvas) {
 
            canvas.translate(200, 200);
            canvas.drawCircle(0, 0, radius++, paint);          
 
            if(radius > 100){
                radius = 10;
            }
 
            invalidate();//通过调用这个方法让系统自动刷新视图
 
        }
 
    }
 
}

运行上面的Activity,你将看到一个圆圈,它原始半径是10,然后不断的变大,直到达到100后又恢复到10,这样循环显示,视觉效果上说你将看到一个逐渐变大的圆圈。

上面就是一个简单的自定义View实现的动画效果,它能做的只是简单的动画效果,具有一些局限性。首先你无法控制动画的显示速度,目前它是以最快的 速度显示,但是当你要更快,获取帧数更高的动画呢? 因为View的帧数是由系统控制的,所以你没办法完成上面的操作。如果你需要编写一个游戏,它需要的帧数比较高,那么View就无能为力了,因为它被设计 出来时本来就不是用来处理一些高帧数显示的。你可以把View理解为一个经过系统优化的,可以用来高效的执行一些帧数比较低动画的对象,它具有特定的使用 场景,比如有一些帧数较低的游戏就可以使用它来完成:贪吃蛇、俄罗斯方块、棋牌类等游戏,因为这些游戏执行的帧数都很低。但是如果是一些实时类的游戏,如 射击游戏、塔防游戏、RPG游戏等就没办法使用View来做,因为它的帧数太低了,会导致动画执行不顺畅。所以我们需要一个能自己控制执行帧数的对 象,SurfaceView因此诞生了。

什么是SurfaceView呢?

为什么是SurfaceView呢?Surface的意思是表层,表面的意思,那么SurfaceView就是指一个在表层的View对象。为什么 说是在表层呢,这是因为它有点特殊跟其他View不一样,其他View是绘制在表层外,而它就是充当表层对象。假设你要在一个球上画画,那么球的表层就当 做你的画布对象,你画的东西会挡住它的表层,我们默认没使用SurfaceView,那么球的表层就是空白的,如果我们使用了SurfaceView,我 们可以理解为我们拿来的球本身表面就具有纹路,你是画再纹路之上的,如果你画的是半透明的,那么你将可以透过你画的东西看到球面本身的纹路。SDK的文档 说到:SurfaceView就是在Window上挖一个洞,它就是显示在这个洞里,其他的View是显示在Window上,所以View可以显式在 SurfaceView之上,你也可以添加一些层在SurfaceView之上。

SurfaceView还有其他的特性,上面我们讲了它可以控制帧数,那它是什么控制的呢?这就需要了解它的使用机制。一般在很多游戏设计中,我们都是开辟一个后台线程计算游戏相关的数据,然后根据这些计算完的新数据再刷新视图对象,由于对View执行绘制操作只能在UI线程上, 所以当你在另外一个线程计算完数据后,你需要调用View.invalidate方法通知系统刷新View对象,所以游戏相关的数据也需要让UI线程能访 问到,这样的设计架构比较复杂,要是能让后台计算的线程能直接访问数据,然后更新View对象那改多好。我们知道View的更新只能在UI线程中,所以使 用自定义View没办法这么做,但是SurfaceView就可以了。它一个很好用的地方就是允许其他线程(不是UI线程)绘制图形(使用Canvas),根据它这个特性,你就可以控制它的帧数,你如果让这个线程1秒执行50次绘制,那么最后显示的就是50帧。

 

如何使用SurfaceView?

首先SurfaceView也是一个View,它也有自己的生命周期。因为它需要另外一个线程来执行绘制操作,所以我们可以在它生命周期的初始化阶 段开辟一个新线程,然后开始执行绘制,当生命周期的结束阶段我们插入结束绘制线程的操作。这些是由其内部一个SurfaceHolder对象完成的。 SurfaceHolder,顾名思义,它里面保存了一个队Surface对象的引用,而我们执行绘制方法就是操作这个 Surface,SurfaceHolder因为保存了对Surface的引用,所以使用它来处理Surface的生命周期,说到底 SurfaceView的生命周期其实就是Surface的生命周期,因为SurfaceHolder保存对Surface的引用,所以使用 SurfaceHolder来处理生命周期的初始化。首先我们先看看建立一个SurfaceView的大概步骤,先看看代码:

DemoSurfaceView.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
package com.android777.demo.uicontroller.graphics;
 
import android.content.Context;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
 
public class DemoSurfaceView extends SurfaceView  implements Callback{
 
    public DemoSurfaceView(Context context) {
        super(context);
 
        init(); //初始化,设置生命周期回调方法
 
    }
 
    private void init(){
 
        SurfaceHolder holder = getHolder();
        holder.addCallback(this); //设置Surface生命周期回调
 
    }
 
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
    }
 
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    }
 
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    }
 
}

上面代码我们在SurfaceView的构造方法中执行了init初始化方法,在这个方法里,我们先获取SurfaceView里的 SurfaceHolder对象,然后通过它设置Surface的生命周期回调方法,使用DemoSurfaceView类本身作为回调方法代理类。 surfaceCreated方法,是当SurfaceView被显示时会调用的方法,所以你需要再这边开启绘制的线 程,surfaceDestroyed方法是当SurfaceView被隐藏会销毁时调用的方法,在这里你可以关闭绘制的线程。上面的例子运行后什么也不 显示,因为还没定义一个执行绘制的线程。下面我们修改下代码,使用一个线程绘制一个逐渐变大的圆圈:

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package com.android777.demo.uicontroller.graphics;
 
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
 
public class DemoSurfaceView extends SurfaceView  implements Callback{
 
    LoopThread thread;
 
    public DemoSurfaceView(Context context) {
        super(context);
 
        init(); //初始化,设置生命周期回调方法
 
    }
 
    private void init(){
 
        SurfaceHolder holder = getHolder();
        holder.addCallback(this); //设置Surface生命周期回调
        thread = new LoopThread(holder, getContext());
    }
 
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
    }
 
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        thread.isRunning = true;
        thread.start();
    }
 
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        thread.isRunning = false;
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 执行绘制的绘制线程
     * @author Administrator
     *
     */
    class LoopThread extends Thread{
 
        SurfaceHolder surfaceHolder;
        Context context;
        boolean isRunning;
        float radius = 10f;
        Paint paint;
 
        public LoopThread(SurfaceHolder surfaceHolder,Context context){
 
            this.surfaceHolder = surfaceHolder;
            this.context = context;
            isRunning = false;
 
            paint = new Paint();
            paint.setColor(Color.YELLOW);
            paint.setStyle(Paint.Style.STROKE);
        }
 
        @Override
        public void run() {
 
            Canvas c = null;
 
            while(isRunning){
 
                try{
                    synchronized (surfaceHolder) {
 
                        c = surfaceHolder.lockCanvas(null);
                        doDraw(c);
                        //通过它来控制帧数执行一次绘制后休息50ms
                        Thread.sleep(50);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    surfaceHolder.unlockCanvasAndPost(c);
                }
 
            }
 
        }
 
        public void doDraw(Canvas c){
 
            //这个很重要,清屏操作,清楚掉上次绘制的残留图像
            c.drawColor(Color.BLACK);
 
            c.translate(200, 200);
            c.drawCircle(0,0, radius++, paint);
 
            if(radius > 100){
                radius = 10f;
            }
 
        }
 
    }
 
}

上面代码编写了一个使用SurfaceView制作的动画效果,它的效果跟上面自定义View的一样,但是这边的SurfaceView可以控制动 画的帧数。在SurfaceView中内置一个LoopThread线程,这个线程的作用就是用来绘制图形,在SurfaceView中实例化一个 LoopThread实例,一般这个操作会放在SurfaceView的构造方法中。然后通过在SurfaceView中的SurfaceHolder的 生命周期回调方法中插入一些操作,当Surface被创建时(SurfaceView显示在屏幕中时),开启LoopThread执行绘 制,LoopThread会一直刷新SurfaceView对象,当SurfaceView被隐藏时就停止改线程释放资源。这边有几个地方要注意下:

1.因为SurfaceView允许自定义的线程操作Surface对象执行绘制方法,而你可能同时定义多个线程执行绘制,所以当你获取 SurfaceHolder中的Canvas对象时记得加同步操作,避免两个不同的线程同时操作同一个Canvas对象,当操作完成后记得调用 SurfaceHolder.unlockCanvasAndPost方法释放掉Canvas锁。

2.在调用doDraw执行绘制时,因为SurfaceView的特点,它会保留之前绘制的图形,所以你需要先清空掉上一次绘制时留下的图形。(View则不会,它默认在调用View.onDraw方法时就自动清空掉视图里的东西)。

3. 记得在回调方法:onSurfaceDestroyed方法里将后台执行绘制的LoopThread关闭,这里是使用join方法。这涉及到线程如何关闭 的问题,多数人建议是通过一个标志位:isRunning来判断线程是否该停止运行,如果你想关闭线程只需要将isRunning改成false即可,线 程会自动执行完run方法后退出。

 

总结:

通过上面的分析,现在大家应该会简单使用SurfaceView了,总的归纳起来SurfaceView和View不同之处有:

1. SurfaceView允许其他线程更新视图对象(执行绘制方法)而View不允许这么做,它只允许UI线程更新视图对象。

2. SurfaceView是放在其他最底层的视图层次中,所有其他视图层都在它上面,所以在它之上可以添加一些层,而且它不能是透明的。

3. 它执行动画的效率比View高,而且你可以控制帧数。

4. 因为它的定义和使用比View复杂,占用的资源也比较多,除非使用View不能完成,再用SurfaceView否则最好用View就可以。(贪吃蛇,俄罗斯方块,棋牌类这种帧数比较低的可以使用View做就好)

posted @ 2011-07-21 09:45 oathleo 阅读(2927) | 评论 (0)编辑 收藏

Android surfaceView 与View 的区别  

如果你的游戏不吃CPU,用View就比较好,符合标准Android操作方式,由系统决定刷新surface的时机。

  但如果很不幸的,你做不到不让你的程序吃CPU,你就只好使用SurfaceView来强制刷新surface了,不然系统的UI进程很可能抢不过你那些吃CPU的线程。

  当然其实不止这两种方法来刷新Surface的,这两种只是纯Java应用比较常见的方法。

  SurfaceView和View最本质的区别在于,surfaceView是在一个新起的单独线程中可以重新绘制画面而View必须在UI的主线程中更新画面。

  那么在UI的主线程中更新画面 可能会引发问题,比如你更新画面的时间过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应按键,触屏等消息。

   当使用surfaceView 由于是在新的线程中更新画面所以不会阻塞你的UI主线程。但这也带来了另外一个问题,就是事件同步。比如你触屏了一下,你需要surfaceView中 thread处理,一般就需要有一个event queue的设计来保存touch event,这会稍稍复杂一点,因为涉及到线程同步。

  所以基于以上,根据游戏特点,一般分成两类。

  1 被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 因为这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。

  2 主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main UI thread。所以显然view不合适,需要surfaceView来控制。

posted @ 2011-07-21 09:36 oathleo 阅读(293) | 评论 (0)编辑 收藏

Android 1.5 API变更概要:
UI framework
· Framework for easier background/UI thread interaction
· 新SlidingDrawer 组件
· 新HorizontalScrollview 组件
AppWidget framework
· 一些关于创建桌面AppWidget 的API.
· 提供根据自定义的内容创建LiveFolders的API
Media framework
· 原声录音和回放 APIs
· 交互式的MIDI 回放引擎
· 开发者使用的视频录像API (3GP format).
· 视频相片分享 Intents
· 媒体搜索Intent
Input Method framework
· 输入法服务framework
· 文本预测引擎
· 提供具有下载能力的IME给使用者
Android软键盘的隐藏显示研究:
http://winuxxan.blog.51cto.com/2779763/522810
android软键盘出来的时候覆盖底部的tab导航:
http://www.eoeandroid.com/thread-67098-1-1.html
android 软键盘Enter键图标的设置:
http://archive.cnblogs.com/a/1994418/
Application-defined hardware requirements
应用可定义硬件需求,应用程序可以定义  说明此程序需要什么硬件需求.比如是否需要物理键盘或者轨迹球.
Speech recognition framework
· 支持语音识别库.
Miscellaneous API additions
· LocationManager -应用可以接收到位置改变的信息.
· WebView - 触摸start/end/move/cancel   DOM 事件的支持
· 重建Sensor Manager APIs
· GLSurfaceView - 创建OpenGL 应用更加方便的framework .
· 软件升级安装成功的Broadcast Intent - 更加平和优秀的软件升级体验

Android 1.6 API变更概要:
UI framework
· 新的类 android.view.animation 控制动画行为:
o AnticipateInterpolator
o AnticipateOvershootInterpolator
o BounceInterpolator
o OvershootInterpolator
· 新的XML 属性android:onClick ,从一个layout文件描述一个view的 View.OnClickListener.
· 对不同分辨率的屏幕的新的支持. 对于Bitmap和Canvas会执行有针对性的缩放行为.该框架会根据屏幕分辨率和其他内容自动缩放bitmap等.
要在你的应用中使用Android 1.6包含的API的话你必须要设置 &quot;4&quot;属性在manifest的 元素中
Search framework
· 应用程序现在可以公开的有关内容,作为建议放入快速搜索框,新的设备范围内的搜索功能,是可从主屏幕搜索。为了支持这一点,搜索框架增加了新的属性,可搜索的元数据文件。有关完整的信息,请参阅SearchManager
文档。
Accessibility framework
· New android.accessibility package that includes classes for capturing accessibility events and forwarding them to an AccessibilityService handler.
· New AccessibilityService package that lets your application track user events and provide visual, audible, or haptic feedback to the user.
Gesture Input
· 新的gesture API :创建,识别,读取,保存手势.
Text-to-speech
· 新的android.speech.tts 包提供了TTS文本朗读功能,从一个文本生成一个声音文件的回放.
http://blog.csdn.net/CBirdLG/archive/2010/10/10/5931728.aspx
Graphics
· android.graphics 中的类,现在支持为不同的屏幕尺寸进行缩放.
Telephony
· 新的SmsManager 发送和接受短信.
Utilities
· 新的DisplayMetrics 字段决定当前设备屏幕的密度.
Android Manifest elements
o 新的 元素
o 新的 标签
o glEsVersion: 指定最小openGL ES的版本
·
元素的新的属性:
o 目标SDK版本: 应用程序能够指定目标版本. 它能够运行在旧版本(低至minSdkVersion), 他是按照应用程序的指定版本开发的. Specifying this version allows the platform to disable compatibility code that is not required or enable newer features that are not available to older applications.
o maxSdkVersion: 指定设计这个程序运行的最高版本 重要: 当使用  这些属性前请认真阅读文档.
New Permissions
· CHANGE_WIFI_MULTICAST_STATE: 允许应用进入Wi-Fi 多点传送模式.
· GLOBAL_SEARCH: 允许全局搜索系统,以便精确确定 content provider.
· INSTALL_LOCATION_PROVIDER: 允许应用在Location Manager.安装一个location provider.
· READ_HISTORY_BOOKMARKS: 允许应用读取(并不能写) 用户的浏览记录和书签
· WRITE_HISTORY_BOOKMARKS: 允许应用写入 (并不能读) 用户的浏览记录和书签
· WRITE_EXTERNAL_STORAGE: 允许程序写入外部存储器.应用程序使用API级别3下将默认授予此权限 (这对用户可见的); 应用程序使用API level4 或者更高的,必须要明确的宣告此权限.

Android 2.0 API变更概要:
Bluetooth
· 开启关闭蓝牙
· 设备和服务发现
· 使用 RFCOMM连接一个可插拔的设备收发数据
· 公布RFCOMM 服务和监听接收 RFCOMM 连接
Sync adapters
· 新的APIs, 同步桥接器连接任何backend
Account Manager
· 集中的帐户管理器 API ,安全的储存和使用可信的tokens/passwords
Contacts
· 新的通信APIs 允许获取多个账户的数据.
· 新的快速通信framework APIs 允许开发者在他们的应用中创建通信标记, 一键点击标记打开一个新的窗口展示一个如何联系当前人的列表.
WebView
· 不赞成使用的类: UrlInterceptHandler, Plugin, PluginData, PluginList, UrlInterceptRegistry.
Camera
· 颜色模式, 场景模式 闪光模式, 焦点模式, 白平衡 旋转和其他设置的新的特征.
· 当缩放级别改变的时候,会回调新的缩放回调接口.
Media
· MediaScanner现在为所有图片生成缩微图when they are inserted into MediaStore.
· 新的缩微图 API : 检索需要的图片和视频的缩微图.
Other Framework
· android.R.style 中新的系统主题,能够更加简单的显示当前acitivities的系统壁纸或者保持之前的activity在后台.新的壁纸管理器API 取代并且增加了wallpaper APIs ,我们可以允许我们的应用要求设置系统壁纸.
· 新的Service APIs帮助应用准确的处理Service 生命周期 ,在指定的低内存状态下service将会被关闭.
o Service.setForeground() 不推荐使用,并且现在这个方法并没有实际执行. .他被一个新的API所取代, startForeground(), that helps (and requires) associating an ongoing notification with the foreground state.
· MotionEvent 如果设备允许的话,MotionEvent 会返回多点触摸信息.最多可同时获取3点
· KeyEvent 现在有了新的按键发送 APIs,去帮助实现 action-on-up 和长按键行为, 一个新的机制取消按键 (虚拟按键).
· WindowManager.LayoutParams 现在有了新的常量允许窗口能够在被锁或者其他的状况中唤醒屏幕,这个允许程序能够让例如闹钟等的应用实现唤醒设备.
· New Intent APIs 广播设备的对接状态,当这个设备放在桌面或者停车场,允许程序启动特殊的activity.
Key events executed on key-up
Android 2.0能够使用虚拟按键HOME, MENU, BACK和SEARCH,而非物理按键,为了让用户在他们的设备中获得最好的用户体验,android平台现在把这些按键执行加入到了key-up,做了 key-down/key-up 配对,而非只有key-down.,这有助于防止意外按钮事件,并让使用者按下按钮区域,然后拖动而不生成一个事件出来。
这种改变只会影响你的应用程序一点,如果它是拦截按钮事件,最好用key-down,而不是key-up.。特例,如果您的应用程序拦截BACK 键,你应该确保你的应用妥善处理按键事件。

Android 2.0.1 API变更概要:
· 新的快速联系人标记风格(quickContactBadgeStyle)* 属性,让应用的QuickContactBadge 组件接收必要的风格.
· 当在manifest里面宣布了filter,取消了支持 ACTION_CONFIGURATION_CHANGED 广播 ,如果想要去接收这个广播, 这个应用必须注册 registerReceiver(BroadcastReceiver, IntentFilter).
性能上的改变:
Bluetooth
改变了 ACTION_REQUEST_ENABLE 和ACTION_REQUEST_DISCOVERABLE的返回值
· ACTION_REQUEST_ENABLE 如果蓝牙是成功开启的,现在返回RESULT_OK .如果使用者拒绝开启蓝牙的请求,则会返回RESULT_CANCELED .
· ACTION_REQUEST_DISCOVERABLE 如果使用者拒绝启动蓝牙或者蓝牙的可发现功能,则返回 RESULT_CANCELED .
通讯
The ACTION_INSERT Intent returns RESULT_CANCELED in cases where the contact was not persisted (例如剪切保存到一个空的操作里面).
修复错误:
资源
现在framework可以正选择应用资源的根据API等级划分的文件夹(drawable-v4是API level4版本用的资源).现在的版本这个功能不能正常工作的问题已经修复.
Contacts
The ACTION_INSERT Intent now returns the appropriate kind of URI when the request is made using the (now deprecated) Contacts APIs.
Other Framework fixes
· getCallingPackage() 现在正确的报告包名, 而不是进程名.

Android 2.1 API变更概要:
Live Wallpapers 动态桌面
以下增加的API可以提供你开发动态的桌面:
· 新android.service.wallpaper 包.
· 新WallpaperInfo 类.
· 升级的WallpaperManager.

附加说明, 如果你的应用相提供Live Wallpapers的功能, 你必须记得增加一个  元素到你的应用manifest里面. 宣布这个属性android:name=&quot;android.software.live_wallpaper&quot;. 举例:
电话

· 新的SignalStrength 类提供当前网络信号的一些信息这些信息可以从onSignalStrengthsChanged(SignalStrength) 回调.
· 新的onDataConnectionStateChanged(int, int) 回调.
Views
· 新的View 方法isOpaque() 和onDrawScrollBars(Canvas).
· 新的RemoteViews 方法addView(int, RemoteViews) 和removeAllViews(int).
· 新的ViewGroup 方法isChildrenDrawingOrderEnabled() 和setChildrenDrawingOrderEnabled(boolean).

WebKit
· 新的WebStorage 方法操作网页数据缓存.
· 新的GeolocationPermissions 方法获取 Geolocation permissions 的出处, 把他们设置到 WebView上.
· 新的WebSettings 方法管理软件缓存, 网页缓存 和屏幕的缩放.
· 新的WebChromeClient 方法处理视频, 历史记录, 自定义view, 软件缓存限制还有其他

Android 2.2 API变更概要:
对Microsoft Exchange更好的支持。Android的几个新特性使之更适于Exchange企业环境。其中一些新特性列举如下:

基于用户名/密码的Exchange帐号自动检测
支持Exchange日历的同步
改进的安全性,管理员可以跨越设备强制应用安全策略
恢复出场设置——管理员可以将设备重置为出场设置,这样就能在设备被偷或丢失后擦除上面的敏感数据了
全局的地址列表查找——可以根据服务器端返回的列表帮助用户自动填充收件人的邮件地址
设备管理API。Android 2.2改进并新增了大量的设备管理API,开发者可以将其用在应用当中:
应用数据备份API——可以将应用数据备份到云中。如果用户切换到另一个Android设备,他就可以从之前的设备中恢复数据。
Cloud-to-Device消息API。云中的用户/系统可以凭借这种增强在设备上触发动作。该特性可以将移动警告发给手机并且支持双向的推同步服务。
可以直接在外部的内存设备(SD卡)上安装应用,还可以将应用从内部迁移到SD卡上,反之亦然。
网络共享。Android 2.2可以通过一台Android电话提供的热点将多个服务连接到Internet上。

性能。借助于新式的Dalvik JIT编译器,对于CPU密集型应用来说,Android 2.2的速度要比Android 2.1快2~5倍。根据Linpack基准测试结果,安装了Froyo的Nexus
One电话可以达到37.5 MFlops,而同样的电话如果使用Android 2.1的话才有6.5 MFlops。

更快的浏览速度。由于浏览器现在使用了Chrome V8引擎,JavaScript代码的处理速度要比Android 2.1快2~3倍。

从浏览器中访问设备API。现在可以直接从浏览器中访问大量的设备API,如加速器、相机、声音识别、翻译等,这样Web应用就能以前所未有的方式与设备交互了。比如说,用户可以在拍完照后将其上传到网上,而这一切都是在浏览器内完成的。

支持Flash 10.1。Froyo支持最新的Flash 10.1
Beta版。最近,JIT编译器的引入极大地改进了性能,这对Flash应用的运行起到了巨大的帮助作用,因为大家都知道,Flash应用是一种CPU密集型应用。

Android商店。Android 2.2开发者和商店用户会从如下新特性中受益无穷:

可以在Android商店搜索应用,包括应用数据

更新——点击一次按钮后会自动更新所有应用

崩溃与冻结报告。Android
2.2集成了崩溃/冻结报告特性,这样在崩溃时用户就可以将完整的细节信息报告给应用发布者了

从PC上浏览商店并将应用直接下载到设备上。用户可以通过PC选择商店的应用,之后应用就可以发到到加载的设备上。要想使用这个特性,用户需要登录并且设备需要在Android商店注册-
音乐管理。用户可以将Windows Media或Mac iTunes上的所有非DRM音乐转换到Android设备上播放。

Android 2.3 API变更概要:
Android 2.3姜饼发布,代号Gingerbread,包含哪些新特性和改进呢?

   1. 新增android.net.sip包,名为SipManager类,可以轻松开发基于Sip的Voip应用。同时使用时必须至少包含这两个权限 <uses-permission android:name="android.permission.INTERNET"> and <uses-permission android:name="android.permission.USE_SIP">,如果需要在Market上过滤仅显示支持VoIP API的机型,可以在发布时androidmanifest.xml中加入 <uses-feature android:name="android.software.sip" android:required="true"> 和 <uses-feature android:name="android.software.sip.voip"> 这两个标志。

  2. Near Field Communications (NFC) 近距离通讯的支持,NFC可以在不接触的情况下实现数据交换通讯,可以很好的代替RFID SIM卡实现手机支付等扩展功能,当然Android123提示这需要硬件的支持
,新增包在 android.nfc包含NfcAdapter,NdefMessage,NdefRecord等类,类似蓝牙的处理方式,使用该API需要声明权 限<uses-permission android:name="android.permission.NFC"> ,同时在Market上过滤支持NFC的设备需要加入<uses-feature android:name="android.hardware.nfc" android:required="true">这句。

  3. 新增陀螺仪和其他的传感器支持
  Android 2.3加入了一些新的感应器,比如gyroscope陀螺仪, rotation vector旋转向量, linear acceleration线性加速器 gravity和barometer气压计的支持。如果过滤这些功能,发布时加入类似<uses-feature android:name="android.hardware.sensor.gyroscope" android:required="true">到androidmanifest.xml中。

  4. 多摄像头支持
新增 Camera.CameraInfo 可以管理摄像头前置或后置
新增 getNumberOfCameras(), getCameraInfo() 和 getNumberOfCameras() 获取摄像头数量。  
新增 get() 方法,可以获取摄像头配置信息 CamcorderProfile
新增 getJpegEncodingQualityParameter() 获取jpeg编码质量参数可以在 CameraPreview.java 文件从ApiDemos示例程序中查看。

5. 新增拍照API
  比如获取焦距getFocusDistances()获取预览FPS getPreviewFpsRange(), 获取焦距范围 getSupportedPreviewFpsRange() 和设置教育 setPreviewFpsRange()

6. 混响音效
本次Android 2.3框架中加入了对混响音效的支持,比如低音,耳机和虚拟化等效果.
新增 android.media.audiofx 包
新增 AudioEffect 类提供音效控制
新增音频会话ID,设置 AudioTrack 和 MediaPlayer.
新 AudioTrack 新增 attachAuxEffect()、getAudioSessionId()和 setAuxEffectSendLevel()。
新 attachAuxEffect() ,getAudioSessionId(), setAudioSessionId(int), 和 setAuxEffectSendLevel() .
相关音效在 AudioFxDemo.java 的 ApiDemos 示例。

6. 照片EXIF信息改进
新增 经纬度标签在JPG格式的EXIF中,同时可以使用 getAltitude() 方法获取经纬度的EXIF信息
新增setOrientationHint() 可以让程序获取视频录制的方向.

7. 下载管理
在Android 2.3中新增的下载管理支持长时间运行的Http下载服务支持。可以保证在手机重启后仍然重试下载等操作,整个过程在后台执行。
通过 DownloadManager 类使用getSystemService(DOWNLOAD_SERVICE) 来实例化,通过 ACTION_NOTIFICATION_CLICKED 这个Intent来处理。
http://www.android123.com.cn/androidkaifa/723.html

8. 限制模式
  可以帮助开发者监控他的应用的性能,处理线程阻塞,避免ANR的发生。

StrictMode.ThreadPolicy 和 StrictMode.VmPolicy 获取VM相关信息.
使用限制模式优化的Android应用程序可以查看android.os.StrictMode包的具体介绍。

Android 3.0 API变更概要:
Android 3.0 SDK中新增了哪些API呢? 我们总结下平板系统honeycomb中的新特性, 首先需要澄清的是经过Android123发现设置模拟器的分辨率到普通WVGA这样的解析度时平板的特性自动消失和Android 2.3没有什么太大区别,按照这样来看未来Android 3.0除了兼容平板外还继续可以被手机所支持,据称3.0的代码针对A9双核CPU进行了进一步的改进。

  一、Fragments 碎片容器
  有关Android Fragments的内容,Android开发网在前几天已经用几篇文章详细讲解了下,大家可以从Fragment对比Activity - Android碎片介绍 一文开始了解。

  二、Action Bar 活动栏
  活动栏Action Bar可以替换传统的标题栏在Activity窗口中,包括程序图标和一些新接口在activity的选项菜单中,另外Action Bar允许你
  Include select menu items directly in the Action Bar—as "action items"—for quick access to global user actions.
  In your XML declaration for the menu item, include the attribute, android:showAsAction with a value of "ifRoom". When there's enough room in the Action Bar, the menu item appears directly in the bar. Otherwise, the item is placed in the overflow menu, revealed by the icon on the right side of the Action Bar.
  Add interactive widgets to the Action Bar—as "action views"—such as a search box.
  In the XML for the menu item that should behave as an action view, include the android:actionViewLayout attribute with a layout resource for the action view or android:actionViewClass with the class name of the widget. Like action items, an action view appears only when there's room for it in the Action Bar. If there's not enough room, it is placed in the overflow menu and behaves like a regular menu item (for example, an item can provide a SearchView as an action view, but when in the overflow menu, selecting the item activates the search dialog).
  Add an action to the application logo when tapped and replace it with a custom logo
  The application logo is automatically assigned the android.R.id.home ID,
which the system deliveres to your activity's onOptionsItemSelected() callback when tapped. Simply respond to this ID in your callback method to perform an action such as go to your application's "home" activity.
  To replace the icon with a logo,
  Add breadcrumbs for navigating backward through fragments
  Add built in tabs and a drop-down list for navigation
  Customize the Action Bar themes and custom backgrounds
  有关ActionBar的文章,可以参考 Action Bar使用方法 - Android活动栏 系列文章

  三、System clipboard系统剪切板
  Android 3.0中的剪切板进行了增强,本次可以支持除了纯文本外更多的内容,如,URL和Intent,对于剪切板类ClipboardManager仍然通过 getSystemService(CLIPBOARD_SERVICE)来实例化,新增的ClipData类用于管理具体的复制对象,可以在SDK的 android.content.ClipData.Item中找到。 具体的使用Android123将在今后的文章中写道。

  四、拖拽
  开始拖拽内容在你的Activity中可以使用startDrag()方法在一个View中,这里 View.DragShadowBuilder提供了拖拽时的阴影,对于拖拽的过程处理可以通过OnDragListener通过View的 setOnDragListener()来设置,在拖拽的时候系统会自动调用onDrag()方法。

  五、增强的appWidgets
  Android 3.0的appWidget开始支持更丰富的控件,比如GridView, ListView, StackView, ViewFlipper和AdapterViewFlipper.而以前必须通过RemoteView显示一个文本或图片,本次全新的 RemoteViewsService增强了桌面小插件的功能。

  六、增强的状态提示栏
  新增的Notification API可以丰富你的状态栏,新的Notification.Builder类可以帮助你轻松实现,支持大图标提示信息通过setLargeIcon方法, 通常显示一些社交类的软件,比如联系人照片,或相册缩略图,设置自定义状态栏,可以使用setTicker()方法。

  七、内容加载器
  新框架API提供了一个异步加载内容的泪,合并和UI组件和fragment来动态加载数据从工作者现成,使用CursorLoader子类来获取ContentResolver中的数据.

  八、A2DP蓝牙和耳机控制API
  Android honeycomb中没有忘记再次增强蓝牙,你可以通过初始化BluetoothProfile通过调用getProfileProxy()在处理 A2DP或耳机HEADSET设置,BluetoothProfile.ServiceListener可以获取客户端连接或断开的回调。
  九、动画框架
  3.0中Android再次增强动画播放类,ObjectAnimator和LayoutTransition需要大家了解一些。

  十、扩展UI框架
  新增以下UI控件
  AdapterViewAnimator
  AdapterViewFlipper
  CalendarView
  ListPopupWindow
  NumberPicker
  PopupMenu
  SearchView
  StackView

  十一、图形相关
  1. 2D图形硬件加速Hardware accelerated 2D graphics , 在androidmanifest.xml的 元素中添加android:hardwareAccelerated="true" 即可。他可以优化程序运行更平滑高效,在滚动和动画方面。
  2.设置渲染模式,比如 LAYER_TYPE_HARDWARE 硬件加速和 LAYER_TYPE_SOFTWARE 使用 setLayerType() 方法.
  3.渲染脚本对于3D图形方面大家可以看看Renderscript类。

  上面是Android 3.0的主要改进,明天Android开发网将和大家一起说下强大的对于平板电脑比较重要的Action Bar活动栏。

posted @ 2011-07-15 09:32 oathleo 阅读(1182) | 评论 (0)编辑 收藏

在很多地方都有“数据交换”这个概念,本文所说的“数据交换” 是指在计算机网络中,一个系统把数据传递给另外一个系统。这非常类似于一个人要告诉另外一个人一件事情。

当一个人要把一件事情告诉另外一个人的时候,我们可以通过电话、邮件、短信、IM工具或者当面说的方式来交流。这种方式类似于系统数据交换要通过 tcp、udp、管道等等的方式实现。当两个人交流的时候,我们需要一种共同的语言才能明白对方的意思,同样的,两个系统要交换数据,也需要定义一种双方 都明白的协议,我们称为“数据交换协议”。

数据交换协议

数据交换协议的目的是让两个系统进行正确的数据交互。所以几乎各种开发语言都提供了方便使用的数据交换功能。比如说使用JAVA语言的开发的系统使 用 MySQL数据库存储数据,就是通过MySQL数据交换协议跟MySQL做数据交换;通过JAVA的RMI可以方便的做跨机器的分布式数据交换,RMI也 就是一种数据交换协议。

一般我们在不同的系统、不同的语言之间交换数据的时候,我们会选择一种通用的交换协议或者自己定义一种容易使用的交换协议。 WebService曾经非常流行, 在Web 2.0时代,轻量级的REST协议又开始受到追捧。那么究竟在我们的系统中应该选择什么样的协议呢?

如何选择数据交换协议

选择什么样的协议跟我们的应用场景有很大的关系。我们需要考虑我们开发是否方便、接口是否容易发布、是否需要考虑带宽占用成本、序列化和反序列化的性能、接口协议的扩展性等等。下面我们看下几个比较常用的交换协议实现。

协议 实现 跨语言 性能 传输量 RPC
xml 广泛 几乎所有 很大 N(可实现)
json 广泛 大量 一般 一般 N(可实现)
php serialize PHPRPC 大量 一般 一般 Y
hessian hessian 大量 一般 Y
thrift thrift 大量 Y
protobuf protobuf 大量 N(可实现)
ice ice 大量 Y
avro Apache Avro 少量 Y
messagepack messagepack 大量 Y

上面表格列出了一些常用数据交换协议的一些特性的比较。这里并没有比较好坏,只是想说明不同数据交换协议是有区别的,所以我们需要在我们的应用场景中进行选择。

开放式

像微博,SNS这种开放平台、对静态html页面提供javascript接口调用的系统都属于这种类型 。这种类型的特点是:

  • 调用方不完全可控,而且是针对公网的,你可能不知道是谁、是什么语言、是什么方式在调用你提供的数据接口;
  • 接口访问量一般都非常大,要求具有很高的性能和吞吐量;
  • 需要考虑安全问题,外部提交的数据可能不是合法的。

所以在这种情况下,需要考虑数据传输的带宽消耗和数据交换协议的易用性,以及多语言支持程度。以前对于html页面使用的javascript接口 调用一般都使用XML格式,最近几年几乎都转成了json格式了,因为json传输量更小,比XML更加容易使用。 而对于开放平台,由于使用的场景很多,所以需要提供多种交换协议格式。基本上都会提供XML和json。为了提高平台本身的性能和客户端的性能,也可以提 供protobuf这种二进制交换协议并且增加压缩支持,以节省带宽传输和解析的性能消耗。

内部服务

对于一个大型系统来说,内部服务的数据交换无处不在。从最基本和常见的数据库数据交换、memcached缓存数据交换、消息队列的数据交换到系统 之间使用的RPC服务框架等等,都可以算作内部服务的数据交换。内部服务的特点是不用考虑防火墙,不对外开放,速度快(基本无带宽成本)。

内部服务的数据交换协议的选择空间非常大,一般需要考虑:

  • 数据交换协议的性能
  • 是否需要跨语言支持
  • 数据交换协议的消息体大小

持久化存储

对于持久化存储来说,每一种数据交换协议其实都可以实现。一般需要根据应用场景考虑:

  • 是否人工可阅读
  • 存储的空间消耗
  • 序列化和反序列化的性能
  • 是否经过压缩

跨语言

假设我们的网站前端页面展示层使用PHP语言开发,中间业务逻辑使用JAVA语言开发,那么就涉及到跨语言数据交换的问题。只要系统不是单纯的使用一种语言,那么就必须考虑这个问题。事实上,考虑未来的扩展和需求变化问题,也最好考虑跨语言的数据交互协议。

数据交换协议可升级

在选择数据交换协议的时候,我们同样需要考虑类似于数据库表的?schema设计时的扩展问题。比如一个提供用户信息的数据交换协议接口,现在包含 用户名、性别、住址的信息,在升级过程中,增加了一个最后登录的IP信息。如果不考虑数据交换协议升级带来的影响,很可能会导致以前的客户端出现异常或者 旧的数据无法正确解析的问题。

兼容协议的巧用

兼容协议的巧用非常有用,新产品兼容提供现有成熟的数据交换协议,可以降低使用门槛和产品的开发速度。比如新浪开源的memcacheQ就使用了memcached协议。

总结

数据交换协议的各种通用开源实现非常多,数据交换协议只是一个非常宽泛的说法,其实只要实现了数据的序列化和反序列化 ,那么就可以说是一个可以交换数据的协议。数据交换协议的性能其实就是序列化和反序列化的性能,如果加上RPC,那么跟RPC实现本身的性能也有非常大的 关系。

posted @ 2011-05-09 16:41 oathleo 阅读(254) | 评论 (0)编辑 收藏

有这样一群人,他们经常孤独地工作到深夜,漆黑夜里的显示器成为房间中唯一的光源,手边残留着比萨饼和碳酸饮料。繁重的编码任务让他们很少离开座位,即便是周五的深夜,这些人依旧在办公室中奋战。
乍一听,这像是在描述黑客们的工作状态。但实际上,大多数普通的开发人员就是这样生活着。除了工作,他们有家庭、兴趣以及责任,但项目的压力让他们无暇顾及工作以外的事情。工时长、假期短以及与当前社会发展脱节等问题普遍存在于他们当中。

虽然现在社会大力倡导所谓的知识经济,但这群聪明且高度专业化的人员不被重视,因为经理们认为,程序员是替代性很强的群体。这样的观念导致这些潜在的社会精英不得不重新考虑他们的职业规划。最终,他们当中的大多数另谋高就,另一些则踏入到全新的行业之中。

你认为游戏行业真的是一片乐土吗?一名业内人士讲,游戏开发几乎会占据程序员生活的全部,因为产品质量总会有改进的余地。他们工作时间长,没有加班费以及应有的假期。有些员工甚至连续四年薪水都没有调整过。他身边不少同事都是因为工作而导致了离婚。

当工作条件变得无法忍受时,最聪明以及最有天分的员工通常是最先离开的。凭借他们的资质,他们可以在其他领域挖掘到更多的机会。这样势必导致开发团队整体 水平的下降。经理对开发者施加的压力越大,长期来看团队的效率就越低。IT顾问布鲁斯·韦伯斯特将这种情况称为“死海效应”。如果公司发展每况愈下,它就 更难得到真正的人才,也更难留住这些人,这样的恶性循环无疑会拖垮公司。离岸外包的出现则加剧了这种趋势:内部开发团队的效率越低,公司就越希望通过低成 本外包取代这个团队。而内部开发者会强烈地感到他们即将被替代,因此无法集中精力工作。

员工的倦怠会毁掉公司的未来,而经理们是可以降低死海效应的。他们可以设定合理的工作时长并且提供加班费,可以规定公休日并严格地执行,可以设置合理的产 品发布时间以减少过度的压力。他们甚至可以尝试调整项目的开发方法,比如采用敏捷开发等。但是,最重要的一点就是,他们必须重新审视开发人员的价值。在这 样一个与互联网发展速度同步的领域,每一个员工都应该被公平、公正地对待,并且获得应有的尊重,即使他们真地喜欢比萨饼和碳酸饮料。

posted @ 2010-08-10 09:51 oathleo 阅读(1680) | 评论 (0)编辑 收藏


功能很简单:
1.从后台实时取数据展示 Demo 是用socket取,起Task每秒去取
2.把取得数据展示成图表形式
3.把取得数据展示成拓扑图形式
代码很简单,拓扑部分在另个项目中,以后集成进Demo

posted @ 2010-08-04 16:37 oathleo 阅读(1906) | 评论 (3)编辑 收藏

Android 2.1 API变更概要:
Live Wallpapers 动态桌面
以下增加的API可以提供你开发动态的桌面:
· android.service.wallpaper.
· WallpaperInfo.
· 升级的WallpaperManager.

附加说明, 如果你的应用相提供Live Wallpapers的功能, 你必须记得增加一个 <uses-feature> 元素到你的应用manifest里面. 宣布这个属性android:name="android.software.live_wallpaper". 举例:<uses-feature android:name="android.software.live_wallpaper" />


电话

· 新的SignalStrength 类提供当前网络信号的一些信息这些信息可以从onSignalStrengthsChanged(SignalStrength) 回调.


· 新的onDataConnectionStateChanged(int, int) 回调.
Views
· 新的View 方法isOpaque()onDrawScrollBars(Canvas).
· 新的RemoteViews 方法addView(int, RemoteViews)removeAllViews(int).

· 新的ViewGroup 方法isChildrenDrawingOrderEnabled()setChildrenDrawingOrderEnabled(boolean).


WebKit
· 新的WebStorage 方法操作网页数据缓存.
· 新的GeolocationPermissions 方法获取 Geolocation permissions 的出处, 把他们设置到 WebView.
· 新的WebSettings 方法管理软件缓存, 网页缓存 和屏幕的缩放.
· 新的WebChromeClient 方法处理视频, 历史记录, 自定义view, 软件缓存限制还有其他

Android 2.0.1 API变更概要:
· 新的快速联系人标记风格(quickContactBadgeStyle)* 属性,让应用的QuickContactBadge 组件接收必要的风格.
· 当在manifest里面宣布了filter,取消了支持 ACTION_CONFIGURATION_CHANGED 广播 ,如果想要去接收这个广播, 这个应用必须注册 registerReceiver(BroadcastReceiver, IntentFilter).
性能上的改变:
Bluetooth
改变了 ACTION_REQUEST_ENABLEACTION_REQUEST_DISCOVERABLE的返回值
· ACTION_REQUEST_ENABLE 如果蓝牙是成功开启的,现在返回RESULT_OK .如果使用者拒绝开启蓝牙的请求,则会返回RESULT_CANCELED .
· ACTION_REQUEST_DISCOVERABLE 如果使用者拒绝启动蓝牙或者蓝牙的可发现功能,则返回 RESULT_CANCELED .
通讯
The ACTION_INSERT Intent returns RESULT_CANCELED in cases where the contact was not persisted (例如剪切保存到一个空的操作里面).
修复错误:
资源
现在framework可以正选择应用资源的根据API等级划分的文件夹(drawable-v4API level4版本用的资源).现在的版本这个功能不能正常工作的问题已经修复.
Contacts
The ACTION_INSERT Intent now returns the appropriate kind of URI when the request is made using the (now deprecated) Contacts APIs.
Other Framework fixes
· getCallingPackage() 现在正确的报告包名, 而不是进程名.

Android 2.0 API变更概要:
Bluetooth
· 开启关闭蓝牙
· 设备和服务发现
· 使用 RFCOMM连接一个可插拔的设备收发数据
· 公布RFCOMM 服务和监听接收 RFCOMM 连接
Sync adapters
· 新的APIs, 同步桥接器连接任何backend
Account Manager
· 集中的帐户管理器 API ,安全的储存和使用可信的tokens/passwords
Contacts
· 新的通信APIs 允许获取多个账户的数据.
· 新的快速通信framework APIs 允许开发者在他们的应用中创建通信标记, 一键点击标记打开一个新的窗口展示一个如何联系当前人的列表.
WebView
· 不赞成使用的类: UrlInterceptHandler, Plugin, PluginData, PluginList, UrlInterceptRegistry.
Camera
· 颜色模式, 场景模式 闪光模式, 焦点模式, 白平衡 旋转和其他设置的新的特征.
· 当缩放级别改变的时候,会回调新的缩放回调接口.
Media
· MediaScanner现在为所有图片生成缩微图when they are inserted into MediaStore.
· 新的缩微图 API : 检索需要的图片和视频的缩微图.
Other Framework
· android.R.style 中新的系统主题,能够更加简单的显示当前acitivities的系统壁纸或者保持之前的activity在后台.新的壁纸管理器API 取代并且增加了wallpaper APIs ,我们可以允许我们的应用要求设置系统壁纸.
· 新的Service APIs帮助应用准确的处理Service 生命周期 ,在指定的低内存状态下service将会被关闭.
o Service.setForeground() 不推荐使用,并且现在这个方法并没有实际执行. .他被一个新的API所取代, startForeground(), that helps (and requires) associating an ongoing notification with the foreground state.
· MotionEvent 如果设备允许的话,MotionEvent 会返回多点触摸信息.最多可同时获取3
· KeyEvent 现在有了新的按键发送 APIs,去帮助实现 action-on-up 和长按键行为, 一个新的机制取消按键 (虚拟按键).
· WindowManager.LayoutParams 现在有了新的常量允许窗口能够在被锁或者其他的状况中唤醒屏幕,这个允许程序能够让例如闹钟等的应用实现唤醒设备.
· New Intent APIs 广播设备的对接状态,当这个设备放在桌面或者停车场,允许程序启动特殊的activity.
Key events executed on key-up
Android 2.0能够使用虚拟按键HOME, MENU, BACKSEARCH,而非物理按键,为了让用户在他们的设备中获得最好的用户体验,android平台现在把这些按键执行加入到了key-up,做了 key-down/key-up 配对,而非只有key-down.,这有助于防止意外按钮事件,并让使用者按下按钮区域,然后拖动而不生成一个事件出来。
这种改变只会影响你的应用程序一点,如果它是拦截按钮事件,最好用key-down,而不是key-up.特例,如果您的应用程序拦截BACK 键,你应该确保你的应用妥善处理按键事件
Android 1.6 API变更概要:
UI framework
· 新的类 android.view.animation 控制动画行为:
o AnticipateInterpolator
o AnticipateOvershootInterpolator
o BounceInterpolator
o OvershootInterpolator
· 新的XML 属性android:onClick ,从一个layout文件描述一个viewView.OnClickListener.
· 对不同分辨率的屏幕的新的支持. 对于BitmapCanvas会执行有针对性的缩放行为.该框架会根据屏幕分辨率和其他内容自动缩放bitmap.
要在你的应用中使用Android 1.6包含的API的话你必须要设置 "4"属性在manifest<uses-sdk> 元素中
Search framework
· 应用程序现在可以公开的有关内容,作为建议放入快速搜索框,新的设备范围内的搜索功能,是可从主屏幕搜索。为了支持这一点,搜索框架增加了新的属性,可搜索的元数据文件。有关完整的信息,请参阅SearchManager
文档。
Accessibility framework
· New android.accessibility package that includes classes for capturing accessibility events and forwarding them to an AccessibilityService handler.
· New AccessibilityService package that lets your application track user events and provide visual, audible, or haptic feedback to the user.
Gesture Input
· 新的gesture API :创建,识别,读取,保存手势.
Text-to-speech
· 新的android.speech.tts 包提供了TTS文本朗读功能,从一个文本生成一个声音文件的回放.
Graphics
·
android.graphics 中的类,现在支持为不同的屏幕尺寸进行缩放.
Telephony
· 新的SmsManager 发送和接受短信.
Utilities
· 新的DisplayMetrics 字段决定当前设备屏幕的密度.
Android Manifest elements
o 新的<uses-feature> 元素
o 新的<supports-screens> 标签
o glEsVersion: 指定最小openGL ES的版本
·
<uses-sdk> 元素的新的属性:
o 目标SDK版本: 应用程序能够指定目标版本. 它能够运行在旧版本(低至minSdkVersion, 他是按照应用程序的指定版本开发的. Specifying this version allows the platform to disable compatibility code that is not required or enable newer features that are not available to older applications.
o maxSdkVersion: 指定设计这个程序运行的最高版本 重要: 当使用 <uses-sdk> 这些属性前请认真阅读文档.
New Permissions
· CHANGE_WIFI_MULTICAST_STATE: 允许应用进入Wi-Fi 多点传送模式.
· GLOBAL_SEARCH: 允许全局搜索系统,以便精确确定 content provider.
· INSTALL_LOCATION_PROVIDER: 允许应用在Location Manager.安装一个location provider.
· READ_HISTORY_BOOKMARKS: 允许应用读取(并不能写) 用户的浏览记录和书签
· WRITE_HISTORY_BOOKMARKS: 允许应用写入 (并不能读) 用户的浏览记录和书签
· WRITE_EXTERNAL_STORAGE: 允许程序写入外部存储器.应用程序使用API级别3下将默认授予此权限 (这对用户可见); 应用程序使用API level4 或者更高的,必须要明确的宣告此权限.

Android 1.5 API变更概要:
UI framework
· Framework for easier background/UI thread interaction
· SlidingDrawer 组件
· HorizontalScrollview 组件
AppWidget framework
· 一些关于创建桌面AppWidget API.
· 提供根据自定义的内容创建LiveFoldersAPI
Media framework
· 原声录音和回放 APIs
· 交互式的MIDI 回放引擎
· 开发者使用的视频录像API (3GP format).
· 视频相片分享 Intents
· 媒体搜索Intent
Input Method framework
· 输入法服务framework
· 文本预测引擎
· 提供具有下载能力的IME给使用者
Application-defined hardware requirements
应用可定义硬件需求,应用程序可以定义 <uses- configuration> 说明此程序需要什么硬件需求.比如是否需要物理键盘或者轨迹球.
Speech recognition framework
· 支持语音识别库.
Miscellaneous API additions
· LocationManager -应用可以接收到位置改变的信息.
· WebView - 触摸start/end/move/cancel  DOM 事件的支持
· 重建Sensor Manager APIs
· GLSurfaceView - 创建OpenGL 应用更加方便的framework .
· 软件升级安装成功的Broadcast Intent - 更加平和优秀的软件升级体验

posted @ 2010-08-02 13:29 oathleo 阅读(688) | 评论 (1)编辑 收藏

很明显UI上的线程安全在Android上控制的也很严格

如果需要做大运算,取网络数据等,得用AsyncTask



AsyncTask

首先AsyncTask是一个抽象类,子类继承AsyncTask必须实现其抽象方法doInBackground(Params…)。同时我们还需要实现onPostExecute(Result),因为结果会在Result中返回。

AsyncTask的生命周期

AsyncTask的生命周期分为四部分,每部分对应一回调方法,我们只需实现这些方法中的某些需要用到的方法。程序执行过程中这些会自动调用它们。

  • onPreExecute():任务执行之前执行,可在这显示进度条。
  • doInBackground(Params…):后台执行,主要用于完成需要任务。执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
  • onProgressUpdate(Progress…):主线程执行,用于显示任务执行的进度。
  • onPostExecute(Result):主线程执行,任务执行的结果作为此方法的参数返回。

AsyncTask中的三种泛型

AsyncTask中的三种泛型类型为Params、Progress、Result。

  • Params:启动任务参数,比如请求的资源地址。
  • Progress:顾名思义,后台任务执行的百分比。
  • Result:后台执行任务返回的结果。

AsyncTask的执行

AsyncTask只能在在主线程中创建实例,创建实例后使用execute(params)执行。任务仅会执行一次,如果想再调用就必须创建新的实例。

具体实现

首先我们先继承实现AsyncTask,然后在主线程的getView()里创建其实例execute().

1、实现AsyncTask

public class DownImageTask extends AsyncTask {
private ImageView gView;
 
protected Bitmap doInBackground(ImageView... views) {
Bitmap bmp = null;
ImageView view = views[0];
HotelListData.Item item;
// 根据iconUrl获取图片并渲染,iconUrl的url放在了view的tag中。
if (view.getTag() != null) {
try {
item = (HotelListData.Item) view.getTag();
URL url = new URL(item.getI().toString());
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setDoInput(true);
conn.connect();
InputStream stream = conn.getInputStream();
bmp = BitmapFactory.decodeStream(stream);
Data.imageMap.put(item.getId(), bmp);
stream.close();
} catch (Exception e) {
Log.v("img", e.getMessage());
return null;
}
}
this.gView = view;
return bmp;
}
 
protected void onPostExecute(Bitmap bm) {
if (bm != null) {
this.gView.setImageBitmap(bm);
this.gView = null;
}
}

2、在UI主线程中创建其实例并execute()执行

HotelListData dlData = new HotelListData();
HotelListData.Item item = dlData.new Item();
 
item = (HotelListData.Item) infoVector.getLs().elementAt(position);
holder.text0.setText(item.getN());
 
holder.star.setImageDrawable(getResources().getDrawable(
imageIndex[Integer.parseInt(item.getS().toString())]));
 
holder.text2.setText(item.getP());
holder.text3.setText(item.getA());
 
if (item.getI() != null &amp;&amp; (!item.getI().equals(""))) {
Bitmap bm = returnBitMap(item.getId());
if (bm != null) {
holder.image.setImageBitmap(bm);
} else {
if (!holder.image.isDrawingCacheEnabled()
|| !holder.image.getTag().equals(item.getI())) {
holder.image.setImageResource(R.drawable.img_loading);
holder.image.setTag(item);
try {
new DownImageTask().execute(holder.image);
holder.image.setDrawingCacheEnabled(true);
} catch (Exception e) {
Log.e("error",
"RejectedExecutionException in content_img: "
+ item.getI());
}
}
}
}

简要

首先创建了DownImageTask,该类继承实现了AsyncTask的doInBackground()和onPostExecute(), 如上面所介绍,当在getView中创建实例并execute()传入需要获取资源地址URL(地址在TAG中)执行异步线程任务后,程序首先调用 doInBackground()。

doInBackground()从传入的Image TAG中获取资源的URL地址进行图片的获取,获取完毕Retrun结果给onPostExecute(),onPostExecute()里再去做相应的结果处理。



posted @ 2010-07-30 11:59 oathleo 阅读(1338) | 评论 (1)编辑 收藏

Android Emulator是一款功能非常齐全的模拟器,电话本、通话等功能都可进行模拟。甚至其内置的浏览器和Google Maps都可以联网。用户可以使用键盘输入,击模拟器按键输入,甚至还可以使用鼠标击、拖动屏幕进行操

1.模拟器和真机的不同之处

    * 不支持呼叫和接听实际来电但可以通过控制台模拟电话呼叫(呼入和呼出)

    * 不支持USB连接

    * 不支持相机/视频捕捉

    * 不支持音频输入(捕捉)但支持输出(重放)

    * 不支持扩展耳机

    * 不能确定连接状态

    * 不能确定电池电量水平和交流充电状态

    * 不能确定SD卡的插入/弹出

    * 不支持蓝牙

 

2.参数大全

Android模拟器emulator.exe文件包含了很多参数,平时在Eclipse IDE中模拟器运行自动调用的,如果仅仅使用Android emulator或采用NetBean这样的开放环境又如何设置呢? 我们总结了一下模拟器的所有参数及使用方法,具体如下所示。 

 

 Android Emulator usage: emulator [options] [-qemu args]
  options:
    -system <dir>       read system images from <dir>
    -datadir <dir>      write user data into <dir>
    -kernel <file>      emulated kernel
指定内核文件
    -ramdisk <file>     ramdisk image (default <system>/ramdisk.img) 创建内存磁盘
    -image <file>       system image (default <system>/system.img)
    -initdata <file>    initial user image (default <system>/userdata.img)
    -data <file>        working user image (default <datadir>/userdata-qemu.img)

   
    -nocache            disable the cache partition 禁止分区缓存
    -sdcard <file>      SD card image (default <system>/sdcard.img) 使用SD卡映像
    -skindir <dir>      search skins in <dir> (default <system>/skins) 搜索外观皮肤路径
    -skin <skin>        select a given skin 选择Android模拟器皮肤ID
    -noskin             don't use any emulator skin 不使用任何模拟器外观,这样有助于提高模拟器速度,内存小的用户可以尝试

    -netspeed <speed>   maximum network download/upload speeds 设置网络速度如GPRS、EDGE、3G更多详细的
内容下面有介绍
    -netdelay <delay>   network latency emulation 网络延时设置
    -netfast            disable network shaping (full speed, no latency) 网络全速工作
    -trace <name>       enable code profiling (press F9 to start) 跟踪调试
    -debug-kernel       send kernel output to the console 内核调试
    -console            enable console shell on current terminal 启用控制台
Shell在当前中端
    -nojni              disable JNI checks in the Dalvik runtime 禁用JNI检查
    -logcat <tags>      enable logcat output with given tags 设置log输出标签
    -noaudio            disable android audio support 禁用音频支持
    -useaudio           enable android audio support (default) 启用音频支持
    -mic <file>         WAV file for audio input 使用wav文件模拟mic麦克输入
    -flash-keys         flash key presses on the device skin
    -raw-keys           disable Unicode keyboard reverse-mapping
    -radio <device>     redirect radio modem interface to character device
    -oldradio           enable old VM-based simulated radio
    -onion <image>      use overlay image over screen
    -onion-alpha <%age> specify onion skin translucency (default 50)
    -http-proxy <proxy> make TCP connections through a HTTP/HTTPS proxy
代理服务器设置
    -verbose            enable verbose output
    -verbose-keys       enable verbose key presses
    -verbose-proxy      enable proxy debug messages
    -version            display emulater version number

    -qemu               pass arguments to qemu
    -qemu -h            display qemu help
    -help               print this help

   Default network latency is 'none'

  <proxy> can be one of the following:

    http://<server>:<port>
    http://<username>:<password>@<server>:<port>

  the 'http://' prefix can be omitted. If '-http-proxy <proxy>' is not used,
  the 'http_proxy' environment variable is looked up and any value matching
  the <proxy> format will be used automatically

3.快捷键 

Android模拟器同样存在很多快捷键,当模拟器运行时,可以使用下面的快捷键来操作Android emulator,这样比键盘和鼠标操作更高效,不妨试一下:

D:"unsetup"android-sdk-windows-1.1_r1"tools>emulator.exe -help-keys

 

  When running the emulator, use the following keypresses:

 

    HOME                    Home button 主界面键

    F2, PAGEUP              Menu (Soft-Left) button 左软键

    Shift-F2, PAGEDOWN      Star (Soft-Right) button 右软键

    ESCAPE                  Back button 后退键

    F3                      Call/Dial button 拨号/呼叫键

    F4                      Hangup/EndCall button 结束通话

    F4                      Power button 电源键

    F5                      Search button 搜索键

    KEYPAD_PLUS, Ctrl-F5    Volume up button 增大音量键 

    KEYPAD_MINUS, Ctrl-F6   Volume down button 减小音量键

    Ctrl-KEYPAD_5, Ctrl-F3  Camera button 相机键

    KEYPAD_7, Ctrl-F11      switch to previous layout 返回键

    KEYPAD_9, Ctrl-F12      switch to next layout 后一个界面

    F8                      toggle cell network on/off 禁止/启用所有网络

    F9                      toggle code profiling 开始跟踪

    Alt-ENTER               toggle fullscreen mode 打开/关闭全屏模式

    F6                      toggle trackball mode 打开/关闭轨迹球

    DELETE                  show trackball 显示轨迹球

    KEYPAD_5                DPad center 导航中建/OK键

    KEYPAD_4                DPad left 左键

    KEYPAD_6                DPad right 右键

    KEYPAD_8                DPad up shang 上键

    KEYPAD_2                DPad down 下键

    KEYPAD_MULTIPLY         increase onion alpha

    KEYPAD_DIVIDE           decrease onion alpha

   Ctrl+F11 对模拟器的屏幕切换。

4.模拟器使用注意事项

平时使用emulator测试开发程序时,可能会遇到系统关于C盘空间不足之类的提示,这是由于Android模拟器每次运行时会临时生成几个.tmp后缀的临时文件,一段时间后,其可能占用几G的磁盘空间。所以需要手工定期清理下C:"Documents and Settings"sh"Local Settings"Temp"AndroidEmulator文件夹下的内容。

posted @ 2010-07-29 15:39 oathleo 阅读(539) | 评论 (0)编辑 收藏

    如果有一天,技术高度发达,发达到生产了一种机器,可以接通人的大脑,产生所有人类可以感知的感觉。
人戴上这种帽子样的机器,就进入幻想世界,在幻想的世界里面所有感觉都和真实的一模一样。
    想吃就吃,想睡就睡,想买房就买房,想干坏事就干坏事,想有美女就有美女...
有了这玩意,人类还能进步吗?

   

posted @ 2010-07-27 16:20 oathleo 阅读(1770) | 评论 (7)编辑 收藏

Google获准在中国运营Google.cn域名的ICP牌照于6月30日到期。在美国西部时间6月28日晚间10点(北京时间6 月29日下午1点),Google通过官方博客发布“关于谷歌中国的最新声明”称,在与中国有关部门的沟通中已明确获知,自动指向的做法是不可接受的,继 续进行自动指向,域名Google.cn的ICP牌照将无法通过年检。

感谢google.cn!是我们自己命运不济,出生卑微。

posted @ 2010-07-01 09:45 oathleo 阅读(1970) | 评论 (7)编辑 收藏

应用:javax.script 包

javascrip 操作 java对象。

GEllipse ellipse = new GEllipse();//自定义java对象
//添加上下文绑定数据
SimpleBindings bindings = new SimpleBindings();
bindings.put("ellipse", ellipse);
ScriptEngine engine = sem.getEngineByExtension("js");
engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
try{
     engine.eval(" ellipse.setX(101);");//脚本里设置自定义java对象对象属性
     System.out.println(ellipse.getX());//输出101,测试OK
}catch(Exception ex){
    ex.printStackTrace();
}

posted @ 2010-06-30 17:09 oathleo 阅读(1461) | 评论 (1)编辑 收藏

Web的功能会越来越强大,这点基本上没有多少人会反对。想想那么多在各种操作系统下跑的五花八门的应用程序,今天基本都能在Web上找到类似的应用,原因太简单了,现在的客户要求已经随着PC和互联网的发展慢慢提高了,他希望能在iphone里看股票,希望在imac上办公,在blackberry里收邮件,谁能跨这么多复杂而多变的各类系统?

只有Web

Web就离不开浏览器,当然如果更加激进些,哪天整个操作系统都是web,那可能就没有浏览器一说了。就时下来说,Web真的已经发展的很强大了。我们可以在浏览器里看新闻,逛论坛,采购物品,收发邮件,在线协同工作,操作office,游戏等等等等。如果说Web相当于桌面应用程序还有什么软肋的话,那就是浏览器里的图形展示。

说到这篇文章的重点,先大概梳理一下。目前浏览器端的图形展示解决方案。Web里的图形解决方案笔者自己给他大概分两种,一种叫无插件,一种叫有插件。无插件嘛就是浏览器原生支持,就像打开html一样。有插件嘛当然就是要装插件的,插件就类似ActiveX等。

先说说有插件的,里面按使用人数又有大众版和专业版,大众版笔者罗列了几个

1.  FlashFlex

2.  Java Swing,JavaFX

3.  Silverlight

4.  VRML

 

在这几项技术FlashFlex感觉是个比较有前途的方向,面向对象的语言,动静结合的对象,基本各类浏览器都兼容的插件和现实效果,丰富的动态效果和绚丽的展示等,都是目前Web里图形展示的Top one。唯一让人感觉缺憾的是adobe这个设计师出生的公司,总让程序员感觉不爽(要是IBM出的这技术该多好)。所以笔者是对Flex的源码实现比较不齿,这哪里像个精品代码应有的样子。如果说还有什么缺陷,效率是一个,无法集成入搜索是一个,回退算是一个吧。

Swing要在Web展示,只能Applet了,这项被千万java程序员唾骂的技术还是有顽强的生命力。为什么?实在是没有办法,除了它还能谁?(相对java程序员) 其实swing是个很不错的技术,可惜了Sun好像不在意Applet的巨大潜力,只关系它的J2EE去了。唉!好在亡羊补牢,来了个新的JavaFX,只是java程序员已经对Applet心有余悸,JavaFx发展如何,再看看吧。

微软的程序员有大奔头了,因为他们有了SL,看看SL刚刚出来时候,那声势浩大的场面,真的是……如果我是微软程序员,我肯定会搞搞SL,虽然它组件依旧很少,客户端依旧安装率不高。我就不怕,等的就是内置SL,绝对可以秒掉很多Flash的市场。

VRML最近才了解到的一个技术,看了下效果还是很震撼,可能程序员不是很熟原因也是它支持的公司基本都是设计软件的公司。插件的安装率估计是最低的,不了解的不说,一笔带过。

 

上面说完了有插件,下面轮到无插件了,无插件的估计就那几个:

1.       VML

2.       SVG

3.       Canvas

VML(Vector Markup Language) 微软的早期浏览器支持的图形展示的一种格式。最大的特点就是只有IE支持,微软估计当年根本没想到IE的占有率会跌到60%,唉千万不要低估消费者。你不行就靠边,我用鼠标说话。

SVG(Scalable Vector Graphics) 我在无插件里最看好的技术,XML的子集,W3C下的一个项目,早几年不瘟不火的,这几年起来了,何以见得?HTML5的标准,IE9原生支持,看看各大厂家,谁希望被AdobeFlash把持这么大一块市场。当然由于微软的原因IE9以前的版本还都需要插件才能支持SVG

Canvas HTML5里另外一个重头戏,介绍也是很多了,至于为什么会既有SVG又有Canvas我还真的不甚明白,谁知道W3C每天都在琢磨什么呢。最大的特点是2d的方式绘画图形,而不像SVG是标签式的。

posted @ 2010-06-21 21:36 oathleo 阅读(1760) | 评论 (1)编辑 收藏

version jdk1.6

很早就听说了这个功能一直没仔细看看,尝试了下 功能不错!

    public static void main(String[] args) {
        ScriptEngineManager sem = new ScriptEngineManager();
       
        //添加上下文绑定数据
        SimpleBindings bindings = new SimpleBindings();
        bindings.put("aaa_av", new Double(10000.1));
        bindings.put("bbb_av", new Double(20000.2));
       
        ScriptEngine engine = sem.getEngineByExtension("js");
        engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
        try{
            //直接解析
            Object res = engine.eval(" res =  Math.max(aaa_av , bbb_av) + aaa_av");
            System.out.println(res);
           
           
            //创建脚本
            String script = "function getMax() "
                + "{ return Math.max(aaa_av , bbb_av)}";
            //执行脚本
            engine.eval(script);
            Invocable inv = (Invocable) engine;
            //执行方法并传递参数
            Object obj = inv.invokeFunction("getMax", null);
            //打印结果
            System.out.println(obj);

        }catch(Exception ex){
            ex.printStackTrace();
        }
    }

posted @ 2010-06-03 15:04 oathleo 阅读(3387) | 评论 (3)编辑 收藏

如果能把大量的swingUI 与画图 结合在一起,可以任意保存成xml或者二进制的文件, 那大量的swing程序,会简化成大量的工程人员画图而成的文件。
当然复杂的UI还是需要编程,而编程完不再需要打包进产品或者项目,而是让工程人员做成文件的方式,保存下来。
这样的思路是否能运用到实际的swing项目,还未可知,但某些特定的项目,也许可以使用。

废话不说了,看看效果: 画图工具里,从文件里读取了两个table。

posted @ 2010-05-31 11:18 oathleo 阅读(2791) | 评论 (4)编辑 收藏

    微软IE团队总经理迪恩·哈克莫维奇(Dean Hachamovich)今天发表声明称,IE 9与以往的IE版本有很大不同。他表示,微软将每8周对预览版IE 9进行一次升级,第一次升级将在5月中期。但哈克莫维奇没有披露正式版IE 9的发布时间。

下 载:Internet Explorer 9 预览版

微软称,预览版IE 9还不是一款完整的浏览器,目前还不包括地址栏等用户导航工具以及安全功能。微软发布了一个它称之为“Test Drive”的网站,方便网站设计人员、应用开发者了解预览版IE 9的功能。

预览版IE 9只支持Windows 7、Windows Vista SP2和Windows Server R2。IE 9可以利用图形处理器的处理能力加速文本和图形的渲染。

用户可以从Test Drive网站下载大小为31MB的预览版IE 9。


=============================================================

里面图形的Demo 包括Graphics 里面的几个例子,都是用SVG实现,包括了Map Chart等。有了IE支持,看样子SVG又要发第二春了。

Canvas暂时还没有看到使用例子。

posted @ 2010-03-17 09:02 oathleo 阅读(1647) | 评论 (0)编辑 收藏

如果两个对象equal,那么它们的hashCode值一定要相同;2、如果两个对象的hashCode相同,它们并不一定equal

当Set要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在 这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。

所以两个不equal的对象,有相同的hash,是可以存进Set的。

class HashNode {
    int id;
   
    public HashNode(int id){
        this.id = id;
    }
   
    public int hashCode() {
        return id;
    }
   
    public boolean equals(Object obj) {
        return false;
    }
}

public class HashTest {

    public static void main(String[] args) {
        HashNode n1 = new HashNode(1);
        HashNode n2 = new HashNode(1);
       
        HashMap map = new HashMap();
        map.put(n1, "111");
        map.put(n2, "222");
       
        System.out.println(n1.equals(n2));
        System.out.println(n1.hashCode() == n2.hashCode());
        System.out.println(map.keySet().size());
    }

}

posted @ 2010-03-03 16:03 oathleo 阅读(1673) | 评论 (4)编辑 收藏

很长一段时间,对MVC和MVP区别很是模糊。
一直忙碌于客户不停的需求中,忽略了产品本身上这些最重要的东西。
现在即将待业,放下自己为之工作近三年的产品,真的感觉犹如失去自己的孩子。
好的一方面是空闲的时间多了,终于可以想想这些事情了。

MVC算是个被人说烂掉的东西了,MVP也屡屡被人提及。
最大的区别在哪里呢?为什么要再演变个MVP出来呢?

就定义上来说最大的区别在于C和P,就构架上来说,是View层实现的方式不同。
MVC:View层肩负很大任务,View关联Model,View的渲染是直接通过Model层的数据来确定的。还是有很多业务逻辑在View上完成。
MVP:View层的任务大大缩减,View不再知道Model,P层完成上面提到的View层完成的业务逻辑。
总之一句话MVP里,View层绝对不能再访问Model了,

任何一种设计模式的出现绝对不是为了出现而出现的。总是为了解决现实中存在的某些老的模式无法或难以解决的问题才出现的。

为什么会出现MVP呢?
看看客户拿到一个设计精良的MVC的产品,做二次开发的时候,如果他项目足够大,肯定会发现MVC的好处。任务集中在Model层,设计好Model层数据的填充,简单的实现就完成了。MVC的架构帮他解决了很多问题,大家很Happy!
当然客户的需求总是永无止境的,当简单需求被满足的时候,他又会往高层次发展,也许他就完全需要不同的View来做同样的Model的展示(比如一个在JSP,一个在Swing或者Android上),在这个时候,稍微想下,他就发现他要做的任务开始变的很大了。Model层的数据纵使可以共享,事件控制(转发)也能,而View层无论如何是逃不了了。于是Web程序员硬着头皮也要学Swing,Swing的程序员郁闷的学JSP。
试想这个时候如果有个人,能把陷在View上的上万行code,拉到一个即能联系到Model,又能联系到View的层次上,那真的要感谢苍天大地了。

MVP我想应该就是在这个时候出现的。它处理所有View和Model之间的消息传递,数据更新,交互操作。比如从Swing的TextField里输入个字段信息,和从JSP里的Form里输入这个字段信息,处理的流程应该是可以共享这段代码的。当然这个时候,为了解决不同View上的一些特殊情况,可以使用适配器模式,来处理多个View的程序设计问题。

设计模式没有好坏之分,只有合不合适。你的产品如果只需要输入个A返回个B,没有平台建议,没有系统升级,那就忘了所有的设计模式,走那条最快实现的路吧。

posted @ 2010-02-28 15:38 oathleo 阅读(2841) | 评论 (6)编辑 收藏




posted @ 2010-02-22 18:03 oathleo 阅读(1500) | 评论 (4)编辑 收藏

Android线程安全问题:

      button2.setOnClickListener(new OnClickListener() {
           ......
     });
加了个监听,里面起Timer,定时修改数据。
发现Log一直在打,View无变化。
估计线程出了问题。类似Swing的线程安全问题。
接着Google.....


The best thing is to  use Handler with delayed messages.
And Timer works fine, the problem is that a Timer runs in a separate thread,   and so you are trying to modify a view owned by another thread (the main   thread that originally created it).

What I think is happening is you're falling off the UI thread. There is a single "looper" thread which handles all screen updates. If you attempt to call "invalidate()" and you're not on this thread nothing will happen.

Try using "postInvalidate()" on your view instead. It'll let you update a view when you're not in the current UI thread.


解决办法和我预计的一样:

1.在Invalidate处调用 postInvalidate,命名上可以参数肯定是把当前的timer线程排队到UI线程去。不过对于我不是很适用,毕竟UI不希望让用户自己去Invalidate

2.既然不能去排队,那就干脆把自己改造成UI线程吧。借助android.os.Handler

          final Handler handler = new Handler();
                Timer timer = new Timer();
                timer.schedule(new TimerTask() {
                    public void run() {
                        handler.post(new Runnable() {
                            public void run() {
                                 root.setName(new Date() + "Root+" );//不一定是显式的调用修改UI的语句
                            }
                        });
                    }
                },1000,3000);   


OK!


 

posted @ 2010-02-04 18:18 oathleo 阅读(272) | 评论 (0)编辑 收藏

1.AWT完全干掉了,看来又要学一遍Android的2D
2.Layout变成一个很爽的东西,类似Swing里JPanel+ Layout的混合体,多好的创意!!当然嵌套啥的是必定支持了
3.java.beans包还存在,又省事不少。
4.sdk还打了一些常用公司包
   包括apache json w3cdom xml.sax等





posted @ 2010-01-19 18:24 oathleo 阅读(186) | 评论 (0)编辑 收藏

     摘要:   阅读全文

posted @ 2010-01-18 18:17 oathleo 阅读(230) | 评论 (0)编辑 收藏

1.BitMap to 数组
        int w = bitmapSrc.getWidth();
        int h = bitmapSrc.getHeight();
       
        int[] pixels = new int[w * h];
        bitmapSrc.getPixels(pixels, 0, w, 0, 0, w, h);

2.RGB HSV互转问题
android.graphics.Color 修复了java.awt.Color 的bug
RGBToHSV HSVToColor

3.Config
       Bitmap bitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);//Config.ARGB_8888,Config.ARGB_4444透明效果


Color 成了int,一下子感觉世界变得简单了。

4.文字的显示长度
            Rect textBound = new Rect();
            paint.getTextBounds(name, 0, name.length(), textBound);

5.文字渲染 x起始点在左下角
       canvas.drawText(name, x, y, paint);


posted @ 2010-01-14 16:32 oathleo 阅读(329) | 评论 (0)编辑 收藏

     摘要:   阅读全文

posted @ 2010-01-13 18:29 oathleo 阅读(273) | 评论 (0)编辑 收藏

1.eclipse 3.5(3.2不支持)
2.模拟器插件
3.Android SDK1.5

3.源代码引入:
ADT是从SDK目录下的“sources” 目录来查找class对应的源代码,这样我们只要把源代码放到sources目录中ADT就可以自动找到对应的源代码了。

 http://www.digginmobile.com/android.asp ,这里有android1.5的源代码,下载源代码后,

在\android-sdk-windows-1.5_r2\platforms\android-1.5下新建一个sources目录,

将源文件放在sources目录下,然后在编写的android的class中就可以看到引用文件的源代码了。

4.不需要每次重启模拟器,直接再跑程序,ADT会自动用当前的模拟器启动程序。否则重启模拟器本机需要60s以上




posted @ 2010-01-12 17:49 oathleo 阅读(241) | 评论 (0)编辑 收藏

     摘要: TWaver3.3 WMS结合GoogleMap  阅读全文

posted @ 2009-12-25 16:34 oathleo 阅读(1801) | 评论 (1)编辑 收藏

     摘要: TWaver3.3 Blink Link Flowing Demo

1.节点告警闪烁,附件的闪烁 增加了IE下 独立的闪烁周期
2.Link连线的流动效果 也增加了IE下 独立的流动周期  阅读全文

posted @ 2009-11-30 16:05 oathleo 阅读(1465) | 评论 (2)编辑 收藏

     摘要:   阅读全文

posted @ 2009-11-18 16:15 oathleo 阅读(735) | 评论 (0)编辑 收藏

     摘要: http://web.servasoft.com/svgdemo/

主要更新部分
1.增强Chart输出功能
2.增强Grid编辑功能
3.增强GisMap工具栏  阅读全文

posted @ 2009-11-05 16:26 oathleo 阅读(1363) | 评论 (0)编辑 收藏

     摘要: TWaverSVG 结合 GoogleMap  阅读全文

posted @ 2009-10-30 14:45 oathleo 阅读(1792) | 评论 (3)编辑 收藏

     摘要: TWaver Network on IPHONE   阅读全文

posted @ 2009-10-20 12:25 oathleo 阅读(1330) | 评论 (4)编辑 收藏

     摘要: TWaver3.2 Released!  阅读全文

posted @ 2009-09-11 16:28 oathleo 阅读(1202) | 评论 (0)编辑 收藏

     摘要: TWaver3.1 Web SVG USA Map Demo  阅读全文

posted @ 2009-09-08 14:18 oathleo 阅读(1525) | 评论 (3)编辑 收藏

     摘要:   阅读全文

posted @ 2009-07-21 17:00 oathleo 阅读(1091) | 评论 (0)编辑 收藏

     摘要: 下载TWaver 3,赢取TWaver纪念版T恤!  阅读全文

posted @ 2009-07-09 10:22 oathleo 阅读(698) | 评论 (0)编辑 收藏

override: function(origclass, overrides){
            if (overrides) {
                var p = origclass.prototype;
                for (var method in overrides) {
                //IE下无法遍历到
               //"toString", "toLocaleString", "valueOf",
               //"hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable"这几个方法


                    p[method] = overrides[method];
                }
                if (TWaver.isIE) {  //IE 问题,目前只有'toString'用到,先处理
                    if (p['toString'] != overrides['toString']) {
                        p['toString'] = overrides['toString'];
                    }
                }
            }
        }

posted @ 2009-07-06 13:50 oathleo 阅读(1432) | 评论 (0)编辑 收藏

判断变量类型:一般情况下,可以先用typeof 运算符,如果结果是"object",再用instanceof来判断;
 特别的地方是:
    instanceof不认为原始类型值的变量是对象,

   1var temp="a string for test";   
   
2//下面这句返回"string"   
   3. alert( typeof temp);   
   
4//下面这句返回"false"   
   5. alert(temp instanceof String);   
   
6.   
   
7//看看Ext内部实现,判断String类型 
   8. if(  typeof temp== "string"){
   9. }

其他附加问题:
  • null:表示尚未存在的对象,注意,尽管尚未存在,也是个对象啊,所以用typeof检测一个null值变量的结果是Object;不过,为了便于写if语句,在js中,"undefined==false", "null=false", 因此,"undefined==null"。
  • 整数:最容易犯的错误就是,忘了070其实是个八进制数,相当于十进制的56;
  • 浮点数:“在进行运算之前,真正存储的是字符串”——这应该是解释执行的本质决定的吧——直接后果是,alert(0.8)这样的语句可以正确输出,而alert(2*0.8)的输出就成了"2.40000000000000003"
  • 数字边界: 数字有几个边界值,分别是Number.MAX_VALUE(最大值), Number.MIN_VALUE(最小值), Number.POSITIVE_INFINITY(正无穷), Number.NEGATIVE_INFINITY(负无穷), Infinity(无穷大,-Infinity,这个有点莫名其妙,不知道为啥又搞出一套);特别地,还有一个isFinit(iNumber)函数来判 断数字是否为无穷大。
  • NaN:一些需要数字作为参数的函数,当传入的实参无法转换为数字时,往往会返回这个值;关于NaN,最重要的就是要记住NaN!=NaN,因此判断一个变量是否为NaN,一定要使用isNaN(var)函数。
  • 将字符串转换为数字:sVar.parseInt() 是最常用的函数,也最容易出错,为了保险起见,最好每次调用的时候,都加上“进制”的参数,比如:a.parseInt(10),就制定了按十进制转换字 符串a;Number(sVar)也是一种转换方式,不同的是,它要求整个字符串都得是有效数字,因此Number("4.5.5")将返回NaN;

posted @ 2009-06-29 18:11 oathleo 阅读(5553) | 评论 (3)编辑 收藏

js 里 Object本身可以做为Map。
条件是Key只能是String

如果要用对象做为Key,这个Map可以来实现。
效率上由于_getIndex方法每次都要遍历,耗时很长,所以通常在1:10左右

总结以上,如果Map的Key是String,最好还是用Object来实现。
而且用in来遍历Map,效率上不是网上说的那么差,和for()差不多

TWaver.Map = function(){
    this._entrys = null;
    this.initialize.apply(this, arguments);
}

TWaver.Map.prototype = {
    initialize: function(){
        this._entrys = new Array();
    },
    put: function(key, value){
        if (key == null || key == undefined) {
            return;
        }
        var index = this._getIndex(key);
        if (index == -1) {
            var entry = new Object();
            entry.key = key;
            entry.value = value;
            this._entrys[this._entrys.length] = entry;
        }else{
            this._entrys[index].value = value;
        }       
    },
    get: function(key){
        var index = this._getIndex(key);
        return (index != -1) ? this._entrys[index].value : null;
    },
    remove: function(key){
        var index = this._getIndex(key);
        if (index != -1) {
            this._entrys.splice(index, 1);
        }
    },
    clear: function(){
        this._entrys.length = 0;;
    },
    contains: function(key){
        var index = this._getIndex(key);
        return (index != -1) ? true : false;
    },
    getCount: function(){
        return this._entrys.length;
    },
    getEntrys: function(){
        return this._entrys;
    },
    _getIndex: function(key){
        if (key == null || key == undefined) {
            return -1;
        }
        var _length = this._entrys.length;
        for (var i = 0; i < _length; i++) {
            var entry = this._entrys[i];
            if (entry == null || entry == undefined) {
                continue;
            }
            if (entry.key === key) {//equal
                return i;
            }
        }
        return -1;
    }
}


posted @ 2009-06-18 16:12 oathleo 阅读(7918) | 评论 (3)编辑 收藏

在ie6.0中快速排序算法比Array对象的sort方法快多了,对于元素比较少的,快速排序的速度基本上是sort方法的5倍左右,对于30000个元素快速排序是sort方法速度的十几倍
在ff2.0中两种排序算法速度基本上差不多,快速排序算法稍微快一点

<script>
function rand(m,n){
      //生成一个m、n之间的整数
        var i=Math.random();
        return Math.round((n-m)*i+m);
 }
            
            
function getRandomArr(m,n,l){
  //m:生成随即整数的最小值,n:生成随即整数的最大值,l:生成的数组的长度
    var resultArr=[];
    for(var i=0;i<l;i++){
        resultArr.push(rand(m,n))
    }
    return resultArr;
}
     
function partition(a,st,en)  
{  
    var s=st;  
    var e=en+1;  
    var temp=a[s];  
    while(1)  
    {  
        while(a[++s]<temp);  
        while(a[--e]>temp);  
        if(s>e)break;  
        var tem=a[s];  
        a[s]=a[e];  
        a[e]=tem;  
    }  
    a[st]=a[e];  
    a[e]=temp;  
    return e;  
}  

function doSort(a,s,e)  
{  
    if(s<e)  
    {  
        var pos=partition(a,s,e);  
        doSort(a,s,pos-1);  
        doSort(a,pos+1,e);  
    }  
}  
     
Array.prototype.quickSort = function()  
{  
      doSort(this,0,this.length-1);  
}


function sortIntF(a,b){return a-b}
function pk(num){
    //num: 用于排序的数组的元素个数
    //生成用于排序的数组
    var arr=getRandomArr(1,999999,num);
     
    //当元素个数小于10000时,执行n次取平均值  
    var n=Math.ceil(10000/num);
     
    //生成多个用于排序的数组的拷贝
    var quickSortArrs=[];
    var sortArrs=[];
    for(var i=0;i<n;i++){
        quickSortArrs.push(arr.slice(0));
        sortArrs.push(arr.slice(0));
    }
     
    var t1=new Date();
     
    for(var i=0;i<n;i++){
        quickSortArrs[i].quickSort();
    }
     
    var t2=new Date();
     
    for(var i=0;i<n;i++){
        sortArrs[i].sort(sortIntF);
    }
     
    var t3=new Date();
     
    alert("性能比较,对于"+num+"个元素的数组,平均每次排序花费时间如下:\n"
    +"Array.prototype.sort:"+((t3-t2)/n)+"ms\n"
    +"quickSort:"+((t2-t1)/n)+"ms\n"
    );
     
    alert("排序结果是否正确:"+(sortArrs[0].join()==quickSortArrs[0].join()));
}

pk(500);
pk(2000);
pk(30000);
</script>

posted @ 2009-06-17 12:10 oathleo 阅读(1296) | 评论 (0)编辑 收藏

今天折腾了大半天Flash与Flex3的配合,特总结一下心得体会:
1) 如果是通过Embed来嵌入swf的话,Flex3只支持FlashCS2所创建的swf.
2) 如果是通过loader来加载的话,只有AS3的swf才能在加载后被控制(这和第一点相反,我花了很长时间才弄明发现这两点,汗!)
3) 如果要直接加载到Flex当中,类必须继承UIComponent,这好比在Flash中必须继承DisplayObject
4) 如果要把Flash的组建打包给Flex使用,应该使用FlexComponentKit,把MC导出成swc。然后在Flex中把swc配置到 Library Path后,对应的组建就可以作为一等公明在Flex中使用了。如果MC是绑定了类的,那么对应类继承UIComponent就可以了。

 

在googleDocs下了一个corelib包,不是蛮实用的(前段时间还自己写trim,浪费时间啊),E文看得累,以备以后查看
//图相用法
import com.adobe.images.JPGEncoder;
public function submit():void {
var encoder:JPGEncoder = new JPGEncoder(80);
var bytes:ByteArray = encoder.encode(getBitmapData());
var request:URLRequest = new URLRequest(UPLOAD_PAGE);
//data值就为图片编码数据ByteArray;
request.data = bytes;
request.method = URLRequestMethod.POST;
//这个是关键,内容类型必须是下面文件流形式;
request.contentType = “application/octet-stream”;
var loader:URLLoader = new URLLoader();
loader.load(request);
}
//加密用法
import com.adobe.crypto.SHA1;
trace(SHA1.hash(”132″));

//utils包比较繁锁,全都是静态方法
import com.adobe.utils.ArrayUtil;
ArrayUtil.arrayContainsValue(arr, value);//arr是否包含value
ArrayUtil.arraysAreEqual(arr1, arr2);//arr1,arr2是否相等
ArrayUtil.copyArray(a);//深拷贝
ArrayUtil.removeValueFromArray(arr, value);//删除值value

import com.adobe.utils.StringUtil;
StringUtil.beginsWith(str1, str2);//str1是否以str2开头
StringUtil.endsWith(str1, str2);//str1是否以str2结束
StringUtil.ltrim(str);//去左空格
StringUtil.rtrim();
StringUtil.trim();
StringUtil.remove(str1, str2);//从str1删除str2
StringUtil.replace(input, replace, replaceWith);//把input中的replace置换为replaceWith
StringUtil.stringsAreEqual(s1, s2, caseSensitive);//s1,s2是否相等,caseSensitive是否大小写敏感

import com.adobe.utils.DateUtil;
DateUtil.compareDates(d1, d2);//比较,d1>d2返回-1,=返回0,<返回1
DateUtil.getAMPM(d);//返回AM or PM
….功能比较全, 太多了, 还有几个不知道

import com.adobe.utils.NumberFormatter;
NumberFormatter.addLeadingZero(5);//返回补0的数,如1变成01

import com.adobe.utils.IntUtil;
IntUtil.toHex(n,bigEndian);//16进制,bigEndian指定是后补0,还是前补0
IntUtil.rol(n, m);//n右移m位(位运算)
IntUtil.ror(n, m);//左移

import com.adobe.utils.DictionaryUtil;
DictionaryUtil.getKeys(d);//得到键名
DictionaryUtil.getValues(d);//得到值

import com.adobe.utils.XMLUtil;
这个还不会用,以后慢慢摸,本来AS3的XML就很完善了

corelib包下载地址


Flash跨域调用问题
由于安全沙箱的限制, 处于不同域下的文件(swf, xml等)在默认状态下是不能相互调用的. 比如A域名下的flash不能访问B域名下的XML. 除非B域名在根目录下的”crossdomain.xml”文档中包含A域名. 但存在以下问题:

1) 不允许改动根目录
解决方法: 在AS3允许crossdomain.xml不在根目录中,这时就要用 Security.loadPolicyFile(”http://www.example.com/sub/dir/pf.xml”);这样的方法来指 定. 当然只有crossdomain.xml所在目录是可以访问的.

2) 不允许添加crossdomain.xml
解决方法: 如果要被读取的是swf文件, 只要在主函数中加入flash.system.Security.allDomain(”A”)即可. 但如果是其他各式的文件, 比如xml文档的话怎么办呢? 可以把xml读取到B上的b.swf(b上加入flash.system.Security.allDomain(”A”)). 然后在A的a.swf中加载b.swf,然后读取b.swf中的xml. 类似于:
_mc =event.target.content as Sprite;
trace(_mc["var"]);



Loader与URLLoader的比较
AS3已经中Loader与URLLoader是两个比较容易混淆的类,特此区分:
应用范围
Loader: swf,图片(jpg,png,gif)
URLLoader:文本文件(xml,php,jsp…)

使用方法
Loader:
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete);
private function loadComplete(event:Event)
{ trace("done");addChild(loader);}

URLLoader:
xmlLoader.dataFormat=URLLoaderDataFormat.TEXT;
xmlLoader.addEventListener(Event.COMPLETE,xmlLoaded);
private function xmlLoaded(event:Event)
{
try {myXML = XML(event.target.data);area.text=myXML;}
catch (e:TypeError) {area.text="Load faild:\n"+e.message;}
}

 


AS3-点阵化文字


上面是这两天做的一个小东西,它能够把输入的文字用点阵来描述,并存这些信息存入一个数组当中。然后用这个数组来重新生成“文字”,这些“文字”可以由任意的Sprite组成,并且可以随意加上动画。

承蒙大家厚爱,把源文件放在这里供大家下载。为了便于将来扩展,我使用的是Observer设计模式,希望不会把大家搞混淆。
源文件下载



Javascript与Flash互动
在SwfObject解决Html与Flash 之间传递参数问题中已经简要介绍了如何使用SwfObject在页面中插入Flash,如何在初始时由JS向Flash传递参数,以及运行时Flash如 何调用JavaScript中函数。这里主要介绍运行时JavaScript如何互相传递参数, 并控制Flash的播放。

源文件下载

其实JS能直接控制Flash的播放,主要通过下列方法实现:
Play() —————————————- 播放动画
StopPlay()————————————停止动画
IsPlaying()———————————– 动画是否正在播放
GotoFrame(frame_number)—————- 跳转到某帧
TotalFrames()——————————- 获取动画总帧数
CurrentFrame()——————————回传当前动画所在帧数-1
Rewind()————————————-使动画返回第一帧
SetZoomRect(left,top,right,buttom)——-放大指定区域
Zoom(percent)——————————改变动画大小
Pan(x_position,y_position,unit)————使动画在x,y方向上平移
PercentLoaded()—————————-返回动画被载入的百分比
LoadMovie(level_number,path)———– 加载动画
TGotoFrame(movie_clip,frame_number)- movie_clip跳转到指定帧数
TGotoLabel(movie_clip,label_name)—— movie_clip跳转到指定标签
TCurrentFrame(movie_clip)————— 回传movie_clip当前帧-1
TCurrentLabel(movie_clip)—————–回传movie_clip当前标签
TPlay(movie_clip)—————————播放movie_clip
TStopPlay(movie_clip)———————-停止movie_clip的播放
GetVariable(variable_name)—————–获取变量
SetVariable(variable_name,value)———–变量赋值
TCallFrame(movie_clip,frame_number)—call指定帧上的action
TCallLabel(movie_clip,label)—————-call指定标签上的action
TGetProperty(movie_clip,property)——–获取movie_clip的指定属性
TSetProperty(movie_clip,property,number)-设置movie_clip的指定属性

Read the rest of this entry »


Flash中组件(Component)的创建和使用
这里简要介绍Flash中自定义组建的创建和使用方法.由于工作的原因,我用的是AS2, AS3的应该类似。
组建的创建
1 创建一个类文件,比如ClassLoader。这个文件实现组件的主要功能。它可以调用其它类,比如cn.adamstudio.effects.TextAnimation(这个类自己写,可以是简单的一个trace),这些类将会自动打包到组件中。

//ClassLoader类:
[IconFile("spidercore.png")];
class ClassLoader extends MovieClip
{
public function setSize()
{
_width=18;
_height=18;
}

public function doNothing():Void
{
// Trick the compiler into including
// the TextAnimation class in the component.
cn.adamstudio.effects.TextAnimation;
}
}

2 创建一个Fla文件,如SWC_Generator。在其中新建一个MovieClip,如swc, 设置如下图:


3 在库中这个MC上右键,在右键菜单里选择”Component Definition…”.设置如下图:


4 此时在库面板中可以看出,MC已经转换成了一个元件.因为元件处在编辑状态.所以直接导入一个png图标到舞台上,如icon.png.这个图标是新建组建的图形标志,将来在库面板和舞台上将会看到它的身影.

5 在库中这个MC上右键,在右键菜单里选择”Export SWC File …”,保存SWC文件.

组建的使用
1 将生成的SWC文件拷入:
C:\Documents and Settings\User \Local Settings\ Application Data \Adobe \Flash CS3 \en \Configuration\Components\swc

2 新建一个Flash文件,如test.fla.在Flash中重新打开Component面板后,会发现swc目录下有我们拷入的SWC文件.将其拖入舞台后,在舞台上删除之.(只需要它在库中).

3 在第一帧上加入代码:
import cn.adamstudio.effects.TextAnimation;
var textAni=new TextAnimation;

即使本地电脑中没有cn.adamstudio.effects.TextAnimation,程序照样能运行,因为它这个类已经包含在了SWC文件当中.

注:SWC_Generator.fla和test.fla的输出设置都应该选择AS2,否则无法得到正确结果;

源文件下载:源文件


AS2 - 创建MovieClip的子类
在Flash中作视觉表现时,常常需要创建MovieClip的子类。下面是一个不错的框架:

Avatar子类:
class cn.adamstudio.Avatar extends MovieClip
{
//定义静态变量,用于初始化
public static var HAPPY:Number = 0;
public static var SAD:Number = 1;
public static var IDLE:Number = 2;

//定义静态方法,用于简洁地创建自己的instance
public static function createAvatar(name:String, target:MovieClip, depth:Number, x:Number, y:Number):Avatar
{
var av:Avatar = Avatar(target.attachMovie(”AvatarSymbol”, name, depth));
av.init(x,y);
return av;
}

//设置instance的坐标
public function init(x:Number, y:Number):Void
{
setState(Avatar.HAPPY);
this._x = x;
this._y = y;
}

//初始化instance
public function setState(newState:Number):Void
{
switch (newState) {
case Avatar.HAPPY :
this.gotoAndStop(”HAPPY”);
break;

case Avatar.SAD :
this.gotoAndStop(”SAD”);
break;

case Avatar.IDLE :
this.gotoAndStop(”IDLE”);
break;
}
}
}
注:其中的静态变量和静态函数是可选的,可以根据需求的不同而有所变化。

主文档中:
import cn.adamstudio.Avatar;
var av:Avatar=Avatar.createAvatar("avatar",_root,0,200,200);

这种方法的特点和优点是用使用子类的静态方法来实例化MovieClip的子类,在主文档中非常简洁。
源文件下载

AS-可正可负随机数的算法
我以前的写法都是:
Math.random()*2-1
今天看到一个比较有意思的写法:
Math.random()-Math.random()


AS3鼠标坐标总结
鼠标是Flash里追主要的互动因素,经常需要侦测鼠标事件(AS3中鼠标事件小结)和得到鼠标的坐标。鼠标坐标的获取可以分为在文档类和在子类中,两种不同的情况。

1)如果是在时间线轴上,或者文档类上使用:
stage.mouseX 和 stage.mouseY

2)在子类(如_sprite:Sprite)上使用:
_sprite.mouseX 和 _sprite.mouseY
这里得到的是鼠标相对于_sprite的坐标。如果需要的是相对于舞台的坐标,则应该使用localToGlobal,如:
var mousePoint:Point=new Point(_sprite.mouseX, _sprite.mouseY);
mousePoint=_sprite.localToGlobal(mousePoint);
trace("Stage coordinates:"+mousePoint);

注:要使用以上代码别忘了 import flash.geom.Point;


AS3练习-往返运动


这是今天做的一个AS3的运动练习,主要是加速和减速运动的配合。发现粒子多了就会出现一些奇怪的现象,比如偶尔会几个粒子在原位置闪动。可能更Flash的代码执行顺序有关,暂时还搞不懂。

as3运行时错误中文说明
1000 系统内存不足。 系统可用内存无法满足 Flash Player 编译代码的需要。请关闭系统上正在运行的某些应用程序或进程。
1001 未实现方法 _。
1002 Number.toPrecision 的范围是 1 至 21。Number.toFixed 和 Number.toExponential 的范围是 0 至 20。指定的值不在期望范围之内。 指定的值不在 precision 参数的期望范围之内。Number.toPrecision 的范围是 1 至 21。Number.toFixed 和 Number.toExponential 的范围是 0 至 20。
1003 radix 参数必须介于 2 至 36 之间;得到 _。 为方法或属性的 radix 参数传递的值小于 2 或大于 36。请传递一个介于 2 至 36 之间的值作为 radix 参数。
1004 对不兼容的对象调用方法 _。 尝试调用的方法不适用于指定对象。如果已将原型函数从一个对象复制到另一个对象然后又调用此函数,但目标对象类型与原始对象类型不同,则会发生此错 误。请确保目标对象与原始对象的类型相同。有关详细信息,请参阅 ECMAScript Language Specification(《ECMAScript 语言规范》)第 3 版中的第 15 章。
1005 数组索引不是正整数 (_)。 尝试使用非正整数的索引值访问数组成员。仅传递正整数作为数组的索引值。
1006 _ 不是函数。 尝试调用不存在的函数时,发生此错误。请确保正在调用正确的函数且自 ActionScript 2.0 以来此 API 尚未发生更改。此外,请确保正在使用正确的对象。例如,使用以下代码时,将出现此错误(由于最后一行错误调用了变量 big 而未调用变量 blg):
var blg:String = “foo”;
var big:Sprite = new Sprite();
var error:int = big.length();
1007 尝试对非构造函数进行实例化。
1008 _ 指代不明确;发现多个匹配的绑定。
1009 无法访问空对象引用的属性或方法。 计算结果为 null 的对象可以不包含任何属性。在某些意外(尽管有效)的情况下,可能发生此错误。以创建 Sprite 对象的以下代码为例。由于从未将此 Sprite 对象添加到显示列表中(使用 DisplayObjectContainer 对象的 addChild() 方法),因此其 stage 属性设置为 null。在这种情况下,此示例将生成此错误,这是因为 Sprite 对象的 stage 属性不能拥有任何属性: Read the rest of this entry »


AIR-最新RSSReader(基于Flash)
经过长时间的努力,终于用Flash CS3+AS3+AIR Beta2做出了RSSReader 2.0。
前一段时间用html+JS做了个WordpressReader, 虽然实现了自动升级,等很cool的功能,但界面还是比较简朴。
AIR读取Blog RSS - Adobe AIR Beta2 实践
WordpressReader 1.1 完成

这次做的RSSReader是基于ActionScript3的,界面漂亮了很多,而且用户体验也有了显著的提高。
程序下载:http://www.adamstudio.cn/blog/download/RSSReader.air
初始介面:

文章阅读界面:

实现的功能:
1 读取服务器端XML文档;
2 将读取的XML文档储存到AIR的内建本地数据库SQLite !!!(太酷了!)
3 判断网络连接状况,如果网络畅通就读取并以动画的形式展示文章标题,同时用最新文章刷新SQLite中已有文章。如果网络不通,则读取并显示SQLite中储存的文章;
4 以动画形式展示动画文章标题;
5 自定义事件和文章标题与文章内容之间的切换。

多说也无用,试用一下你就知道Adobe AIR有多强了!
程序下载:http://www.adamstudio.cn/blog/download/RSSReader.air


Flash-navigateToURL取代getURL
AS3中使用 navigateToURL取代了getURL,个人感觉navigateToURL最大的好处就是方便了传递参数,不足的地方嘛,据说弹出的新窗口会被 浏览器拦截。需要使用:ExternalInterface.call(”window.open”,winurl,”");来避免,但是这是采用了调用 JS来做,是必须在浏览器支撑并且JS可以使用的情况下(没有测试)。
另外发现在Adobe AIR中使用navigateToURL打开连接时,只能在新窗口中打开(不会被浏览器拦截),”_self”,”_parent”,”_top”都没有用.而且都是调用浏览器,而不是在AIR中打开.

具体用法如下:

package {
import flash.display.Sprite;
import flash.net.navigateToURL;
import flash.net.URLRequest;
import flash.net.URLVariables;

public class NavigateToURLExample extends Sprite {

public function NavigateToURLExample() {
var url:String = “http://www.adobe.com”;
var variables:URLVariables = new URLVariables();
variables.exampleSessionId = new Date().getTime();
variables.exampleUserLabel = “Your Name”;
var request:URLRequest = new URLRequest(url);
request.data = variables;
try {
navigateToURL(request);
}
catch (e:Error) {
// handle error here
}
}
}
}


Flash-如何改变动态文本透明度?
因为Flash的系统字体不直接支持透明,所以我们得通过嵌入字体或者Filter类来解决。简单地通过改变动态文本的alpha或者它做在的mc的alpha都是没有用的。

1 嵌入字体
这种方法最简单,选中动态文本框,然后在属性面板中点嵌入(“Embed”)按钮,按后选择要全部字库嵌入,还是只嵌入部分字符。但代价是文件会变大,尤其在嵌入中文字体的时候,绝对是噩梦。当然只是嵌入下载进度0-9这样简单的几个字符,还是非常方便的。

2 Filter
这是从Blueidea学来的,就是给动态文本增加一个滤镜,即使是空滤镜也可以。
AS3中代码
//建立动态文本
var my_txt:TextField=new TextField();
my_txt.autoSize = TextFieldAutoSize.LEFT;
my_txt.background = true;
my_txt.border = true;
my_txt.text = “Hello world and welcome to the show.”;
//定义滤镜
var txt_blur:BlurFilter = new BlurFilter(0, 0, 0);
my_txt.filters = [txt_blur];
my_txt.alpha = 0.5;
//加入动态文本
my_txt.x=my_txt.y=50;
addChild(my_txt);
AS2中代码
import flash.filters.BlurFilter;
var txt_blur:BlurFilter = new BlurFilter(0, 0, 0);
this.createTextField(”my_txt”, 1, 100, 100, 300, 100);
my_txt.text = “DDGGDGDGDGDG”;
my_txt.filters = [txt_blur];
my_txt._alpha = 50;

3 BitmapData 和 ColorMatrixFilter
据HbrO说BitmapData和ColorMatrixFilter也能实现动态文本的半透明效果。但我这人比较懒,发现一种方法之后就犯懒了。以后有时间再研究吧 ,哈哈。


AS3中鼠标事件小结
鼠标事件(MouseEvent)和鼠标位置(AS3鼠标坐标总结)是 RIA中最重要的人机交互途径。最近在做一个动态产品展示的系统ProdutShow的时候才发现自己对鼠标事件的了解有多么肤浅。现在 ProductShow已经做完了,这里把在使用鼠标事件时要注意的问题总结一下:
1 鼠标事件分为MOUSE_OVER, MOUSE_MOVE, MOUSE_DOWN, MOUSE_UP, MOUSE_OUT, MOUSE_WHEEL和MOUSE_LEAVE。其中前六个事件都来自flash.events.MouseEvent类,最后一个 MOUSE_LEAVE却是来自flash.events.Event,在导入类包的时候一定要注意这个问题,因为我在这点上就花了很长时间调试,才得发 现问题所在。
MOUSE_OVER - 鼠标移动到目标对象之上时触发, 可以用于模拟按钮的mouse over效果;
MOUSE_MOVE - 鼠标在目标对象之上移动时触发,主要用于判断。比如判断在拖拽实例时,实例是否在允许的范围之内,如果超出,立刻停止拖拽或者重新设定实例的坐标;
MOUSE_DOWN - 鼠标在目标对象之上按下时触发。注意,只有按下鼠标左键时才会触发,右键和滚轮都不会触发。在目标对象之外按下鼠标左键,再移动到目标对象之上时,也不会触发;
MOUSE_UP - 鼠标在目标对象之上松开时触发。注意,只有松开鼠标左键时才会触发,右键和滚轮都不会触发。在目标对象之上按下鼠标左键,再移动到目标对象之外松开时,不会触发。但在目标对象之外按下鼠标左键,再移动到目标对象之上松开时,就会触发。
MOUSE_OUT- 鼠标移动到目标对象之外时触发。
MOUSE_WHEEL - 鼠标在目标对象之上转动滚轮时触发。
MOUSE_LEAVE - 当光标离开舞台时触发(stage.addEventListener(Event.MOUSE_LEAVE,leaveHandler);)。在使用自 定鼠标后,在鼠标离开舞台时,触发MOUSE_LEAVE事件,然后可以把自定义的鼠标隐藏掉,避免还停留在舞台上。

2 mouseChildren。目标对象中含有子实例时,感应鼠标行为的是子时列,而非目标对象。如果使用 cursor.mouseEnabled=false; 就可以由目标对象来更应鼠标行为。

3 mouseEnabled。当实例重叠时,出于显示列表上方的实例总比下方实例更有优先权感应鼠标行为。当想让下方实例感应鼠标行为时使用 cursor.mouseEnabled=false; 即可。这常用于自定义鼠标后,去除自定义鼠标对鼠标行为的干涉,因为自定义鼠标往往一直处于鼠标下方,其他实例无法再感应到鼠标的变化。

另外,也许DOUBLE_CLICK也应该算做鼠标事件,但要使用它,必须先让doubleClickEnabled=true:
var bg:Sprite=new Sprite();
bg.doubleClickEnabled=true;
bg.addEventListener(MouseEvent.DOUBLE_CLICK,clickHandler);


typeof、is、as的区别
typeof、is、as都是用于判断变量类型的,只是各自的返回值不同。请看下方代码:
var a:Number=0;
trace(typeof(a));//输出:Number
trace(typeof(typeof(a)));//输出:String
trace(a is Number);//输出:true
trace(a as Number);//输出:0
trace(a as String);//输出:null



Null、NaN和undefined的区别
其实Null、NaN和undefined都是变量的默认初始值。变量类型不同,系统给与的初始值就不同:
int,uint - 0
Boolean - false
Number - NaN
String,Array,Object - null
未指定变量类型 - undefined



SwfObject解决Html与Flash之间传递参数问题
在彻底摒弃Adobe的 激活ActiveX控件的方法一文中已经详细分析了使用Adobe提供的AC_RunActiveContent.js导致HTML与Flash之间不能 传递参数的问题。经过Adobe论坛里GWD的提示,我转而寻求SwfObject的帮助。发现SwfObject是一个很好的解决方案。

SwfObject英文介绍:http://blog.deconcept.com/swfobject/
SwfObject中文翻译:http://www.awflasher.com/flash/articles/swfobj.htm
源文件:SWFObject 1.5

关于SwfObject的介绍上面两篇文章已经讲的很详细了。我这里只列一段标准的应用和一些上面两篇文章没有提到的问题.

Html中的JS代码
<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript">
// <![CDATA[
var so = new SWFObject("asCallJs.swf", "MyDemo", "500", "400", "9", "#FF6600");
so.addVariable("param1", "Parameter1"); // this line is optional, but this example uses the variable and displays this text inside the flash movie
so.addVariable("param2", "Parameter2");
so.useExpressInstall('expressinstall.swf');
so.write("flashcontent");
// ]]>
</script><!--被AS调用的JS函数-->
<script language="Javascript">
// <![CDATA[
// adds two numbers, and sends the result back to ActionScript
function addNumbers(num1, num2)
{
result=num1 + num2;
alert("3+7=" + result);
return (result);
}
// ]]>
</script> Read the rest of this entry »


彻底摒弃Adobe的激活ActiveX控件的方法
大家知道,在IE中只有激活了 ActiveX控件,Flash才能够与浏览者交互,否则得手动点一下激活。Flash也提供了一个很“方便”的解决方案,就是在发布swf文件的同时, 发布html文件即可。这样Flash会在生成一个swf文件,一个包含swf的Html文件,和一个“AC_RunActiveContent.js” 文件。Html文件通过调用AC_RunActiveContent.js,实现激活ActiveX控件。这一切都很便捷,直到你希望在html和 Flash之间传递参数。
问题出现
在很多商业网站中,都涉及到用同一个Flash来显示大量不同的内容(图片,视频或产品信息等),这就需要向这个Flash传递参数。常见的传参方法有三种,但都会受到AC_RunActiveContent.js的不良影响。
1 ExternalInterface: 这是困扰我最久的一个问题。据Adobe的描述,这是最好的传参方法,能都非常自由和直接地在AS和JS之间互相传递参数或者互相调用函数。但我在使用 Adobe的示例文件时发现,在IE中AS无法得到JS的返回值(ExternalInterface在IE中的Bug),经过不断的尝试才发现是 AC_RunActiveContent.js在捣鬼,只要把它和html中对应代码以 及<noscript></noscript>删除就一切正常了。
请看示例:
Player8,AS2: http://www.adamstudio.cn/lab/var/test/test_v8.html
Player9,AS3: http://www.adamstudio.cn/lab/var/test/test_v9.html
如果带有激活ActiveX控件的那段JS代码,IE中就无法得到返回值,请看:
http://www.adamstudio.cn/lab/var/test/test_error.html
所有源文件:http://www.adamstudio.cn/lab/var/test/test.rar
2 FlashVars:
3 URL传递参数
后 两种方法受AC_RunActiveContent.js的影响更大,因为这两种方法都是 在<noscript></noscript>之间加入代码,而在JS能运行的浏览器当中(绝大多数浏览器都能运行JS),这些 代码根本就不会运行。所以无论在Firefox或者IE中都不起任何作用!
也就是说常用的三种在Html与AS之间传递参数的方法均受到激活ActiveX控件的那段代码的影响。所以要想在html和Flash之间传递参数,就必须摒弃Flash自带的激活ActiveX控件的方案!

替代方案:SwfObject 请参考SwfObject解决Html与Flash之间传递参数问题

posted @ 2009-06-10 17:03 oathleo 阅读(732) | 评论 (0)编辑 收藏

     摘要: TWaver3.0 SVG WebRadar Chart   阅读全文

posted @ 2009-06-04 16:40 oathleo 阅读(1178) | 评论 (1)编辑 收藏

     摘要: TWaver3.0 SVG WebGIS  阅读全文

posted @ 2009-05-19 10:54 oathleo 阅读(1197) | 评论 (0)编辑 收藏

     摘要: 电信拓扑Web解决方案  阅读全文

posted @ 2009-04-13 10:33 oathleo 阅读(1872) | 评论 (7)编辑 收藏

     摘要: 电信拓扑Web解决方案  阅读全文

posted @ 2008-12-17 11:15 oathleo 阅读(2018) | 评论 (15)编辑 收藏

     摘要: 电信拓扑解决方案  阅读全文

posted @ 2008-09-23 18:50 oathleo 阅读(1506) | 评论 (3)编辑 收藏

买房,钱到用时方恨少.
恨什么呢?自己怎么还是这么穷?
不够努力,走错了路,还是?
是不是做技术就只能这样了?
太多的疑问,没有答案,只能往前走.

posted @ 2008-08-06 15:59 oathleo 阅读(931) | 评论 (2)编辑 收藏

     摘要:   阅读全文

posted @ 2008-07-07 10:40 oathleo 阅读(374) | 评论 (0)编辑 收藏

     摘要:   阅读全文

posted @ 2008-07-01 15:18 oathleo 阅读(477) | 评论 (0)编辑 收藏

     摘要:   阅读全文

posted @ 2008-06-30 18:21 oathleo 阅读(342) | 评论 (0)编辑 收藏

     摘要: JS调用applet方法访问文件  阅读全文

posted @ 2008-06-30 17:55 oathleo 阅读(3702) | 评论 (2)编辑 收藏

     摘要:   阅读全文

posted @ 2008-06-21 11:40 oathleo| 编辑 收藏

     摘要: 电信拓扑解决方案  阅读全文

posted @ 2008-06-21 10:56 oathleo 阅读(1571) | 评论 (5)编辑 收藏

     摘要:   阅读全文

posted @ 2008-06-17 14:23 oathleo 阅读(1315) | 评论 (2)编辑 收藏