[转载]Google Local Search API 简介

mikel阅读(1286)

[转载]Google Local Search API 简介 – liongis – 博客园.

Google 提供了一个基于JavaScript的本地搜索的API,我们可以通过这个API来嵌入到我们的应用程序中,实现搜索的功能。如javascrtip,Flash,java等。

此接口返回的数据为JSON格式的数据,可以方便进行解析。

Google Local Search API首页地址是:

http://code.google.com/intl/zh-CN/apis/maps/documentation/localsearch/index.html

以下是一个简单的例子:

1 <DOCTYPE html> 2  <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta http-equiv="content-type" content="text/html; charset=utf-8"/> 5 <title>Google Search API Sample</title> 6 <script src="http://www.google.com/jsapi?key=INSERT-YOUR-KEY"></script> 7 <script type="text/javascript"> 8 // This code generates a "Raw Searcher" to handle search queries. The Raw Searcher requires 9   // you to handle and draw the search results manually. 10   google.load('search', '1'); 11 12 var localSearch; 13 function searchComplete() { 14 15 // Check that we got results 16 document.getElementById('content').innerHTML = ''; 17 if (localSearch.results && localSearch.results.length > 0) { 18 for (var i = 0; i < localSearch.results.length; i++) { 19 20 // Create HTML elements for search results 21 var p = document.createElement('p'); 22 var a = document.createElement('a'); 23 var b = document.createElement('b'); 24 var c = document.createElement('c'); 25 a.href = localSearch.results[i].url; 26 a.innerHTML = localSearch.results[i].title; 27 b.innerHTML = "<br>" + 28 localSearch.results[i].streetAddress; 29 c.innerHTML = "<br>" + 30 localSearch.results[i].city + "," + 31 localSearch.results[i].region; 32 33 // Append search results to the HTML nodes 34 p.appendChild(a); 35 p.appendChild(b); 36 p.appendChild(c); 37 document.body.appendChild(p); 38 } 39 } 40 } 41 42 function onLoad() { 43 44 // Create a LocalSearch instance. 45 localSearch = new google.search.LocalSearch(); 46 47 // Set the Local Search center point 48 localSearch.setCenterPoint("New York, NY"); 49 50 // Set searchComplete as the callback function when a search is complete. The 51 // localSearch object will have results in it. 52 localSearch.setSearchCompleteCallback(this, searchComplete, null); 53 54 // Specify search quer(ies) 55 localSearch.execute('coffee New York NY'); 56 57 // Include the required Google branding. 58 // Note that getBranding is called on google.search.Search 59 google.search.Search.getBranding('branding'); 60 } 61 62 // Set a callback to call your code when the page loads 63 google.setOnLoadCallback(onLoad); 64 65 </script> 66 </head> 67 <body style="font-family: Arial;border: 0 none;"> 68 <div id="branding" style="float: left;"></div><br /> 69 <div id="content">Loading...</div> 70 </body> 71 </html>

其中最重要的是调用这个地址:

http://ajax.googleapis.com/ajax/services/search/local?v=1.0&q=Palm%20Springs%20CA
两个必须的参数如下:
v:版本号,如1.0
q:搜索的关键字
还有一些其它常可以用到的参数:
key:搜索的时候,需要验证的key值,这个你必须到google上去申请
sll:中心坐标,你可以指定一个坐标为中心进行搜索
rsz:每页显示几条数据,值为1-8,当然,每次搜索最大记录数为64

我们来看看常见的几种语言是如何来使用的:
使用Flash
var service:HTTPService = new HTTPService(); service.url = 'http://ajax.googleapis.com/ajax/services/search/local'; service.request.v = '1.0'; service.request.q = 'Palm%20Springs%20CA'; service.request.key = 'INSERT-YOUR-KEY'; service.resultFormat = 'text'; service.addEventListener(ResultEvent.RESULT, onServerResponse); service.send(); private function onServerResponse(event:ResultEvent):void { try { var json:Object = JSON.decode(event.result as String); // now have some fun with the results... } catch(ignored:Error) { } }
使用Java

URL url = new URL("http://ajax.googleapis.com/ajax/services/search/local?" + "v=1.0&q=barack%20obama&key=INSERT-YOUR-KEY&userip=INSERT-USER-IP"); URLConnection connection = url.openConnection(); connection.addRequestProperty("Referer", /* Enter the URL of your site here */); String line; StringBuilder builder = new StringBuilder(); BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); while((line = reader.readLine()) != null) { builder.append(line); } JSONObject json = new JSONObject(builder.toString()); // now have some fun with the results...

使用PHP

$url = "http://ajax.googleapis.com/ajax/services/search/local?" + "v=1.0&q=barack%20obama&key=INSERT-YOUR-KEY&userip=INSERT-USER-IP"; // sendRequest // note how referer is set manually $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_REFERER, /* Enter the URL of your site here */); $body = curl_exec($ch); curl_close($ch); // now, process the JSON string $json = json_decode($body); // now have some fun with the results...


今天先介绍到这里,以后我会更详细的进行简介一下。

下面是我用Flex做的一个示例,结合了Google Map,支持关键字搜索,并可以导出结果。

再次申明,程序只用于学习使用,请必用于商业。需要安装Flash AIR

下载地址是:http://files.cnblogs.com/liongis/GMapLocalSearch.rar

[转载]html5声频audio和视频video

mikel阅读(1172)

[转载]html5声频audio和视频video – 破狼 – 博客园.

html5作为下一代web标准,年前轩起了html5热潮。对于html5我只是本着了解看看。关于html5和 RIA(silverlight,flash,JavaFx等)我不想说什么,也没有什么可说的,存在就有其存在的理由。孰优孰劣,留给事实、时间来证明 的。

在html5中出现了一些新特性:

  • canvas 元素
  • 视频 video 和 声频audio 元素 ;
  • 对本地离线存储(localStorage,sessionStorage)的支持 ;
  • 新增特殊内容元素:article、footer、header、nav、section ;
  • 新增表单控件: calendar、date、time、email、url、search 。

今天看看视频和声频:在html5中规定了视频的标准方法:video

<video src="xxx.ogg" controls="controls">你的浏览器还不支持哦</video>
  我们也可以设置多个source,浏览器会为我们选择第一个可识别的视频来播放,形如:
<video width="320" height="240" controls="controls">
<source src="xxx.ogg" type="video/ogg">
 <source src="xx1.mp4" type="video/mp4">
你的浏览器还不支持哦</video>
video属性有:
属性 描述
autoplay autoplay 如果出现该属性,则视频在就绪后马上播放。
controls controls 如果出现该属性,则向用户显示控件,比如播放按钮。
height 像素 设置视频播放器的高度。
loop loop 如果出现该属性,则当媒介文件完成播放后再次开始播放。
preload preload 如果出现该属性,则视频在页面加载时进行加载,并预备播放。

如果使用 “autoplay”,则忽略该属性。

src url视频地址 要播放的视频的 URL。
width 像素 设置视频播放器的宽度。
autobuffer Autobuffer

(自动缓冲)

在网页显示时,该二进制属性表示是由用户代理(浏览器)自动缓冲的内容,还是由用户使用相关API进行内容缓冲
poster url图片地址

当视频未响应或缓冲不足时,该属性值链接到一个图像。该图像将以一定比例被显示出来

在HTML5 规定了声频标准为 audio 元素,audio 元素能够播放声音文件或者音频流。

audio格式和video相似:直接行多source:

<audio controls="controls">
  <source src="xx.ogg" type="audio/ogg">
  <source src="xx1.mp3" type="audio/mpeg">
你的浏览器还不支持哦
</audio>
其属性比video少了height、width、poster。
在我们的开发中多媒体越来越重要,html5出现了这些video和audio。

[转载]介绍一个开源的ORM--ORM.NET

mikel阅读(823)

[转载]介绍一个开源的ORM–ORM.NET – Code,I hate you… – 博客园.

一.介绍

ORM.NET是一个开源的.net对象关系映射的代码生成工具,它根据数据库结构生成一个数据实体层,为每一个表生成一个对应的类,为表的每一个字段生成类的一个属性。

通过生成的DataManager对象,不用使用存储过程和嵌入SQL脚本就可以很容易根据复杂的条件检索数据,除此之外,数据更新,插入和删除可以通过一次调用就可以对数据进行保存。

官网地址:http://orm-net.sourceforge.net/

下载:http://sourceforge.net/projects/orm-net/files/ORM.NET/

二.演示

http://orm-net.sourceforge.net/tour.html

三.官方提供的使用示例

//根据数据库连接字符串创建一个数据管理对象

DataManager data = new DataManager(Config.Dsn);

//获取一个Customers集合并检索关联的Order表

CustomersCollection customers = data.GetCustomersCollection(FetchPath.Customers.Orders);

//根据ContactName进行降序排序

customers.SortByContactName(SortDirection.Descending);

//更新Customers表中CustomerID=”ALFKI”的记录,把ContactName修改为”Peach”

customers.FindByCusmerID(“ALFKI”).ContactName = “Peach”;

//创建一个新的customer对象

Customers customer = data.NewCustomers(“Tes7″,”Orero software”);

customer.ContactName = “Tech Support”;

//创建新的关联对象

Orders order = customer.NewOrders();

order.OrderDate = DateTime.Now;

//通知DataManager更新数据库一直持续到所有的操作完成

data.CommitAll();

说明:我只是翻译过来跟大家分享一下这个ORM,让大家多了解一下,具体我没在项目中用过也没测试过,个人觉得这样的ORM只适合做网站和小项目可能提高开发效率。

[转载]AndroidNDK开发之“文件操作”

mikel阅读(1015)

[转载]AndroidNDK开发之“文件操作” – duicky – 博客园.

其实和上层没什么关系,主要是通过C来完成文件的基本操作。不好意思大家,时间不够,不多说,贴上关键代码。

关键文件代码:

MainActivity.java

package com.scan.file;

import Android.app.Activity;
import Android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {

private static final String TAG = “File”;
private Button doc = null;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

initControls();
}

/**
* 初始化控件
*/
public void initControls() {
doc = (Button) this.findViewById(R.id.btn_do_c);
doc.setOnClickListener(new MyButtonOnClickListener());
}

/**
* 监听ButtonOnClick
*
* @author lxf
*
*/
class MyButtonOnClickListener implements OnClickListener {

@Override
public void onClick(View v) {
switch (v.getId()) {

case R.id.btn_do_c:
String do_c_result = doCMethod();
displayMessage(do_c_result);
break;
}

}

}

/*
* Toast显示消息
*/
private void displayMessage(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}

/**
* 测试方法
*
* @return
*/
public native String sayHello();

/**
* 执行C底层的方法
*
* @return
*/
public native String doCMethod();

/*
* 载人本地库文件
*/
static {
System.loadLibrary(“AndroidJni”);
}
}

file.h

#include <string.h>
#include <stdio.h>
#include “define.h”

unsigned short File_Open(FILE_HANDLE** FileHandle, char* name, unsigned short flag,unsigned short mode);

unsigned short File_Close(FILE_HANDLE* FileHandle);

unsigned short File_GetSize(FILE_HANDLE* FileHandle, unsigned long* FileSize);

unsigned short File_Read(FILE_HANDLE* FileHandle, char* buf, unsigned long count,unsigned long* ReadCount);

unsigned short File_Write(FILE_HANDLE* FileHandle, char* buf, unsigned long count,unsigned long* WriteCount);

unsigned short File_Seek(FILE_HANDLE* FileHandle, long offset, short origin,unsigned long* SeekLen);

unsigned short File_Delete(char* name);

unsigned short File_ISExist(char* path);

unsigned short File_Create_Dir(char* dirName);

unsigned short File_Delete_Dir(char* dirName);

Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := AndroidJni
LOCAL_SRC_FILES := AndroidJni.c File.c SyncmlEngine.c

LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog

include $(BUILD_SHARED_LIBRARY)

AndroidJni.c

#include <string.h>
#include <jni.h>
#include <android/log.h>
#include “SyncmlEngine.h”

//测试方法sayHello
jstring Java_com_scan_file_MainActivity_sayHello(JNIEnv* env, jobject thiz) {
//打印信息出来
__android_log_print(ANDROID_LOG_INFO, “JNIMsg”, “SayHello”);
return (*env)->NewStringUTF(env, “Hello from JNI ! sayHello”);
}

//执行C底层方法
jstring Java_com_scan_file_MainActivity_doCMethod(JNIEnv* env, jobject thiz) {
//打印信息出来
__android_log_print(ANDROID_LOG_INFO, “JNIMsg”, “doCMethod”);

SyncmlStart();

return (*env)->NewStringUTF(env, “Do C Method OK!”);
}

file.c

#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <dirent.h>
#include <android/log.h>
#include “File.h”

/**
* File_Open–打开文件
* flag–读\写\读写\追加
* mode–如果没有,是否新建
*/
unsigned short File_Open(FILE_HANDLE** FileHandle, char* name,
unsigned short flag, unsigned short mode) {

if (FileHandle == NULL) {
return 100;
}
if (name == NULL) {
return 100;
}
char type[128] = “”;

if (flag == FO_OREAD) {
if (mode != FO_CREATE) {
strcpy(type, “r”); //只读,不建文件
} else {
strcpy(type, “r+”);
}
} else if (flag == FO_OWRITE) {
if (mode != FO_CREATE) {
strcpy(type, “w”); //只写,不建文件
} else {
strcpy(type, “w+”);
}
} else if (flag == FO_RW) {
if (mode != FO_CREATE) {
strcpy(type, “a”);
} else {
strcpy(type, “a+”);
}
} else if (flag == FO_APPEND) {
if (mode != FO_CREATE) {
strcpy(type, “a”);
} else {
strcpy(type, “a+”);
}
}

*FileHandle = fopen(name, type);
return 0;
}

/**
* File_Close–关闭文件
* 返回值
* 0–关闭成功;否则失败
*/
unsigned short File_Close(FILE_HANDLE* FileHandle) {
if (FileHandle == NULL) {
return 100;
}
return fclose(FileHandle);
}

/**
* File_GetSize–得到文件长度
* FileSize–返回文件长度
*/
unsigned short File_GetSize(FILE_HANDLE* FileHandle, unsigned long* FileSize) {
if (FileHandle == NULL) {
return 100;
}
fseek(FileHandle, 0L, SEEK_END);
*FileSize = ftell(FileHandle);
return 0;
}

/**
* File_Read–读取文件到buf
* count–读取的长度
* ReadCount–返回已读取的长度
*/
unsigned short File_Read(FILE_HANDLE* FileHandle, char* buf,
unsigned long count, unsigned long* ReadCount) {
if (FileHandle == NULL) {
return 100;
}
*ReadCount = fread(buf, 1, count, FileHandle);
__android_log_print(ANDROID_LOG_INFO, “JNIMsg”,
“File_Read           ReadCount=%d”, *ReadCount);
return 0;
}

/**
* File_Write–从buf中写入文件
* count–写入的长度
* WriteCount–返回已写入的长度
*/
unsigned short File_Write(FILE_HANDLE* FileHandle, char* buf,
unsigned long count, unsigned long* WriteCount) {
if (FileHandle == NULL) {
return 100;
}
unsigned short write_result = fwrite(buf, count, 1, FileHandle); // 返回值是成功写入的项目数
if(write_result == 1) {
*WriteCount = write_result * count;
}
return write_result;
}

/**
* File_Seek–给文件偏移量
* offset–偏移量
* origin–偏移方向
* SeekLen–返回已偏移的长度
* 返回值0–成功,其他失败
*/
unsigned short File_Seek(FILE_HANDLE* FileHandle, long offset, short origin,
unsigned long* SeekLen) {
unsigned short seek_result = fseek(FileHandle, offset, origin);
if(seek_result == 0) {
*SeekLen = offset;
}
return seek_result;
}

/**
* File_Delete–删除文件
* 0–删除成功  -1–删除失败
*/
unsigned short File_Delete(char* name) {
if (name == NULL) {
return 100;
}
return remove(name);
}

/**
* File_ISExist–判断文件是否存在
* 0存在  -1不存在
*/
unsigned short File_ISExist(char* path) {
if (path == NULL) {
return 100;
}
return access(path, 0);
}

/**
* File_Create_Dir–创建文件目录
* 返回0–成功
*/
unsigned short File_Create_Dir(char* dirName) {
if (dirName == NULL) {
return 100;
}
return mkdir(dirName, S_IRWXU);
}

/**
* File_Delete_Dir–删除文件目录
*/
unsigned short File_Delete_Dir(char* dirName) {
if (dirName == NULL) {
return 100;
}
DIR* dp = NULL;
DIR* dpin = NULL;
char *pathname = (char*) malloc(256);
memset(pathname, 0, 256);
struct dirent* dirp;
dp = opendir(dirName);
if (dp == NULL) {
__android_log_print(ANDROID_LOG_INFO, “JNIMsg”,
“File_Delete_Dir      your input directory is not exist!”);
return 100;
}
while ((dirp = readdir(dp)) != NULL) {
if (strcmp(dirp->d_name, “..”) == 0 || strcmp(dirp->d_name, “.”) == 0)
continue;
strcpy(pathname, dirName);
strcat(pathname, “/”);
strcat(pathname, dirp->d_name);
dpin = opendir(pathname);
if (dpin != NULL) {
closedir(dpin);
dpin = NULL;
File_Delete_Dir(pathname);
} else {
remove(pathname);
}
}
rmdir(dirName);
closedir(dp);
free(pathname);
pathname = NULL;
dirp = NULL;

return 0;
}

有看不懂的地方可以留言,一起探讨。

[转载]中兴 X876使用技巧

mikel阅读(1118)

X876使用小技巧

第一次使用安卓系统,于是把自己遇到并解决的问题一个个写出来,都是在876上实践的。

1.关于WIFI黑屏就掉线的解决方法:
进入“设置”-“无线和网络”-“WLAN设置”-“MENU(手机的菜单键)”-“高级”-“WLAN休眠策略”-“永不休眠”-“MENU”-“保存”
有很多人说无效,我也不知道什么原因,之前我是没问题的,后来也不行了~郁闷。

2.蓝牙接发问题:
发送:点住文件不放,弹出对话框,选蓝牙发送。
接收:收到消息时,(注意看手机最左上角的消息通知),然后试试按住信息栏不放往下托拉。(信息栏就是最上面那栏,有信号阿,电池阿这里)

3.图标的显示、隐藏和换屏:
显示:有的人安装了软件后,软件不会在主屏上显示,而是直接到了程序库里(自己暂时这么叫了),调出来的方法是进入程序库,找到对应软件的图标点住不放直到可移动后直接移到主屏上。
隐藏:在主屏上对着一个图标点住不放直到可移动后(有震动提示),把它扔到垃圾桶。
换屏:在主屏上对着一个图标点住不放直到可移动后,移到主屏的边缘不动,手机自动会换屏。
程序库进入方法:激活屏幕后,MENU对上的那个点阵块。

4.SD装载与卸载:
手机用数据线连上电脑后,手机方会有提示“装载”或“不装载”,装载就是连上SD卡,这时可以拷贝文件到手机SD卡上。
如果要断开SD与电脑的连接,直接按住信息栏不放往下托拉,点击“关闭USB存储设备”,再点“关”闭即可。
如果一开始点了不装载,之后又想装载。直接按住信息栏不放往下托拉,点击“USB已连接”再点“装载”即可
注:以上“4”的操作从没断开过数据线。(这个好阿,手机屁屁可以多插几年了)

5.输入法的切换:
很多人不喜欢手机自带的输入法,包括我也一样。所以会自行装其他输入法(我最喜欢百度输入法),那么要如何在输入的时候换你安装好的输入法呢?
方法:点住输入框不放。然后看到了吧?

6.google搜索框的调用:
其实手机带的google搜索很有用,很方便。输入一个字符,手机有关的就会显示出来,无关的也可以调出来。不过它占在主屏上很不好看也浪费位置。我们可以用上面“3”的方法把它去掉。那么要如何调出来呢?
激活屏幕,然后对着“MENU”长按不放,看到什么了没?一个键盘! 直接输入就行了。比如输入“U” 那么”UC浏览器”是不是就可以用了呢?  再比如输入“www.baidu.com”是不是直接就可以用UC上网呢?(前提是UC是默认浏览器)就不用特意去开UC,开了UC后又输入了。方便吧?

7.后台程序的查看:
方法跟“6”一样,不过是对着房子键长按。(MENU左边那个)。不过好像不能结束程序。
下面8楼的兄弟”cby200311″指的就是这个。加分鼓励。

8.长按屏幕左下或右下的“…”键,能够调出五屏来。

9.壁纸不能全屏?
解决方法:别用240X400的壁纸(虽然像素是这个),876的壁纸是跟着屏幕动的,876有五个分屏!经过试验。  请使用像素为:600X500的壁纸。 我已经验证可行,相当不错。

10.铃音、信息音和闹钟音的自由调用:
铃音:找到声音文件,长按不放,弹出的对话框中选“用作铃声
信息音:进入信息-“MENU”-“设置”-“选择铃声” 确定即可。
闹钟音:进入“闹钟时钟”–“MENU”-“添加闹钟”(或对着已有闹钟长按-编辑)-“铃声” 选择确定即可。

自由铃音:
在SD卡的根目录下增加media文件夹,在该文件夹里创建audio文件夹,在该文件夹里在创建以下文件夹:
ringtones      文件夹—来电铃声,里面放入自选的铃声音乐
notifications  文件夹—短信铃声,里面放入自选的铃声音乐;
alarms          文件夹—闹铃铃声,里面放入自选的铃声音乐;
设置好后,用上面的方法进行调用。

[转载]深入理解Android消息处理系统——Looper、Handler、Thread

mikel阅读(857)

[转载]深入理解Android消息处理系统——Looper、Handler、Thread – Greenwood – 博客园.

(自) Activity,Service属于主线程,在主线程中才能更新UI,如toast等。其他线程中不能直接使用,这时可以使用Handler来处理,Handler可以在Activity和Service中。

熟悉Windows编程的朋友可能知道Windows程序是消息驱动的,并且有全局的消息循环系统。而Android应用程序也是消息驱动的,按道 理来说也应该提供消息循环机制。实际上谷歌参考了Windows的消息循环机制,也在Android系统中实现了消息循环机制。Android通过 Looper、Handler来实现消息循环机制,Android消息循环是针对线程的(每个线程都可以有自己的消息队列和消息循环)。本文深入介绍一下 Android消息处理系统原理。

Android系统中Looper负责管理线程的消息队列和消息循环,具体实现请参考Looper的源码。 可以通过Loop.myLooper()得到当前线程的Looper对象,通过Loop.getMainLooper()可以获得当前进程的主线程的 Looper对象。

前面提到Android系统的消息队列和消息循环都是针对具体线程的,一个线程可以存在(当然也可以不存在)一个消息队列和一个消息循环 (Looper),特定线程的消息只能分发给本线程,不能进行跨线程,跨进程通讯。但是创建的工作线程默认是没有消息循环和消息队列的,如果想让该线程具 有消息队列和消息循环,需要在线程中首先调用Looper.prepare()来创建消息队列,然后调用Looper.loop()进入消息循环。如下例 所示:

class LooperThread extends Thread {
public Handler mHandler;

public void run() {
Looper.prepare();

mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};

Looper.loop();
}
}这样你的线程就具有了消息处理机制了,在Handler中进行消息处理。

Activity是一个UI线程,运行于主线程中,Android系统在启动的时候会为Activity创建一个消息队列和消息循环(Looper)。详细实现请参考ActivityThread.java文件。

Handler的作用是把消息加入特定的(Looper)消息队列中,并分发和处理该消息队列中的消息。构造Handler的时候可以指定一个Looper对象,如果不指定则利用当前线程的Looper创建。详细实现请参考Looper的源码。

Activity、Looper、Handler的关系如下图所示:

message

一个Activity中可以创建多个工作线程或者其他的组件,如果这些线程或者组件把他们的消息放入Activity的主线程消息队列,那么该消息就会在 主线程中处理了。因为主线程一般负责界面的更新操作,并且Android系统中的weget不是线程安全的,所以这种方式可以很好的实现Android界 面更新。在Android系统中这种方式有着广泛的运用。

那么另外一个线程怎样把消息放入主线程的消息队列呢?答案是通过Handle对象,只要Handler对象以主线程的Looper创建,那么调用 Handler的sendMessage等接口,将会把消息放入队列都将是放入主线程的消息队列。并且将会在Handler主线程中调用该handler 的handleMessage接口来处理消息。

这里面涉及到线程同步问题,请先参考如下例子来理解Handler对象的线程模型:

1、首先创建MyHandler工程。

2、在MyHandler.java中加入如下的代码:

package com.simon;

import android.app.Activity;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
import android.os.Handler;

public class MyHandler extends Activity {
static final String TAG = “Handler”;
Handler h = new Handler(){
public void handleMessage (Message msg)
{
switch(msg.what)
{
case HANDLER_TEST:
Log.d(TAG, “The handler thread id = ” + Thread.currentThread().getId() + “\n”);
break;
}
}
};

static final int HANDLER_TEST = 1;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, “The main thread id = ” + Thread.currentThread().getId() + “\n”);

new myThread().start();
setContentView(R.layout.main);
}

class myThread extends Thread
{
public void run()
{
Message msg = new Message();
msg.what = HANDLER_TEST;
h.sendMessage(msg);
Log.d(TAG, “The worker thread id = ” + Thread.currentThread().getId() + “\n”);
}
}
}在这个例子中我们主要是打印,这种处理机制各个模块的所处的线程情况。如下是我的机器运行结果:

09-10 23:40:51.478: Debug/Handler(302): The main thread id = 1
09-10 23:40:51.569: Debug/Handler(302): The worker thread id = 8
09-10 23:40:52.128: DEBUG/Handler(302): The handler thread id = 1我们可以看出消息处理是在主线程中处理的,在消息处理函数中可以安全的调用主线程中的任何资源,包括刷新界面。工作线程和主线程运行在不同的线程中,所 以必须要注意这两个线程间的竞争关系。

上例中,你可能注意到在工作线程中访问了主线程handler对象,并在调用handler的对象向消息队列加入了一个消息。这个过程中会不会出现消息队 列数据不一致问题呢?答案是handler对象不会出问题,因为handler对象管理的Looper对象是线程安全的,不管是加入消息到消息队列和从队 列读出消息都是有同步对象保护的,具体请参考Looper.java文件。上例中没有修改handler对象,所以handler对象不可能会出现数据不 一致的问题。

通过上面的分析,我们可以得出如下结论:

1、如果通过工作线程刷新界面,推荐使用handler对象来实现。

2、注意工作线程和主线程之间的竞争关系。推荐handler对象在主线程中构造完成(并且启动工作线程之后不要再修改之,否则会出现数据不一致),然后在工作线程中可以放心的调用发送消息SendMessage等接口。

3、除了2所述的hanlder对象之外的任何主线程的成员变量如果在工作线程中调用,仔细考虑线程同步问题。如果有必要需要加入同步对象保护该变量。

4、handler对象的handleMessage接口将会在主线程中调用。在这个函数可以放心的调用主线程中任何变量和函数,进而完成更新UI的任务。

5、Android很多API也利用Handler这种线程特性,作为一种回调函数的变种,来通知调用者。这样Android框架就可以在其线程中将消息发送到调用者的线程消息队列之中,不用担心线程同步的问题。

深入理解Android消息处理机制对于应用程序开发非常重要,也可以让你对线程同步有更加深刻的认识。以上是最近Simon学习Android消息处理机制的一点儿总结,如有错误之处请不吝指教。

转自:http://blog.csdn.net/dywe_ddm/archive/2010/10/10/5930948.aspx

[转载]Flash游戏编程指南

mikel阅读(1104)

[转载]Flash游戏编程指南-RIABook.cn.


这本是天地会译林军翻译的完整版,700多页真是辛苦了,除了每页上边的培训广告有点煞风景其他都好.
英文原书是这本The Essential Guide to Flash Games: Building Interactive Entertainment with ActionScript

目录

第一部分  基本游戏框架
第一章 第二游戏说          (译者:aserrewin)
第二章 创建一个AS3游戏框架     (译者:aserrewin)
第三章 创建超级点击         (译者:kenjor)

第二部分  游戏实例
第四章 御空加农炮的基础架构     (译者:yyluo-阿树)
第五章 构建御空加农炮游戏循环    (译者:yyluo-阿树)
第六章 预备!坦克大战        (译者:sun11086-0025)
第七章 构建坦克大战游戏       (译者:sun11086-0025,peichao01)
第八章 休闲智力游戏-魔法色块    (译者:cosmos53076)
第九章 骰子游戏王          (译者:yangjh415)
第十章 滚屏游戏世界         (译者:Pizzaman)
第十一章 制作绝佳的反应力游戏    (译者:享受生活)
第十二章 制作一个Viral Game: 隧道惊魂 (译者:心月不皈,Mr.Star )

下载:

From 115网盘
From 微盘
From 天地会

[转载]android开发我的新浪微博客户端-阅读微博功能篇(6.2)

mikel阅读(871)

[转载]android开发我的新浪微博客户端-阅读微博功能篇(6.2) – 遇见未知的自己 – 博客园.

注:最近由于OAuth上传图片碰到了难题,一直在做这方面的研究导致博客很久没有更新。

在上面一篇中已经实现了预读微博的UI界面,效果如上图,接下来完成功能部分的代码,当用户在上一个列表界面的列表中点击某一条微博的时候显示这个阅读微博的界面,在这个界面中根据传来的微博ID,然后根据这个ID通过api获取微博的具体内容进行显示。

在ViewActivity.class的onCreate方法中添加如下代码:

private UserInfo user;
private String key=“”;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view);

。。。。。

//获取上一个页面传递过来的key,key为某一条微博的id
Intent i=this.getIntent();
if(!i.equals(null)){
Bundle b
=i.getExtras();
if(b!=null){
if(b.containsKey(key)){
key
= b.getString(key);
view(key);
}
}
}

}

接下来就是view方法具体获取微博内容的方法,在这个方法中如果获取的本条微博如果包含图片那么就用前面AsyncImageLoader的方法异步载入图片并且进行显示,同时在这个方法中还要获取本条微博被转发的次数以及评论的次数,具体代码如下:

private void view(String id){
user
=ConfigHelper.nowUser;
OAuth auth
=new OAuth();
String url
= http://api.t.sina.com.cn/statuses/show/:id.json;
List params
=new ArrayList();
params.add(
new BasicNameValuePair(source, auth.consumerKey));
params.add(
new BasicNameValuePair(id, id));
HttpResponse response
=auth.SignRequest(user.getToken(), user.getTokenSecret(), url, params);
if (200 == response.getStatusLine().getStatusCode()){
try {
InputStream is
= response.getEntity().getContent();
Reader reader
= new BufferedReader(new InputStreamReader(is), 4000);
StringBuilder buffer
= new StringBuilder((int) response.getEntity().getContentLength());
try {
char[] tmp = new char[1024];
int l;
while ((l = reader.read(tmp)) != 1) {
buffer.append(tmp,
0, l);
}
}
finally {
reader.close();
}
String string
= buffer.toString();
//Log.e(“json”, “rs:” + string);
response.getEntity().consumeContent();
JSONObject data
=new JSONObject(string);
if(data!=null){
JSONObject u
=data.getJSONObject(user);
String userName
=u.getString(screen_name);
String userIcon
=u.getString(profile_image_url);
Log.e(
userIcon, userIcon);
String time
=data.getString(created_at);
String text
=data.getString(text);

TextView utv=(TextView)findViewById(R.id.user_name);
utv.setText(userName);
TextView ttv
=(TextView)findViewById(R.id.text);
ttv.setText(text);

ImageView iv=(ImageView)findViewById(R.id.user_icon);
AsyncImageLoader asyncImageLoader
= new AsyncImageLoader();
Drawable cachedImage
= asyncImageLoader.loadDrawable(userIcon,iv, new ImageCallback(){
@Override
public void imageLoaded(Drawable imageDrawable,ImageView imageView, String imageUrl) {

imageView.setImageDrawable(imageDrawable);
}
});
if (cachedImage == null)
{
iv.setImageResource(R.drawable.usericon);
}
else
{
iv.setImageDrawable(cachedImage);
}
if(data.has(bmiddle_pic)){
String picurl
=data.getString(bmiddle_pic);
String picurl2
=data.getString(original_pic);

ImageView pic=(ImageView)findViewById(R.id.pic);
pic.setTag(picurl2);
pic.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
Object obj
=v.getTag();
Intent intent
= new Intent(ViewActivity.this,ImageActivity.class);
Bundle b
=new Bundle();
b.putString(
url, obj.toString());
intent.putExtras(b);
startActivity(intent);
}
});
Drawable cachedImage2
= asyncImageLoader.loadDrawable(picurl,pic, new ImageCallback(){
@Override
public void imageLoaded(Drawable imageDrawable,ImageView imageView, String imageUrl) {
showImg(imageView,imageDrawable);
}
});
if (cachedImage2 == null)
{
//pic.setImageResource(R.drawable.usericon);
}
else
{
showImg(pic,cachedImage2);
}
}
}
}
catch (IllegalStateException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
catch (JSONException e) {
e.printStackTrace();
}
}
url
= http://api.t.sina.com.cn/statuses/counts.json;
params
=new ArrayList();
params.add(
new BasicNameValuePair(source, auth.consumerKey));
params.add(
new BasicNameValuePair(ids, id));
response
=auth.SignRequest(user.getToken(), user.getTokenSecret(), url, params);
if (200 == response.getStatusLine().getStatusCode()){
try {
InputStream is
= response.getEntity().getContent();
Reader reader
= new BufferedReader(new InputStreamReader(is), 4000);
StringBuilder buffer
= new StringBuilder((int) response.getEntity().getContentLength());
try {
char[] tmp = new char[1024];
int l;
while ((l = reader.read(tmp)) != 1) {
buffer.append(tmp,
0, l);
}
}
finally {
reader.close();
}
String string
= buffer.toString();
response.getEntity().consumeContent();
JSONArray data
=new JSONArray(string);
if(data!=null){
if(data.length()>0){
JSONObject d
=data.getJSONObject(0);
String comments
=d.getString(comments);
String rt
=d.getString(rt);
Button btn_gz
=(Button)findViewById(R.id.btn_gz);
btn_gz.setText(
转发(+rt+));
Button btn_pl
=(Button)findViewById(R.id.btn_pl);
btn_pl.setText(
评论(+comments+));
}
}
}
catch (IllegalStateException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
catch (JSONException e) {
e.printStackTrace();
}
}

}

在上面的方法中对于微博中包含的图片显示尺寸进行了特别的处理,如果直接把获取的图片显示在ImageView中,因为当图片宽高超过手机屏幕的时候,系 统会自动按照手机的屏幕按比例缩放图片进行显示,但是我发现一个现象图片的高虽然是按照比例缩小了,但是图片占据的高仍旧是原来图片的高度照成真实图片和 文字内容之间多了很高的一块空白,这个现象非常的奇怪,所以我写了如下方法进行处理:

private void showImg(ImageView view,Drawable img){
int w=img.getIntrinsicWidth();
int h=img.getIntrinsicHeight();
Log.e(
w, w+/+h);
if(w>300)
{
int hh=300*h/w;
Log.e(
hh, hh+“”);
LayoutParams para
=view.getLayoutParams();
para.width
=300;
para.height
=hh;
view.setLayoutParams(para);
}
view.setImageDrawable(img);

}

本篇到这里就结束了,请继续关注下一篇。

[转载]ASP.NET MVC 3.0学习系列文章—NuGet and ASP.NET MVC 3.0

mikel阅读(1123)

[转载]ASP.NET MVC 3.0学习系列文章—NuGet and ASP.NET MVC 3.0 – 爱因斯坦的小脑 – 博客园.

这两周忙着换工作,也没时间更新这个系列的文章。。。。。。。 Smile 在在博客园搜了NuGet这个关键字,结果只有两页,还有几篇文章是我的,所以我觉得还是介绍下NuGet,以及NuGet.org,好让一些初学者能够快速的入门。

ASP.NET MVC 3.0学习系列文章—序

ASP.NET MVC 3.0学习系列文章–Razor and ASP.NET MVC 3.0

ASP.NET MVC 3.0学习系列文章—Controllers in ASP.NET MVC 3.0

ASP.NET MVC 3.0学习系列文章—Model in ASP.NET MVC 3.0

ASP.NET MVC 3.0学习系列文章–Dependency Resolution in ASP.NET MVC 3.0

NuGet-Stickers-550x365

1.Introduction

NuGet is a Visual Studio 2010 extension that makes it easy to add, remove, and update libraries and tools in Visual Studio projects that use the .NET Framework. This topic lists documentation that will help you use NuGet packages and create your own.

NuGet是一个开源的项目,项目的发起人是微软的几个人员。如果你关注NuGet建议关注这两个人:

a.David Ebbo http://blog.davidebbo.com/ Twitter: @davidebbo

b. Phil Haack http://haacked.com/

2.Why NuGet

NuGet的使用可以缩短我们下载和添加dll的时间。不适用nuget的时候,我们添加一个dll需要先下载,解压,添加引用等等。而使用nuGet只需要一步操作。

image

可以看出来,使用NuGet后,dll的配置可以自动添加,而且当有新的版本出现时可以自动更新dll。

使用NuGet另外一个优点是,你添加一个dll后,它会自动把相关联的dll给添加到引用中来。

image

3.安装NuGet

你可以去codeplex上下载NuGet,或者使用VS2010的Extension Manager来安装NuGet:

image

关于NuGet的使用,我这里就给大家说明下如何使用帮助命令:

image

4.NuGet的打包和Feed:

1. 如何打包一个NuGet包: http://nuget.codeplex.com/wikipage?title=Creating%20a%20Package

2.Hosting Your Own Local and Remote NuGet Feeds

http://haacked.com/archive/2010/10/21/hosting-your-own-local-and-remote-nupack-feeds.aspx

5.NuGet.org

image

你只需要注册一个账号就可以上传Package了。 如果你需要和别人分享一个模块或者项目,可以试试使用nuget来分享。。

Nick

[转载]memcached源码分析之slabs

mikel阅读(1101)

[转载]memcache源码分析之slabs – 先贝夜话 – 博客园.

slab是memcache用来管理item的内容存储部分。

分配内存时,memcache把我们通过参数m设置的内存大小分配到每个slab中

1、slab默认最多为200个,但是由于item的最大为1MB,而且每个slab里面存储的item的尺寸是根据factor来确定的,所以能够分配的slab的个数小于200。

2、关于增长因子factor参数(配置时参数名为f),默认为1.25,即每个slab所能存储的item的大小是根据factor的大小来变化的。

3、每个slab中含有一个或多个trunk,trunk中存储的就是item,item的最大为1M,所以trunk最大为1M

4、每个slab中会有一个item空闲列表,当新的item需要存储时,首先会考虑空闲列表,从中取出一个位置用来存储。当空闲列表满时,系统会去自动扩充。

5、每个slab中有二个参数为end_page_ptr、end_page_free,前者指向当前空闲的trunk指针,后者当前 trunk指向空闲处,当4中的空闲列表为空时,如果end_page_ptr和end_page_free不为空,则会在此trunk中存储item。 如果没有多余的trunk可用,系统会自动扩充trunk。

采用这种方式管理内存的好处是最大程度的减少了内存碎片的产生,提高了存储和读取效率。

下面是一些源码注释

slabs.h

1 /* stats */
2 void stats_prefix_init(void);
3 void stats_prefix_clear(void);
4 void stats_prefix_record_get(const char *key, const size_t nkey, const bool is_hit);
5 void stats_prefix_record_delete(const char *key, const size_t nkey);
6 void stats_prefix_record_set(const char *key, const size_t nkey);
7 /*@null@*/
8 char *stats_prefix_dump(int *length);

slabs.c

001 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
002 /*
003 * Slabs memory allocation, based on powers-of-N. Slabs are up to 1MB in size
004 * and are divided into chunks. The chunk sizes start off at the size of the
005 * "item" structure plus space for a small key and value. They increase by
006 * a multiplier factor from there, up to half the maximum slab size. The last
007 * slab size is always 1MB, since that's the maximum item size allowed by the
008 * memcached protocol.
009 */
010 #include "memcached.h"
011 #include <sys/stat.h>
012 #include <sys/socket.h>
013 #include <sys/signal.h>
014 #include <sys/resource.h>
015 #include <fcntl.h>
016 #include <netinet/in.h>
017 #include <errno.h>
018 #include <stdlib.h>
019 #include <stdio.h>
020 #include <string.h>
021 #include <assert.h>
022 #include <pthread.h>
023
024 /* powers-of-N allocation structures */
025
026 typedef struct {
027 unsigned int size; /* item的大小 */
028 unsigned int perslab; /* 每个trunk有多少item */
029
030 void **slots; //空闲item列表
031 unsigned int sl_total; //空闲总量
032 unsigned int sl_curr; //当前空闲处
033
034 void *end_page_ptr; //当前trunk空闲处
035 unsigned int end_page_free; //当前trunk空闲个数
036
037 unsigned int slabs; //已分配chunk数目
038
039 void **slab_list; //trunk指针
040 unsigned int list_size; //trunk数目
041
042 unsigned int killing; /* index+1 of dying slab, or zero if none */
043 size_t requested; //已分配总内存大小
044 } slabclass_t;
045
046 static slabclass_t slabclass[MAX_NUMBER_OF_SLAB_CLASSES];
047 static size_t mem_limit = 0;//内存限制大小
048 static size_t mem_malloced = 0;//已分配大小
049 static int power_largest;
050
051 static void *mem_base = NULL;
052 static void *mem_current = NULL;//内存使用当前地址
053 static size_t mem_avail = 0;//剩余内存
054
055 /**
056 * slab 线程锁
057 */
058 static pthread_mutex_t slabs_lock = PTHREAD_MUTEX_INITIALIZER;
059
060 /*
061 * Forward Declarations
062 */
063 static int do_slabs_newslab(const unsigned int id);
064 static void *memory_allocate(size_t size);
065
066 #ifndef DONT_PREALLOC_SLABS
067 /* Preallocate as many slab pages as possible (called from slabs_init)
068 on start-up, so users don't get confused out-of-memory errors when
069 they do have free (in-slab) space, but no space to make new slabs.
070 if maxslabs is 18 (POWER_LARGEST - POWER_SMALLEST + 1), then all
071 slab types can be made.  if max memory is less than 18 MB, only the
072 smaller ones will be made.  */
073 static void slabs_preallocate (const unsigned int maxslabs);
074 #endif
075
076
077 //寻找适合给定大小的item存储的slab
078 unsigned int slabs_clsid(const size_t size) {
079 int res = POWER_SMALLEST;
080
081 if (size == 0)
082 return 0;
083 while (size > slabclass[res].size)//找到第一个比item size大的slab
084 if (res++ == power_largest)
085 return 0;
086 return res;
087 }
088
089
090 /* slab初始化*/
091 /* limit:内存大小(字节);factor:增长因子;prealloc:是否一次性分配内存*/
092 void slabs_init(const size_t limit, const double factor, const bool prealloc) {
093 int i = POWER_SMALLEST - 1;//0
094 unsigned int size = sizeof(item) + settings.chunk_size;//chunk_size 最小分配空间
095
096 mem_limit = limit;
097
098 if (prealloc) {//一次分配所有设置的内存
099 /* Allocate everything in a big chunk with malloc */
100 mem_base = malloc(mem_limit);
101 if (mem_base != NULL) {
102 mem_current = mem_base;
103 mem_avail = mem_limit;
104 } else {
105 fprintf(stderr, "Warning: Failed to allocate requested memory in one large chunk.\nWill allocate in smaller chunks\n");
106 }
107 }
108
109 memset(slabclass, 0, sizeof(slabclass));
110
111 while (++i < POWER_LARGEST && size <= settings.item_size_max / factor) {
112 /* Make sure items are always n-byte aligned */
113 if (size % CHUNK_ALIGN_BYTES)//字节数为8的倍数
114 size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES);
115
116 slabclass[i].size = size;//item大小
117 slabclass[i].perslab = settings.item_size_max / slabclass[i].size;//item数目
118 size *= factor;//乘以增长因子
119 if (settings.verbose > 1) {
120 fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n",i, slabclass[i].size, slabclass[i].perslab);
121 }
122 }
123
124 power_largest = i;
125 slabclass[power_largest].size = settings.item_size_max;
126 slabclass[power_largest].perslab = 1;//最大的只能存储一个item
127 if (settings.verbose > 1) {
128 fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n",i, slabclass[i].size, slabclass[i].perslab);
129 }
130
131 /* for the test suite:  faking of how much we've already malloc'd */
132 {
133 char *t_initial_malloc = getenv("T_MEMD_INITIAL_MALLOC");
134 if (t_initial_malloc) {
135 mem_malloced = (size_t)atol(t_initial_malloc);
136 }
137
138 }
139
140 #ifndef DONT_PREALLOC_SLABS
141 {
142 char *pre_alloc = getenv("T_MEMD_SLABS_ALLOC");
143
144 if (pre_alloc == NULL || atoi(pre_alloc) != 0) {
145 slabs_preallocate(power_largest);
146 }
147 }
148 #endif
149 }
150
151
152 //新分配trunk
153 #ifndef DONT_PREALLOC_SLABS
154 static void slabs_preallocate (const unsigned int maxslabs) {
155 int i;
156 unsigned int prealloc = 0;
157
158 /* pre-allocate a 1MB slab in every size class so people don't get
159 confused by non-intuitive "SERVER_ERROR out of memory"
160 messages.  this is the most common question on the mailing
161 list.  if you really don't want this, you can rebuild without
162 these three lines.  */
163
164 for (i = POWER_SMALLEST; i <= POWER_LARGEST; i++) {
165 if (++prealloc > maxslabs)
166 return;
167 do_slabs_newslab(i);
168 }
169
170 }
171 #endif
172
173
174 //扩充trunk数目
175 static int grow_slab_list (const unsigned int id) {
176 slabclass_t *p = &slabclass[id];
177 if (p->slabs == p->list_size) {
178 size_t new_size =  (p->list_size != 0) ? p->list_size * 2 : 16;
179 void *new_list = realloc(p->slab_list, new_size * sizeof(void *));
180 if (new_list == 0) return 0;
181 p->list_size = new_size;
182 p->slab_list = new_list;
183 }
184 return 1;
185 }
186
187
188
189 //分配trunk
190 static int do_slabs_newslab(const unsigned int id) {
191 slabclass_t *p = &slabclass[id];
192 int len = p->size * p->perslab;//1MB
193 char *ptr;
194
195 if ((mem_limit && mem_malloced + len > mem_limit && p->slabs > 0) || (grow_slab_list(id) == 0) || ((ptr = memory_allocate((size_t)len)) == 0)) {
196 MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED(id);
197 return 0;
198 }
199
200 memset(ptr, 0, (size_t)len);
201 p->end_page_ptr = ptr;
202 p->end_page_free = p->perslab;
203
204 p->slab_list[p->slabs++] = ptr;
205 mem_malloced += len;
206 MEMCACHED_SLABS_SLABCLASS_ALLOCATE(id);
207
208 return 1;
209 }
210
211
212
213 /*@存储item@*/
214 static void *do_slabs_alloc(const size_t size, unsigned int id) {
215 slabclass_t *p;
216 void *ret = NULL;
217
218 if (id < POWER_SMALLEST || id > power_largest) {
219 MEMCACHED_SLABS_ALLOCATE_FAILED(size, 0);
220 return NULL;
221 }
222
223 p = &slabclass[id];
224 assert(p->sl_curr == 0 || ((item *)p->slots[p->sl_curr - 1])->slabs_clsid == 0);
225
226 #ifdef USE_SYSTEM_MALLOC
227 if (mem_limit && mem_malloced + size > mem_limit) {
228 MEMCACHED_SLABS_ALLOCATE_FAILED(size, id);
229 return 0;
230 }
231 mem_malloced += size;
232 ret = malloc(size);
233 MEMCACHED_SLABS_ALLOCATE(size, id, 0, ret);
234 return ret;
235 #endif
236
237 /* fail unless we have space at the end of a recently allocated page,
238 we have something on our freelist, or we could allocate a new page */
239 if (! (p->end_page_ptr != 0 || p->sl_curr != 0 || do_slabs_newslab(id) != 0)) {//没有空闲 也不能扩展
240 ret = NULL;
241 } else if (p->sl_curr != 0) {
242 /* return off our freelist */
243 ret = p->slots[--p->sl_curr];
244 } else {
245 /* if we recently allocated a whole page, return from that */
246 assert(p->end_page_ptr != NULL);
247 ret = p->end_page_ptr;
248 if (--p->end_page_free != 0) {
249 p->end_page_ptr = ((caddr_t)p->end_page_ptr) + p->size;
250 } else {
251 p->end_page_ptr = 0;
252 }
253 }
254
255 if (ret) {
256 p->requested += size;
257 MEMCACHED_SLABS_ALLOCATE(size, id, p->size, ret);
258 } else {
259 MEMCACHED_SLABS_ALLOCATE_FAILED(size, id);
260 }
261
262 return ret;
263 }
264
265
266 //释放item内存
267 static void do_slabs_free(void *ptr, const size_t size, unsigned int id) {
268 slabclass_t *p;
269
270 assert(((item *)ptr)->slabs_clsid == 0);
271 assert(id >= POWER_SMALLEST && id <= power_largest);
272 if (id < POWER_SMALLEST || id > power_largest)
273 return;
274
275 MEMCACHED_SLABS_FREE(size, id, ptr);
276 p = &slabclass[id];
277
278 #ifdef USE_SYSTEM_MALLOC
279 mem_malloced -= size;
280 free(ptr);
281 return;
282 #endif
283
284 if (p->sl_curr == p->sl_total) { //需要扩充空闲列表
285 int new_size = (p->sl_total != 0) ? p->sl_total * 2 : 16; /* 16 is arbitrary */
286 void **new_slots = realloc(p->slots, new_size * sizeof(void *));
287 if (new_slots == 0)
288 return;
289 p->slots = new_slots;
290 p->sl_total = new_size;
291 }
292 p->slots[p->sl_curr++] = ptr;
293 p->requested -= size;
294 return;
295 }
296
297
298 static int nz_strcmp(int nzlength, const char *nz, const char *z) {
299 int zlength=strlen(z);
300 return (zlength == nzlength) && (strncmp(nz, z, zlength) == 0) ? 0 : -1;
301 }
302
303
304 //获取状态
305 bool get_stats(const char *stat_type, int nkey, ADD_STAT add_stats, void *c) {
306 bool ret = true;
307
308 if (add_stats != NULL) {
309 if (!stat_type) {
310 /* prepare general statistics for the engine */
311 STATS_LOCK();
312 APPEND_STAT("bytes", "%llu", (unsigned long long)stats.curr_bytes);
313 APPEND_STAT("curr_items", "%u", stats.curr_items);
314 APPEND_STAT("total_items", "%u", stats.total_items);
315 APPEND_STAT("evictions", "%llu",(unsigned long long)stats.evictions);
316 APPEND_STAT("reclaimed", "%llu",(unsigned long long)stats.reclaimed);
317 STATS_UNLOCK();
318 } else if (nz_strcmp(nkey, stat_type, "items") == 0) {
319 item_stats(add_stats, c);
320 } else if (nz_strcmp(nkey, stat_type, "slabs") == 0) {
321 slabs_stats(add_stats, c);
322 } else if (nz_strcmp(nkey, stat_type, "sizes") == 0) {
323 item_stats_sizes(add_stats, c);
324 } else {
325 ret = false;
326 }
327 } else {
328 ret = false;
329 }
330
331 return ret;
332 }
333
334
335 /*状态*/
336 static void do_slabs_stats(ADD_STAT add_stats, void *c) {
337 int i, total;
338 /* Get the per-thread stats which contain some interesting aggregates */
339 struct thread_stats thread_stats;
340 threadlocal_stats_aggregate(&thread_stats);
341
342 total = 0;
343 for(i = POWER_SMALLEST; i <= power_largest; i++) {
344 slabclass_t *p = &slabclass[i];
345 if (p->slabs != 0) {
346 uint32_t perslab, slabs;
347 slabs = p->slabs;
348 perslab = p->perslab;
349
350 char key_str[STAT_KEY_LEN];
351 char val_str[STAT_VAL_LEN];
352 int klen = 0, vlen = 0;
353
354 APPEND_NUM_STAT(i, "chunk_size", "%u", p->size);
355 APPEND_NUM_STAT(i, "chunks_per_page", "%u", perslab);
356 APPEND_NUM_STAT(i, "total_pages", "%u", slabs);
357 APPEND_NUM_STAT(i, "total_chunks", "%u", slabs * perslab);
358 APPEND_NUM_STAT(i, "used_chunks", "%u",slabs*perslab - p->sl_curr - p->end_page_free);
359 APPEND_NUM_STAT(i, "free_chunks", "%u", p->sl_curr);
360 APPEND_NUM_STAT(i, "free_chunks_end", "%u", p->end_page_free);
361 APPEND_NUM_STAT(i, "mem_requested", "%llu",(unsigned long long)p->requested);
362 APPEND_NUM_STAT(i, "get_hits", "%llu",(unsigned long long)thread_stats.slab_stats[i].get_hits);
363 APPEND_NUM_STAT(i, "cmd_set", "%llu",(unsigned long long)thread_stats.slab_stats[i].set_cmds);
364 APPEND_NUM_STAT(i, "delete_hits", "%llu",(unsigned long long)thread_stats.slab_stats[i].delete_hits);
365 APPEND_NUM_STAT(i, "incr_hits", "%llu",(unsigned long long)thread_stats.slab_stats[i].incr_hits);
366 APPEND_NUM_STAT(i, "decr_hits", "%llu",(unsigned long long)thread_stats.slab_stats[i].decr_hits);
367 APPEND_NUM_STAT(i, "cas_hits", "%llu",(unsigned long long)thread_stats.slab_stats[i].cas_hits);
368 APPEND_NUM_STAT(i, "cas_badval", "%llu",(unsigned long long)thread_stats.slab_stats[i].cas_badval);
369
370 total++;
371 }
372 }
373
374 /* add overall slab stats and append terminator */
375
376 APPEND_STAT("active_slabs", "%d", total);
377 APPEND_STAT("total_malloced", "%llu", (unsigned long long)mem_malloced);
378 add_stats(NULL, 0, NULL, 0, c);
379 }
380
381
382 //为item分配内存
383 static void *memory_allocate(size_t size) {
384 void *ret;
385
386 if (mem_base == NULL) {
387 /* We are not using a preallocated large memory chunk */
388 ret = malloc(size);
389 } else {
390 ret = mem_current;
391
392 if (size > mem_avail) {
393 return NULL;
394 }
395
396 /* mem_current pointer _must_ be aligned!!! */
397 if (size % CHUNK_ALIGN_BYTES) {
398 size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES);
399 }
400
401 mem_current = ((char*)mem_current) + size;
402 if (size < mem_avail) {
403 mem_avail -= size;
404 } else {
405 mem_avail = 0;
406 }
407 }
408
409 return ret;
410 }
411
412
413 //存储
414 void *slabs_alloc(size_t size, unsigned int id) {
415 void *ret;
416
417 pthread_mutex_lock(&slabs_lock);
418 ret = do_slabs_alloc(size, id);
419 pthread_mutex_unlock(&slabs_lock);
420 return ret;
421 }
422
423
424 //释放
425 void slabs_free(void *ptr, size_t size, unsigned int id) {
426 pthread_mutex_lock(&slabs_lock);
427 do_slabs_free(ptr, size, id);
428 pthread_mutex_unlock(&slabs_lock);
429 }
430
431
432 //状态
433 void slabs_stats(ADD_STAT add_stats, void *c) {
434 pthread_mutex_lock(&slabs_lock);
435 do_slabs_stats(add_stats, c);
436 pthread_mutex_unlock(&slabs_lock);
437 }