安卓相机报错mm-camera 软件下载-CORE: af_cont_detect_scene_change_fv:459 cur_real_gain

Camera Strap | Topo Designs
Free U.S. shipping on orders over $150
Leave a note for the seller
Shipping & taxes calculated at checkout
Green Pattern - $29.00
Multi Pattern - $29.00
Maroon Pattern - $29.00
Blue Pattern - $29.00
Add to cart
Camera Strap
We know you're always on the move. We also know a camera is no good if it can't keep up so we've made a camera strap with a Colorado twist by using heavy duty climbing rope to secure your rig at all times. Durable, lightweight, available in four colors.
All of our Camera Straps are handmade here in Colorado.
26.5" long
Strong stitching keeps your camera safe
Sliplocks all adjustment with ease
10.5mm climbing rope, 3/8" nylon webbing, 3/8" sliplocks
Made in USA
Camera Strap
We know you're always on the move. We also know a camera is no good if it can't keep up so we've made a camera strap with a Colorado twist by using heavy duty climbing rope to secure your rig at all times. Durable, lightweight, available in four colors.
All of our Camera Straps are handmade here in Colorado.
26.5" long
Strong stitching keeps your camera safe
Sliplocks all adjustment with ease
10.5mm climbing rope, 3/8" nylon webbing, 3/8" sliplocks
Made in USAandroid—camera从应用到驱动——驱动代码
下面是展讯平台一个camera_gc5004的驱动代码:
所做的工作主要有:
1、camera上电_gc5004_mipi_PowerOn
2、识别camera型号_gc5004_mipi_Identify
3、硬件寄存器相关的设置
4、为kernel系统提供函数接口g_gc5004_mipi_raw_info
#include &utils/Log.h&
#include "sensor.h"
#include "jpeg_exif_header.h"
#include "sensor_drv_u.h"
#include "sensor_raw.h"
#include "sensor_gc5004_mipi_raw_param.c"
#define SENSOR_PRINT CMR_LOGE
#define DW9714_VCM_SLAVE_ADDR (0x18&&1)
#define gc5004_mipi_I2C_ADDR_W
#define gc5004_mipi_I2C_ADDR_R
#define gc5004_mipi_RAW_PARAM_COM
static int s_gc5004_mipi_gain = 0;
static int s_capture_shutter = 0;
static int s_capture_VTS = 0;
static int s_video_min_framerate = 0;
static int s_video_max_framerate = 0;
LOCAL uint32_t _gc5004_mipi_GetResolutionTrimTab(uint32_t param);
LOCAL uint32_t _gc5004_mipi_PowerOn(uint32_t power_on);
/*上电函数*/
LOCAL uint32_t _gc5004_mipi_Identify(uint32_t param);
/*读取ID函数*/
LOCAL uint32_t _gc5004_mipi_BeforeSnapshot(uint32_t param);
LOCAL uint32_t _gc5004_mipi_after_snapshot(uint32_t param);
LOCAL uint32_t _gc5004_mipi_StreamOn(uint32_t param);
LOCAL uint32_t _gc5004_mipi_StreamOff(uint32_t param);
LOCAL uint32_t _gc5004_mipi_write_exposure(uint32_t param);
LOCAL uint32_t _gc5004_mipi_write_gain(uint32_t param);
LOCAL uint32_t _gc5004_mipi_write_af(uint32_t param);
LOCAL uint32_t _gc5004_mipi_flash(uint32_t param);
LOCAL uint32_t _gc5004_mipi_ExtFunc(uint32_t ctl_param);
LOCAL uint32_t _gc5004_mipi_get_VTS(void);
LOCAL uint32_t _gc5004_mipi_set_VTS(int VTS);
LOCAL uint32_t _gc5004_mipi_ReadGain(uint32_t param);
LOCAL uint32_t _gc5004_mipi_set_video_mode(uint32_t param);
LOCAL uint32_t _gc5004_mipi_get_shutter(void);
LOCAL uint32_t _dw9174_SRCInit(uint32_t mode);
LOCAL uint32_t _gc5004_mipi_com_Identify_otp(void* param_ptr);
LOCAL const struct raw_param_info_tab s_gc5004_mipi_raw_param_tab[]={
{gc5004_mipi_RAW_PARAM_COM, &s_gc5004_mipi_raw_info, _gc5004_mipi_com_Identify_otp, PNULL},
{RAW_INFO_END_ID, PNULL, PNULL, PNULL}
struct sensor_raw_info* s_gc5004_mipi_raw_info_ptr=NULL;
static uint32_t g_module_id = 0;
static uint32_t g_flash_mode_en = 0;
static uint32_t g_af_slewrate = 1;
LOCAL const SENSOR_REG_T gc5004_mipi_common_init[] = {
{0x04, 0x40},
{0x05, 0x01},
LOCAL const SENSOR_REG_T gc5004_mipi__mipi_raw[] = {
{0x18, 0x02},//skip on
LOCAL SENSOR_REG_TAB_INFO_T s_gc5004_mipi_resolution_Tab_RAW[] = {
{ADDR_AND_LEN_OF_ARRAY(gc5004_mipi_common_init), 0, 0, 24, SENSOR_IMAGE_FORMAT_RAW},
{ADDR_AND_LEN_OF_ARRAY(gc5004_mipi__mipi_raw), , 24, SENSOR_IMAGE_FORMAT_RAW},
{ADDR_AND_LEN_OF_ARRAY(gc5004_mipi__mipi_raw), , 24, SENSOR_IMAGE_FORMAT_RAW},
LOCAL SENSOR_TRIM_T s_gc5004_mipi_Resolution_Trim_Tab[] = {
{0, 0, 0, 0, 0, 0, {0, 0, 0, 0}},
{0, 0, , 200, 480, 1000, {0, 0, }},//sysclk*10
{0, 0, , 500, 480, 1972, {0, 0, }},//sysclk*10
LOCAL const SENSOR_REG_T s_gc5004_mipi__video_tab[SENSOR_VIDEO_MODE_MAX][1] = {
/*video mode 0: ?fps*/
{0xff, 0xff}
LOCAL const SENSOR_REG_T s_gc5004_mipi__video_tab[SENSOR_VIDEO_MODE_MAX][1] = {
/*video mode 0: ?fps*/
{0xff, 0xff}
LOCAL SENSOR_VIDEO_INFO_T s_gc5004_mipi_video_info[] = {
{{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, PNULL},
{{{30, 30, 200, 64}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}},(SENSOR_REG_T**)s_gc5004_mipi__video_tab},
{{{15, 15, 500, 64}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}},(SENSOR_REG_T**)s_gc5004_mipi__video_tab},
{{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, PNULL},
LOCAL uint32_t _gc5004_mipi_set_video_mode(uint32_t param)
SENSOR_REG_T_PTR sensor_reg_
if (param &= SENSOR_VIDEO_MODE_MAX)
if (SENSOR_SUCCESS != Sensor_GetMode(&mode)) {
SENSOR_PRINT("fail.");
return SENSOR_FAIL;
if (PNULL == s_gc5004_mipi_video_info[mode].setting_ptr) {
SENSOR_PRINT("fail.");
return SENSOR_FAIL;
sensor_reg_ptr = (SENSOR_REG_T_PTR)&s_gc5004_mipi_video_info[mode].setting_ptr[param];
if (PNULL == sensor_reg_ptr) {
SENSOR_PRINT("fail.");
return SENSOR_FAIL;
for (i=0x00; (0xff!=sensor_reg_ptr[i].reg_addr)||(0xff!=sensor_reg_ptr[i].reg_value); i++) {
Sensor_WriteReg(sensor_reg_ptr[i].reg_addr, sensor_reg_ptr[i].reg_value);
SENSOR_PRINT("0x%02x", param);
LOCAL SENSOR_IOCTL_FUNC_TAB_T s_gc5004_mipi_ioctl_func_tab = {
_gc5004_mipi_PowerOn,
_gc5004_mipi_Identify,
_gc5004_mipi_GetResolutionTrimTab,
_gc5004_mipi_BeforeSnapshot,
_gc5004_mipi_after_snapshot,
PNULL, //_gc5004_mipi_flash,
_gc5004_mipi_write_exposure,
_gc5004_mipi_write_gain,
_gc5004_mipi_write_af,
//对焦函数
PNULL, //_gc5004_mipi_GetExifInfo,
_gc5004_mipi_ExtFunc,
PNULL, //_gc5004_mipi_set_anti_flicker,
_gc5004_mipi_StreamOn,
//打开camera函数
_gc5004_mipi_StreamOff,
//关闭camera函数
SENSOR_INFO_T g_gc5004_mipi_raw_info = {
//外部调用接口
gc5004_mipi_I2C_ADDR_W, // salve i2c write address
gc5004_mipi_I2C_ADDR_R, // salve i2c read address
SENSOR_I2C_REG_8BIT | SENSOR_I2C_REG_8BIT, // bit0: 0: i2c register value is 8 bit, 1: i2c register value is 16 bit
// bit1: 0: i2c register addr
is 8 bit, 1: i2c register addr
// other bit: reseved
SENSOR_HW_SIGNAL_PCLK_N | SENSOR_HW_SIGNAL_VSYNC_N | SENSOR_HW_SIGNAL_HSYNC_P, // bit0: 0: 1:positive -& polarily of pixel clock
// bit2: 0: 1:positive -& polarily of horizontal synchronization signal
// bit4: 0: 1:positive -& polarily of vertical synchronization signal
// other bit: reseved
// preview mode
SENSOR_ENVIROMENT_NORMAL | SENSOR_ENVIROMENT_NIGHT,
// image effect
SENSOR_IMAGE_EFFECT_NORMAL |
SENSOR_IMAGE_EFFECT_BLACKWHITE |
SENSOR_IMAGE_EFFECT_RED |
SENSOR_IMAGE_EFFECT_GREEN |
SENSOR_IMAGE_EFFECT_BLUE |
SENSOR_IMAGE_EFFECT_YELLOW |
SENSOR_IMAGE_EFFECT_NEGATIVE | SENSOR_IMAGE_EFFECT_CANVAS,
// while balance mode
// bit[0:7]: count of step in brightness, contrast, sharpness, saturation
// bit[8:31] reseved
SENSOR_LOW_PULSE_RESET, // reset pulse level
// reset pulse width(ms)
SENSOR_HIGH_LEVEL_PWDN, // 1: 0: low level valid
// count of identify code
{{0xf0, 0x50},
// supply two code to identify sensor.
{0xf1, 0x04}},
// for Example: index = 0-& Device id, index = 1 -& version id
SENSOR_AVDD_2800MV, // voltage of avdd
// max width of source image
// max height of source image
"gc5004_mipi",
// name of sensor
SENSOR_IMAGE_FORMAT_RAW, // define in SENSOR_IMAGE_FORMAT_E enum,SENSOR_IMAGE_FORMAT_MAX
// if set to SENSOR_IMAGE_FORMAT_MAX here, image format depent on SENSOR_REG_TAB_INFO_T
SENSOR_IMAGE_PATTERN_RAWRGB_B,// pattern of inp
s_gc5004_mipi_resolution_Tab_RAW, // point to resolution table information structure
&s_gc5004_mipi_ioctl_func_tab, // point to ioctl function table
&s_gc5004_mipi_raw_info_ptr,
// information and table about Rawrgb sensor
//&g_gc5004_mipi_ext_info,
// extend information about sensor
SENSOR_AVDD_1800MV, // iovdd
SENSOR_AVDD_1500MV, // dvdd
// skip frame num before preview
打开camera到预览跳过得帧数
// skip frame num before capture
打开camera拍照览跳过得帧数
// deci frame num during preview
// deci frame num during video preview
{SENSOR_INTERFACE_TYPE_CSI2, 2, 10, 0},
s_gc5004_mipi_video_info,
// skip frame num while change setting
LOCAL struct sensor_raw_info* Sensor_GetContext(void)
return s_gc5004_mipi_raw_info_
LOCAL uint32_t Sensor_gc5004_mipi_InitRawTuneInfo(void)
uint32_t rtn=0x00;
struct sensor_raw_info* raw_sensor_ptr=Sensor_GetContext();
struct sensor_raw_tune_info* sensor_ptr=raw_sensor_ptr-&tune_
struct sensor_raw_cali_info* cali_ptr=raw_sensor_ptr-&cali_
raw_sensor_ptr-&version_info-&version_id=0x;
raw_sensor_ptr-&version_info-&srtuct_size=sizeof(struct sensor_raw_info);
LOCAL uint32_t _gc5004_mipi_GetResolutionTrimTab(uint32_t param)
SENSOR_PRINT("0x%x",
(uint32_t)s_gc5004_mipi_Resolution_Trim_Tab);
return (uint32_t) s_gc5004_mipi_Resolution_Trim_T
LOCAL uint32_t _gc5004_mipi_PowerOn(uint32_t power_on)
/*上电函数*/
SENSOR_AVDD_VAL_E dvdd_val = g_gc5004_mipi_raw_info.dvdd_
SENSOR_AVDD_VAL_E avdd_val = g_gc5004_mipi_raw_info.avdd_
SENSOR_AVDD_VAL_E iovdd_val = g_gc5004_mipi_raw_info.iovdd_
BOOLEAN power_down = g_gc5004_mipi_raw_info.power_down_
BOOLEAN reset_level = g_gc5004_mipi_raw_info.reset_pulse_
if (SENSOR_TRUE == power_on) {//上电时序
Sensor_PowerDown(power_down);
// Open power
Sensor_SetMonitorVoltage(SENSOR_AVDD_2800MV);
Sensor_SetVoltage(dvdd_val, avdd_val, iovdd_val);
Sensor_SetMonitorVoltage(SENSOR_AVDD_2800MV);
usleep(20*1000);
_dw9174_SRCInit(2);
Sensor_SetMCLK(SENSOR_DEFALUT_MCLK);
usleep(10*1000);
Sensor_PowerDown(!power_down);
// Reset sensor
Sensor_Reset(reset_level);
usleep(10*1000);
Sensor_PowerDown(power_down);
Sensor_SetMCLK(SENSOR_DISABLE_MCLK);
Sensor_SetVoltage(SENSOR_AVDD_CLOSED, SENSOR_AVDD_CLOSED, SENSOR_AVDD_CLOSED);
Sensor_SetMonitorVoltage(SENSOR_AVDD_CLOSED);
SENSOR_PRINT("SENSOR_gc5004_mipi: _gc5004_mipi_Power_On(1:on, 0:off): %d", power_on);
return SENSOR_SUCCESS;
LOCAL uint32_t _gc5004_mipi_cfg_otp(uint32_t
uint32_t rtn=SENSOR_SUCCESS;
struct raw_param_info_tab* tab_ptr = (struct raw_param_info_tab*)s_gc5004_mipi_raw_param_
uint32_t module_id=g_module_
SENSOR_PRINT("SENSOR_gc5004_mipi: _gc5004_mipi_cfg_otp");
if(PNULL!=tab_ptr[module_id].cfg_otp){
tab_ptr[module_id].cfg_otp(0);
LOCAL uint32_t _gc5004_mipi_com_Identify_otp(void* param_ptr)
uint32_t rtn=SENSOR_FAIL;
uint32_t param_
SENSOR_PRINT("SENSOR_gc5004_mipi: _gc5004_mipi_com_Identify_otp1111");
/*read param id from sensor omap*/
param_id=gc5004_mipi_RAW_PARAM_COM;
if(gc5004_mipi_RAW_PARAM_COM==param_id){
rtn=SENSOR_SUCCESS ;
rtn=SENSOR_SUCCESS ;
LOCAL uint32_t _gc5004_mipi_GetRawInof(void)
uint32_t rtn=SENSOR_SUCCESS;
struct raw_param_info_tab* tab_ptr = (struct raw_param_info_tab*)s_gc5004_mipi_raw_param_
uint32_t param_
uint32_t i=0x00;
/*read param id from sensor omap*/
param_id=gc5004_mipi_RAW_PARAM_COM;
for(i=0x00; ; i++)
g_module_id =
if(RAW_INFO_END_ID==tab_ptr[i].param_id){
if(NULL==s_gc5004_mipi_raw_info_ptr){
SENSOR_PRINT("SENSOR_gc5004_mipi: ov5647_GetRawInof no param error");
rtn=SENSOR_FAIL;
SENSOR_PRINT("SENSOR_gc5004_mipi: gc5004_mipi_GetRawInof end");
else if(PNULL!=tab_ptr[i].identify_otp){
if(SENSOR_SUCCESS==tab_ptr[i].identify_otp(0))
s_gc5004_mipi_raw_info_ptr = tab_ptr[i].info_
SENSOR_PRINT("SENSOR_gc5004_mipi: gc5004_mipi_GetRawInof success");
LOCAL uint32_t _gc5004_mipi_GetMaxFrameLine(uint32_t index)
uint32_t max_line=0x00;
SENSOR_TRIM_T_PTR trim_ptr=s_gc5004_mipi_Resolution_Trim_T
max_line=trim_ptr[index].frame_
return max_
LOCAL uint32_t _gc5004_mipi_Identify(uint32_t param)
#define gc5004_mipi_PID_VALUE
#define gc5004_mipi_PID_ADDR
#define gc5004_mipi_VER_VALUE
#define gc5004_mipi_VER_ADDR
uint8_t pid_value = 0x00;
uint8_t ver_value = 0x00;
uint32_t ret_value = SENSOR_FAIL;
SENSOR_PRINT("SENSOR_gc5004_mipi: mipi raw identify\n");
pid_value = Sensor_ReadReg(gc5004_mipi_PID_ADDR);
if (gc5004_mipi_PID_VALUE == pid_value) {
ver_value = Sensor_ReadReg(gc5004_mipi_VER_ADDR);//读取ID
SENSOR_PRINT("SENSOR_gc5004_mipi: Identify: PID = %x, VER = %x", pid_value, ver_value);
if (gc5004_mipi_VER_VALUE == ver_value) {
//判断读取的id是否正确
ret_value=_gc5004_mipi_GetRawInof();
Sensor_gc5004_mipi_InitRawTuneInfo();
ret_value = SENSOR_SUCCESS;
SENSOR_PRINT("SENSOR_gc5004_mipi: this is gc5004_mipi sensor !");
SENSOR_PRINT
("SENSOR_gc5004_mipi: Identify this is GC%x%x sensor !", pid_value, ver_value);
SENSOR_PRINT("SENSOR_gc5004_mipi: identify fail,pid_value=%x", pid_value);
return ret_//返回ID是否读取正确
LOCAL uint32_t _gc5004_mipi_write_exposure(uint32_t param)
uint32_t ret_value = SENSOR_SUCCESS;
uint16_t expsure_line=0x00;
uint16_t dummy_line=0x00;
uint16_t shutter_temp=0x00;
SENSOR_PRINT("gc5004_mipi_Write_line
= %d \n",param);
expsure_line=param&0
dummy_line=(param&&0x10)&0
SENSOR_PRINT("gc5004_mipi_Write_line
dummy_line
= %d \n",dummy_line );
if (!expsure_line) expsure_line = 4; /* avoid 0 */
if(expsure_line & 4) expsure_line = 4;
if(expsure_line & 8191) expsure_line = 8191;//2
//Update Shutter
expsure_line = expsure_line/4;
expsure_line = expsure_line*4;
shutter_temp = expsure_line%4;
if(shutter_temp &2)
expsure_line+=4;
SENSOR_PRINT("gc5004_mipi_Write_line
= %d \n",expsure_line);
ret_value = Sensor_WriteReg(0x04, (expsure_line) & 0xFF);
ret_value = Sensor_WriteReg(0x03, (expsure_line && 8) & 0x1F);
return ret_
LOCAL uint32_t _gc5004_mipi_write_gain(uint32_t param)
uint32_t ret_value = SENSOR_SUCCESS;
uint16_t temp=0x00;
uint32_t real_gain = 0;
SENSOR_PRINT("_gc5004_mipi raw _write_gain param = %d
\n",param);
real_gain = ((param&0xf)+16)*(((param&&4)&0x01)+1)*(((param&&5)&0x01)+1)*(((param&&6)&0x01)+1)*(((param&&7)&0x01)+1);
real_gain = real_gain*(((param&&8)&0x01)+1)*(((param&&9)&0x01)+1)*(((param&&10)&0x01)+1)*(((param&&11)&0x01)+1);
real_gain &&= 2;
SENSOR_PRINT("_gc5004_mipi raw _write_gain real_gain = %d
\n",real_gain);
Sensor_WriteReg(0xfe, 0x00);
Sensor_WriteReg(0xb6, 0x00);
Sensor_WriteReg(0xb1, 0x01);
Sensor_WriteReg(0xb2, 0x00);
if(real_gain & 64)
real_gain = 64;
Sensor_WriteReg(0xb6, 0x00);
Sensor_WriteReg(0xb1, 0x01);
Sensor_WriteReg(0xb2, 0x00);
else if ((64 &= real_gain)&(real_gain & 90))
Sensor_WriteReg(0xb6, 0x00);
temp = real_
SENSOR_PRINT("_gc5004_mipi_write_gain_1 temp = %d
\n",temp);
Sensor_WriteReg(0xb1, temp&&6);
Sensor_WriteReg(0xb2, (temp&&2)&0xfc);
else if ((90 &= real_gain)&(real_gain & 128))
Sensor_WriteReg(0xb6, 0x01);
temp = 64*real_gain/90;
SENSOR_PRINT("_gc5004_mipi_write_gain_2 temp = %d
\n",temp);
Sensor_WriteReg(0xb1, temp&&6);
Sensor_WriteReg(0xb2, (temp&&2)&0xfc);
else if ((128 &= real_gain)&(real_gain & 178))
Sensor_WriteReg(0xb6, 0x02);
temp = 64*real_gain/128;
SENSOR_PRINT("_gc5004_mipi_write_gain_3 temp = %d
\n",temp);
Sensor_WriteReg(0xb1, temp&&6);
Sensor_WriteReg(0xb2, (temp&&2)&0xfc);
else if ((178 &= real_gain)&(real_gain & 247))
Sensor_WriteReg(0xb6, 0x03);
temp = 64*real_gain/178;
SENSOR_PRINT("_gc5004_mipi_write_gain_4 temp = %d
\n",temp);
Sensor_WriteReg(0xb1, temp&&6);
Sensor_WriteReg(0xb2, (temp&&2)&0xfc);
else if (247 &= real_gain)
Sensor_WriteReg(0xb6, 0x04);
temp = 64*real_gain/247;
SENSOR_PRINT("_gc5004_mipi_write_gain_5 temp = %d
\n",temp);
Sensor_WriteReg(0xb1, temp&&6);
Sensor_WriteReg(0xb2, (temp&&2)&0xfc);
return ret_
LOCAL uint32_t _gc5004_mipi_write_af(uint32_t param)
uint32_t ret_value = SENSOR_SUCCESS;
slave_addr = DW9714_VCM_SLAVE_ADDR;
uint16_t cmd_len = 0;
uint8_t cmd_val[2] = {0x00};
cmd_val[0] = ((param&0xfff0)&&4) & 0x3f;
cmd_val[1] = ((param&0x0f)&&4) & 0xf0;
cmd_len = 2;
ret_value = Sensor_WriteI2C(slave_addr,(uint8_t*)&cmd_val[0], cmd_len);
SENSOR_PRINT("SENSOR_Gc5004: _write_af, ret =
%d, param = %d,
MSL:%x, LSL:%x\n",
ret_value, param, cmd_val[0], cmd_val[1]);
return ret_
LOCAL uint32_t _gc5004_mipi_PreBeforeSnapshot(uint32_t param)
cap_shutter,prv_
uint32_t shutter_h,shutter_l,
SENSOR_PRINT("_gc5004_mipi_PreBeforeSnapshot param :%d",param);
if(SENSOR_MODE_PREVIEW_ONE&= param){
SENSOR_PRINT("SENSOR_gc5004_mipi:preview equal to capture");
return SENSOR_SUCCESS;
shutter_l = (uint8_t)Sensor_ReadReg(0x04);
shutter_h = (uint8_t)Sensor_ReadReg(0x03);
shutter = ((shutter_h&&8)&0x1F00)|(shutter_l&0xFF);
SENSOR_PRINT("SENSOR_gc5004_mipi_PreBeforeSnapshot prv_shutter = %d",shutter);
prv_shutter =
Sensor_SetMode(param);
cap_shutter = shutter*2/5;
SENSOR_PRINT("SENSOR_gc5004_mipi_PreBeforeSnapshot cap_shutter = %d",cap_shutter);
if(!cap_shutter)cap_shutter=1;
if(cap_shutter&1)cap_shutter=1;
if(cap_shutter&8191)cap_shutter=8191;
Sensor_WriteReg(0x04,cap_shutter&0xFF);
Sensor_WriteReg(0x03,(cap_shutter&&8)&0x1F);
usleep(100*1000);
//Sensor_StreamOff();
return SENSOR_SUCCESS;
LOCAL uint32_t _gc5004_mipi_BeforeSnapshot(uint32_t param)
uint32_t cap_mode = (param && CAP_MODE_BITS);
uint32_t rtn = SENSOR_SUCCESS;
param = param & 0
rtn = _gc5004_mipi_PreBeforeSnapshot(param);
SENSOR_PRINT("_gc5004_mipi_BeforeSnapshot+++++++++++++++++ param = %d",param);
LOCAL uint32_t _gc5004_mipi_after_snapshot(uint32_t param)
SENSOR_PRINT("SENSOR_gc5004_mipi: after_snapshot mode:%d", param);
Sensor_SetMode(param);
return SENSOR_SUCCESS;
LOCAL uint32_t _gc5004_mipi_flash(uint32_t param)
SENSOR_PRINT("SENSOR_gc5004_mipi: param=%d", param);
g_flash_mode_en =
Sensor_SetFlash(param);
SENSOR_PRINT_HIGH("end");
return SENSOR_SUCCESS;
LOCAL uint32_t _gc5004_mipi_StreamOn(uint32_t param)
SENSOR_PRINT("SENSOR_gc5004_mipi: StreamOn");
usleep(50*1000);
Sensor_WriteReg(0xfe, 0x03);
Sensor_WriteReg(0x10, 0x91);
Sensor_WriteReg(0xfe, 0x00);
usleep(50*1000);
LOCAL uint32_t _gc5004_mipi_StreamOff(uint32_t param)
SENSOR_PRINT("SENSOR_gc5004_mipi: StreamOff");
usleep(50*1000);
Sensor_WriteReg(0xfe, 0x03);
Sensor_WriteReg(0x10, 0x81);
Sensor_WriteReg(0xfe, 0x00);
usleep(50*1000);
static uint32_t _gc5004_mipi_SetEV(uint32_t param)
uint32_t rtn = SENSOR_SUCCESS;
LOCAL uint32_t _gc5004_mipi_ExtFunc(uint32_t ctl_param)
uint32_t rtn = SENSOR_SUCCESS;
SENSOR_EXT_FUN_PARAM_T_PTR ext_ptr =
(SENSOR_EXT_FUN_PARAM_T_PTR) ctl_
SENSOR_PRINT_HIGH("0x%x", ext_ptr-&cmd);
switch (ext_ptr-&cmd) {
case SENSOR_EXT_FUNC_INIT:
case SENSOR_EXT_FOCUS_START:
case SENSOR_EXT_EXPOSURE_START:
case SENSOR_EXT_EV:
rtn = _gc5004_mipi_SetEV(ctl_param);
LOCAL uint32_t _dw9174_SRCInit(uint32_t mode)
uint8_t cmd_val[2] = {0x00};
slave_addr = 0;
uint16_t cmd_len = 0;
uint32_t ret_value = SENSOR_SUCCESS;
int i = 0;
slave_addr = DW9714_VCM_SLAVE_ADDR;
SENSOR_PRINT("SENSOR_Gc5004: _DW9714A_SRCInit: mode = %d\n", mode);
switch (mode) {
cmd_val[0] = 0
cmd_val[1] = 0xa3;
cmd_len = 2;
ret_value = Sensor_WriteI2C(slave_addr,(uint8_t*)&cmd_val[0], cmd_len);
cmd_val[0] = 0xa1;
cmd_val[1] = 0x0e;
cmd_len = 2;
ret_value = Sensor_WriteI2C(slave_addr,(uint8_t*)&cmd_val[0], cmd_len);
cmd_val[0] = 0xf2;
cmd_val[1] = 0x90;
cmd_len = 2;
ret_value = Sensor_WriteI2C(slave_addr,(uint8_t*)&cmd_val[0], cmd_len);
cmd_val[0] = 0
cmd_val[1] = 0x51;
cmd_len = 2;
ret_value = Sensor_WriteI2C(slave_addr,(uint8_t*)&cmd_val[0], cmd_len);
return ret_
LOCAL uint32_t _gc5004_mipi_ReadGain(uint32_t param)
uint32_t rtn = SENSOR_SUCCESS;
没有更多推荐了,Bmob平台为您的移动应用提供了一个完整的后端解决方案,我们提供轻量级的SDK开发包,让开发者以最小的配置和最简单的方式使用Bmob平台提供的服务,进而完全消除开发者编写服务器代码以及维护服务器的操作。快速入门
建议您在阅读本开发文档之前,先阅读我们提供的 ,便于您后续的开发。SDK导入
Android Studio配置
鉴于目前Google官方推荐使用 Android Studio 进行Android项目开发,自 V3.4.2 开始,Bmob Android SDK 可以使用Gradle来进行包依赖管理,如果你使用Android Studio来进行基于BmobSDK的项目开发,请按照如下两个步骤进行:一、 在Project的build.gradle文件中添加Bmob的maven仓库地址,示例如下:(注意文字说明部分):
buildscript {
repositories {
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
allprojects {
repositories {
//Bmob的maven仓库地址,必须填写
maven { url &https://raw.github.com/bmob/bmob-android-sdk/master& }
二、 在app的build.gradle文件中添加compile依赖文件,示例如下:(注意文字说明部分):
apply plugin: 'com.android.application'
compileSdkVersion 22
buildToolsVersion '22.0.1'
//**兼容Android6.0系统所需,如果这句话报错,可在dependencies标签下使用compile 'cn.bmob.android:http-legacy:1.0'**
useLibrary 'org.apache.http.legacy'
defaultConfig {
applicationId &cn.bmob.android&
minSdkVersion 14
targetSdkVersion 22
versionCode 1
versionName &1.0&
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
//以下SDK开发者请根据需要自行选择
//bmob-sdk:Bmob的android sdk包,包含了Bmob的数据存储、文件等服务,以下是最新的bmob-sdk:
//3.4.7-aar:具务必查看下面注释[1]
compile 'cn.bmob.android:bmob-sdk:3.4.7-aar'
//bmob-push:Bmob的推送包
compile 'cn.bmob.android:bmob-push:0.8'
//bmob-im:Bmob的即时通讯包,注意每个版本的im依赖特定版本的bmob-sdk,具体的依赖关系可查看下面注释[3]
compile 'cn.bmob.android:bmob-im:2.0.4'
compile 'cn.bmob.android:androidasync:2.1.6'
compile 'cn.bmob.android:bmob-sdk:3.4.6'
//注:别忘记导入3.4.6的相关依赖包[2]
//bmob-sms :Bmob单独为短信服务提供的包
compile 'cn.bmob.android:bmob-sms:1.0.1'
//如果你想应用能够兼容Android6.0,请添加此依赖(org.apache.http.legacy.jar)
compile 'cn.bmob.android:http-legacy:1.0'
注:[1]、为了降低开发者的使用成本,现提供3.4.7-aar,此aar包含libbmob.so、okhttp、okio及自动更新组件所需要的资源文件。开发者再也不需要配置libbmob.so,不需要添加okhttp、okio,也不需要复制自动更新组件的资源文件啦,只需要添加以下依赖即可。compile 'cn.bmob.android:bmob-sdk:3.4.7-aar'
注:由于PermissionManager权限管理类需要依赖support-v4:23.2.1的jar包,导致开发者认为SDK依赖文件较多,故分离出SDK。开发者如果需要兼容Android6.0系统,可以在下载的SDK的官方Demo的com.example.bmobexample.permission包下面查看该类源码。[2]、bmob-sdk:3.4.6依赖以下包:compile 'cn.bmob.android:bmob-sdk:3.4.6'
compile 'com.squareup.okhttp:okhttp:2.4.0'//CDN文件服务使用okhttp相关包进行文件的上传和下载(必填)
compile 'com.squareup.okio:okio:1.4.0'
如果需要兼容Android6.0系统,请添加以下两项:compile 'com.android.support:support-v4:23.2.1'
compile 'cn.bmob.android:http-legacy:1.0'
[3]、每个版本的im依赖特定版本的bmob-sdk:
bmob-im:1.1.8---&bmob-sdk:3.3.5
bmob-im:1.1.9---&bmob-sdk:3.4.3
bmob-im:2.0.1---&bmob-sdk:3.4.6-0304
bmob-im:2.0.2---&bmob-sdk:3.4.6-0304
bmob-im:2.0.3---&bmob-sdk:3.4.6
bmob-im:2.0.4---&bmob-sdk:3.4.6
其中bmob-sdk:3.4.6-0304是Bmob Android SDK的过渡版本,主要用于NewIM_v2.0.1及v2.0.2。
[4]、bmob-sms适用于只需要使用Bmob短信功能的开发者,而bmob-sdk内部包含了bmob-sms的短信功能,请不要重复添加。[5]、BmobSDK的官方仓库:,开发者可到此仓库查看最新发布的各版本SDK,我们会尽量与官网发布的SDK保持同步更新。Eclipse导入
找到对应SDK下载之后,在Eclipse工程的项目根目录中新建libs文件夹,将下载的jar包添加到此文件夹即可。注:1、若配置不成功,则需要额外增加以下步骤:右键工程根目录,选择Properties -& Java Build Path -& Libraries,然后点击Add External JARs... 选择指向该libs文件夹下的jar的路径,点击OK即可。2、BmobSDK_v3.4.7需要依赖okhttp3(3.2.0)、okio(1.7.0)及libbmob.so库,so库的导入方式是把下载后的libs文件夹中的各种so文件拷贝到项目中的libs文件夹下。3、BmobSDK_v3.4.6需要依赖okhttp(2.4.0)、okio(1.4.0),如果需要兼容Android6.0系统,则还需要添加support-v4(23.2.1)及org.apache.http.legacy依赖包。兼容Android6.0
自v3.4.6版本开始,Bmob提供了一些新的方法和工具类来帮助开发者为自己的应用兼容Android6.0系统。配置org.apache.http.legacy
Android6.0版本移除了对Appache的HTTP client的支持,因此,需要添加org.apache.http.legacy.jar包,请参照如下方式添加:
Eclipse 你需要在Eclipse工程的项目根目录中新建libs文件夹,将org.apache.http.legacy.jar包,添加到libs文件夹中
AndroidStudio 你需要在app的build.gradle文件添加配置信息useLibrary 'org.apache.http.legacy'声明编译时依赖 android { compileSdkVersion 23
buildToolsVersion &23.0.2&
useLibrary 'org.apache.http.legacy'
注:如果在build.gradle文件中useLibrary 'org.apache.http.legacy'这句话报错,可将该jar直接放到libs目录下即可。运行时权限管理
Android6.0中对特定的权限进行了动态授权的方式,需要在运行时用户手动授予,如果用户拒绝后再次申请还可以向用户弹框说明权限的作用,用户点击确认后再去申请。因此,我们提供了一个权限管理的工具类PermissionManager(cn.bmob.v3.helper),具体使用如下:注:在v3.4.6的BmobSDK内部集成PermissionManager类,自v3.4.7以后的SDK内部将不再提供该类,开发者可以在下载的配套官方Demo的com.example.bmobexample.permission包下面查看该类源码。1.构建PermissionManager对象PermissionM
helper = PermissionManager.with(MainActivity.this)
//添加权限请求码
.addRequestCode(MainActivity.REQUEST_CODE_CAMERA)
//设置权限,可以添加多个权限
.permissions(Manifest.permission.CAMERA)
//设置权限监听器
.setPermissionsListener(new PermissionListener() {
public void onGranted() {
//当权限被授予时调用
Toast.makeText(MainActivity.this, &Camera Permission granted&,Toast.LENGTH_LONG).show();
public void onDenied() {
//用户拒绝该权限时调用
Toast.makeText(MainActivity.this, &Camera Permission denied&,Toast.LENGTH_LONG).show();
public void onShowRationale(String[] permissions) {
//当用户拒绝某权限时并点击`不再提醒`的按钮时,下次应用再请求该权限时,需要给出合适的响应(比如,给个展示对话框来解释应用为什么需要该权限)
Snackbar.make(btn_camera, &需要相机权限去拍照&, Snackbar.LENGTH_INDEFINITE)
.setAction(&ok&, new View.OnClickListener() {
public void onClick(View v) {
//必须调用该`setIsPositive(true)`方法
helper.setIsPositive(true);
helper.request();
}).show();
//请求权限
.request();
with方法可以传入Activity或者Fragment;
addRequestCode方法传入请求码,用于区分各种不同的权限申请;
permissions方法传入的是你所要请求的权限,支持可变参数,可以批量申请权限;
PermissionListener接口回调的三个方法:
onGranted()会在权限申请通过后被调用;
onDenied()在权限申请被拒绝时被调用
onShowRationale()方法中你可以弹对话框向用户解释权限的作用,不过记得要调用setIsPositive(true)。
request方法用来请求权限申请
2.覆写onRequestPermissionsResult方法@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_CODE_CAMERA:
helper.onPermissionResult(permissions, grantResults);
Notification变更
Android6.0中,Notification.setLatestEventInfo()方法被移除,替代的方案是用Notification.Builder来构建通知,对此SDK提供了NotificationCompat(cn.bmob.v3.helper)类来做版本兼容(与android.support.v4.app包下的NotificationCompat用法一样)。参照代码如下:NotificationManager notificationManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent pi = PendingIntent.getActivity(mContext, 0,
new Intent(MainActivity.this, MainActivity.class), 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext)
.setTicker(&更新啦&)
.setContentTitle(&标题&)
.setContentText(&内容&)
.setSmallIcon(R.drawable.ic_launcher);
Notification notification = builder.build();
notificationManager.notify(0, notification);
一个数据对象(APP中创建的BmobObject类的子类)对应于Bmob后台的一个数据表。数据对象
Bmob存储的数据是建立在BmobObject基础上的,所以任何要保存的数据对象必须继承自BmobObject类。BmobObject类本身包含objectId、createdAt、updatedAt、ACL四个默认的属性,objectId是数据的唯一标示,相当于数据库中表的主键,createdAt是数据的创建时间,updatedAt是数据的最后修改时间,ACL是数据的操作权限。如,你的游戏中使用GameScore表来记录玩家的比分信息,其中表的字段有:score(分数)、playerName(玩家名字)、isPay(是否付费玩家)、pic(玩家头像)属性,那么这个数据对象为如下定义://必须要继承自BmobObject类
public class GameScore extends BmobObject{
private String playerN
private Boolean isP
private BmobF
public String getPlayerName() {
return playerN
public void setPlayerName(String playerName) {
this.playerName = playerN
public Integer getScore() {
public void setScore(Integer score) {
this.score =
public Boolean getIsPay() {
return isP
public void setIsPay(Boolean isPay) {
this. isPay = isP
public BmobFile getPic() {
public void setPic(BmobFile pic) {
this.pic =
需要注意的是:
JavaBean不需要对objectId、createdAt、updatedAt、ACL四个属性进行定义。
不少开发者会没有注意到createdAt和updatedAt属性中的字母d,写成createAt和updateAt。
尽可能使用Integer、Boolean,而不是int、boolean,也就是选择包装类,而不是使用基本数据类型(这两者的区别大家可以看这篇文章:
为了提供更好的服务,BmobSDK中提供了BmobUser、BmobInstallation、BmobRole三个特殊的BmobObject对象来完成不同的功能,在这里我们统一称为特殊对象。
BmobUser对象主要是针对应用中的用户功能而提供的,它对应着web端的User表,使用BmobUser对象可以很方便的在应用中实现用户的注册、登录、邮箱验证等功能,具体的使用方法可查看文档的部分。
BmobInstallation对象主要用于应用的安装设备管理中,它对应着web端的Installation表,任何安装了你应用的设备都会在此表中产生一条数据标示该设备。结合Bmob提供的推送功能,还可以实现将自定义的消息推送给不同的设备终端,具体的使用方法可查看文档的部分。
BmobRole对象主要用于角色管理,对应用于Web端的Role表,具体的使用方法可查看文档的部分。
目前为止,Bmob支持的数据类型:String、Integer、Float、Short、Byte、Double、Character、Boolean、Object、Array。同时也支持BmobObject、BmobDate、BmobGeoPoint、BmobFile特有的数据类型。以下为Web端类型与SDK端支持的JAVA类型对应表:
支持的JAVA类型
Integer、Float、Short、Byte、Double、Character
对应数据库的Number类型
Bmob特有类型,用来标识文件类型
BmobGeoPoint
Bmob特有类型,用来标识地理位置
Bmob特有类型,用来标识日期类型
Bmob特有类型,用来标识指针类型
BmobRelation
Bmob特有类型,用来标识数据关联
注:1、不能使用int、float、short byte、double、character等基本数据类型。类名和表名的关系
Bmob官方推荐类名和表名完全一致的映射使用方式, 即如,上面的GameScore类,它在后台对应的表名也是GameScore(区分大小写)。
如果你希望表名和类名并不相同,如表名为T_a_b,而类名还是GameScore,那么你可以使用BmobObject提供的setTableName(&表名&)的方法,示例代码如下://这时候实际操作的表是T_a_b
public class GameScore extends BmobObject{
private String playerN
private Boolean isP
private BmobF
public GameScore() {
this.setTableName(&T_a_b&);
public String getPlayerName() {
return playerN
//其他方法,见上面的代码
当然了,除了在构造函数中直接调用setTableName方法之外,你还可以在GameScore的实例中动态调用setTableName方法。
查询自定义表名的数据
如果您使用了setTableName方法来自定义表名,那么在对该表进行数据查询的时候必须使用以下方法。需要注意的是查询的结果是JSONArray,需要自行解析JSONArray中的数据。/**
* 查询数据
public void queryData(){
BmobQuery query = new BmobQuery(&T_a_b&);
query.findObjects(this, new FindCallback() {
public void onSuccess(JSONArray arg0) {
//注意:查询的结果是JSONArray,需要自行解析
showToast(&查询成功:&+arg0.length());
public void onFailure(int arg0, String arg1) {
showToast(&查询失败:&+arg1);
自定义表名情况下的更新、删除数据和普通的更新、删除数据方式一样,没有变化。为方便大家了解学习,我们提供了一个关于自定义表名情况下增删改查数据的Demo,下载地址是:。添加数据
添加数据使用BmobObject对象的save方法,就可以将当前对象的内容保存到Bmob服务端。例如,你现在要保存一条游戏分数的记录,代码如下:GameScore gameScore = new GameScore();
//注意:不能调用gameScore.setObjectId(&&)方法
gameScore.setPlayerName(&比目&);
gameScore.setScore(89);
gameScore.setIsPay(false);
gameScore.save(mContext, new SaveListener() {
public void onSuccess() {
toast(&添加数据成功,返回objectId为:&+gameScore.getObjectId() + ”,数据在服务端的创建时间为:“ + gameScore.getCreatedAt());
public void onFailure(int code, String arg0) {
// 添加失败
运行以上代码,如果添加成功,你可以在Bmob提供的后台的数据浏览中看到类似这样的结果:objectId: &0c6db13c&, score: 89, playerName: &比目&, isPay: false,createdAt:& 10:32:54&, updatedAt:& 10:32:54&
这里需要注意的是:
如果服务器端不存在GameScore表,那么系统将自动建表,并插入数据。
如果服务器端已经存在GameScore表,和相应的score、playerName、isPay字段,那么你此时添加的数据和数据类型也应该和服务器端的表结构一致,否则会保存数据失败。
每个BmobObject对象都有几个默认的键(数据列)是不需要开发者指定的,objectId是每个保存成功数据的唯一标识符。createdAt和updatedAt代表每个对象(每条数据)在服务器上创建和最后修改的时间。这些键(数据列)的创建和数据内容是由服务器端自主来完成的。因此,使用save和insert方法时,不需要调用setObjectId方法,否则会出现提示:“It is a reserved field: objectId(105)”--表明objectId为系统保留字段,不允许修改。。
更新一个对象也是非常简单。例如:将GameScore表中objectId为0c6db13c的游戏分数修改为77.GameScore gameScore = new GameScore();
gameScore.setScore(77);
gameScore.update(this, &0c6db13c&, new UpdateListener() {
public void onSuccess() {
// TODO Auto-generated method stub
Log.i(&bmob&,&更新成功:&);
public void onFailure(int code, String msg) {
// TODO Auto-generated method stub
Log.i(&bmob&,&更新失败:&+msg);
自V3.4.4版本开始,SDK提供了另一种方法来更新数据,通过调用Bmobobject类中的setValue(key,value)方法,只需要传入key及想要更新的值即可举例,说明如下:public class Person extends BmobObject {
private BmobU
//BmobObject类型
private BankC
//Object类型
//Integer类型
private B //Boolean类型
getter、setter方法
其中BankCard类结构如下:
public class BankCard{
private String cardN
private String bankN
public BankCard(String bankName, String cardNumber){
this.bankName = bankN
this.cardNumber = cardN
getter、setter方法
Person p2=new Person();
//更新BmobObject的值
p2.setValue(&user&, BmobUser.getCurrentUser(this, MyUser.class));
//更新Object对象
p2.setValue(&bankCard&,new BankCard(&农行&, &农行账号&));
//更新Object对象的值
//p2.setValue(&bankCard.bankName&,&建行&);
//更新Integer类型
//p2.setValue(&age&,11);
//更新Boolean类型
//p2.setValue(&gender&, true);
p2.update(this, objectId, new UpdateListener() {
public void onSuccess() {
// TODO Auto-generated method stub
Log.i(&bmob&,&更新成功:&);
public void onFailure(int code, String msg) {
// TODO Auto-generated method stub
Log.i(&bmob&,&更新失败:&+msg);
注意:修改数据只能通过objectId来修改,目前不提供查询条件方式的修改方法。原子计数器
很多应用可能会有计数器功能的需求,比如文章点赞的功能,如果大量用户并发操作,用普通的更新方法操作的话,会存在数据不一致的情况。为此,Bmob提供了原子计数器来保证原子性的修改某一数值字段的值。注意:原子计数器只能对应用于Web后台的Number类型的字段,即JavaBeans数据对象中的Integer对象类型(不要用int类型)。gameScore.increment(&score&); // 分数递增1
gameScore.update(this, updateListener);
您还可以通过increment(key, amount)方法来递增或递减任意幅度的数字gameScore.increment(&score&, 5); // 分数递增5
//gameScore.increment(&score&, -5); // 分数递减5
gameScore.update(this, updateListener);
从服务器删除对象。例如:将GameScore表中objectId为dd8e6aff28的数据删除。GameScore gameScore = new GameScore();
gameScore.setObjectId(&dd8e6aff28&);
gameScore.delete(this, new DeleteListener() {
public void onSuccess() {
// TODO Auto-generated method stub
Log.i(&bmob&,&删除成功&);
public void onFailure(int code, String msg) {
// TODO Auto-generated method stub
Log.i(&bmob&,&删除失败:&+msg);
注意:删除数据只能通过objectId来删除,目前不提供查询条件方式的删除方法。删除字段的值
你可以在一个对象中删除一个字段的值,通过remove操作:GameScore gameScore = new GameScore();
gameScore.setObjectId(&dd8e6aff28&);
gameScore.remove(&score&);
// 删除GameScore对象中的score字段
gameScore.update(this, new UpdateListener() {
public void onSuccess() {
// TODO Auto-generated method stub
Log.i(&bmob&,&删除GameScore对象中的score字段成功&);
public void onFailure(int code, String msg) {
// TODO Auto-generated method stub
Log.i(&bmob&,&删除GameScore对象中的score字段失败:&+msg);
批量数据操作
在BmobObject对象中提供了三种用于批量操作的方法,分别是insertBatch、updateBatch、deleteBatch,批量添加、更新、删除。
insertBatch的使用方式如下:
List&BmobObject& persons = new ArrayList&BmobObject&();
for (int i = 0; i & 3; i++) {
Person person = new Person();
person.setName(&张三 &+i);
person.setAddress(&上海朝阳路&+i+&号&);
person.setGpsAdd(new BmobGeoPoint(112..52065));
person.setUploadTime(new BmobDate(new Date()));
List&String& hobbys = new ArrayList&String&();
hobbys.add(&阅读&);
hobbys.add(&篮球&);
hobbys.add(&唱歌&);
person.setHobby(hobbys);
person.setBankCard(new BankCard(&中国银行&, &545097&+i));
persons.add(person);
new BmobObject().insertBatch(this, persons, new SaveListener() {
public void onSuccess() {
// TODO Auto-generated method stub
toast(&批量添加成功&);
public void onFailure(int code, String msg) {
// TODO Auto-generated method stub
toast(&批量添加失败:&+msg);
updateBatch的使用方式如下:
List&BmobObject& persons = new ArrayList&BmobObject&();
Person p1 = new Person();
p1.setObjectId(&e51d651c22&);
p1.setAge(25);
Person p2 = new Person();
p2.setObjectId(&3f70a922c4&);
p2.setAge(26);
p2.setGender(false);
Person p3 = new Person();
p3.setObjectId(&08fdd55765&);
p3.setAge(27);
persons.add(p1);
persons.add(p2);
persons.add(p3);
new BmobObject().updateBatch(this, persons, new UpdateListener() {
public void onSuccess() {
// TODO Auto-generated method stub
toast(&批量更新成功&);
public void onFailure(int code, String msg) {
// TODO Auto-generated method stub
toast(&批量更新失败:&+msg);
deleteBatch的使用方式如下:
List&BmobObject& persons = new ArrayList&BmobObject&();
Person p1 = new Person();
p1.setObjectId(&38ea274d0c&);
Person p2 = new Person();
p2.setObjectId(&01e29165bc&);
Person p3 = new Person();
p3.setObjectId(&d&);
persons.add(p1);
persons.add(p2);
persons.add(p3);
new BmobObject().deleteBatch(this, persons, new DeleteListener() {
public void onSuccess() {
// TODO Auto-generated method stub
toast(&批量删除成功&);
public void onFailure(int code, String msg) {
// TODO Auto-generated method stub
toast(&批量删除失败:&+msg);
任何一种批量操作每次只支持最大50条记录的操作。
批量操作不支持对User表的操作。
数据的查询可能是每个应用都会频繁使用到的,BmobSDK中提供了BmobQuery类,它提供了多样的方法来实现不同条件的查询,同时它的使用也是非常的简单和方便的。查询单条数据
当我们知道某条数据的objectId时,就可以根据objectId直接获取单条数据对象。例如:查询objectId为a203eba875的人员信息。BmobQuery&GameScore& query = new BmobQuery&GameScore&();
query.getObject(this, &a203eba875&, new GetListener&GameScore&() {
public void onSuccess(GameScore object) {
// TODO Auto-generated method stub
toast(&查询成功:&);
//获得playerName的信息
object.getPlayerName();
//获得数据的objectId信息
object.getObjectId();
//获得createdAt数据创建时间(注意是:createdAt,不是createAt)
object.getCreatedAt();
public void onFailure(int code, String arg0) {
// TODO Auto-generated method stub
toast(&查询失败:&+arg0);
查询多条数据
查询某个数据表中的所有数据是非常简单的查询操作,例如:查询GameScore表中playerName为“比目”的50条数据记录。BmobQuery&GameScore& query = new BmobQuery&GameScore&();
//查询playerName叫“比目”的数据
query.addWhereEqualTo(&playerName&, &比目&);
//返回50条数据,如果不加上这条语句,默认返回10条数据
query.setLimit(50);
//执行查询方法
query.findObjects(this, new FindListener&GameScore&() {
public void onSuccess(List&GameScore& object) {
// TODO Auto-generated method stub
toast(&查询成功:共&+object.size()+&条数据。&);
for (GameScore gameScore : object) {
//获得playerName的信息
gameScore.getPlayerName();
//获得数据的objectId信息
gameScore.getObjectId();
//获得createdAt数据创建时间(注意是:createdAt,不是createAt)
gameScore.getCreatedAt();
public void onError(int code, String msg) {
// TODO Auto-generated method stub
toast(&查询失败:&+msg);
查询的结果不需要进行任何处理,BmobSDK已经为你封装成相应的JavaBean集合了,你直接使用即可。注:通过setLimit方法设置返回的记录数量。更多细节可一节。查询条件
在查询的使用过程中,基于不同条件的查询是非常常见的,BmobQuery同样也支持不同条件的查询。比较查询
如果要查询特定键的特定值,可以使用addWhereEqualTo方法,如果要过滤掉特定键的值可以使用addWhereNotEqualTo方法。比如需要查询playerName不等于“Barbie”的数据时可以这样写:query.addWhereNotEqualTo(&playerName&, &Barbie&);
当然,你可以在你的查询操作中添加多个约束条件,来查询符合要求的数据。query.addWhereNotEqualTo(&playerName&, &Barbie&);
//名字不等于Barbie
query.addWhereGreaterThan(&score&, 60);
//条件:分数大于60岁
各种不同条件的比较查询:// 分数 & 50
query.addWhereLessThan(&score&, 50);
//分数 &= 50
query.addWhereLessThanOrEqualTo(&score&, 50);
//分数 & 50
query.addWhereGreaterThan(&score&, 50);
//分数 &= 50
query.addWhereGreaterThanOrEqualTo(&score&, 50);
如果你想查询匹配几个不同值的数据,如:要查询“Barbie”,“Joe”,“Julia”三个人的成绩时,你可以使用addWhereContainedIn方法来实现。String[] names = {&Barbie&, &Joe&, &Julia&};
query.addWhereContainedIn(&playerName&, Arrays.asList(names));
相反,如果你想查询排除“Barbie”,“Joe”,“Julia”这三个人的其他同学的信息,你可以使用addWhereNotContainedIn方法来实现。String[] names = {&Barbie&, &Joe&, &Julia&};
query.addWhereNotContainedIn(&playerName&, Arrays.asList(names));
时间查询比较特殊,我们需要结合BmobDate这个类来查询某个指定日期时间前后的数据,这里也给出示例供大家参考:比如:如果想查询指定日期之前的数据,则可以使用addWhereLessThan或者addWhereLessThanOrEqualTo(包含当天)来查询。如果想查询指定日期之后的数据,则可以使用addWhereGreaterThan或addWhereGreaterThanOrEqualTo(包含当天)来查询。如果想查询指定时间当天的数据,则需要使用复合与查询来查询,例如,想查询号当天的Person数据,示例代码如下:BmobQuery&Person& query = new BmobQuery&Person&();
List&BmobQuery&Person&& and = new ArrayList&BmobQuery&Person&&();
//大于00:00:00
BmobQuery&Person& q1 = new BmobQuery&Person&();
String start = & 00:00:00&;
SimpleDateFormat sdf = new SimpleDateFormat(&yyyy-MM-dd HH:mm:ss&);
date = sdf.parse(start);
} catch (ParseException e) {
e.printStackTrace();
q1.addWhereGreaterThanOrEqualTo(&createdAt&,new BmobDate(date));
and.add(q1);
//小于23:59:59
BmobQuery&Person& q2 = new BmobQuery&Person&();
String end = & 23:59:59&;
SimpleDateFormat sdf1 = new SimpleDateFormat(&yyyy-MM-dd HH:mm:ss&);
Date date1
date1 = sdf1.parse(end);
} catch (ParseException e) {
e.printStackTrace();
q2.addWhereLessThanOrEqualTo(&createdAt&,new BmobDate(date1));
and.add(q2);
//添加复合与查询
query.and(and);
注:由于createdAt、updatedAt是服务器自动生成的时间,在服务器保存的是精确到微秒值的时间,所以,基于时间类型的比较的值要加1秒。数组查询
对于字段类型为数组的情况,需要查找字段中的数组值包含有xxx的对象,可以使用addWhereContainsAll方法:比如我想查询有阅读和唱歌爱好的人,可以这样:BmobQuery&Person& query = new BmobQuery&Person&();
String [] hobby = {&阅读&,&唱歌&};
query.addWhereContainsAll(&hobby&, Arrays.asList(hobby));
query.findObjects(this, new FindListener&Person&() {
public void onSuccess(List&Person& object) {
// TODO Auto-generated method stub
toast(&查询成功:共& + object.size() + &条数据。&);
public void onError(int code, String msg) {
// TODO Auto-generated method stub
toast(&查询失败:& + code);
对字符串值的模糊查询 比如 查询包含字符串的值,有几种方法。你可以使用任何正确的正则表达式来检索相匹配的值,使用addWhereMatches方法:query.addWhereMatches((&username&, &^[A-Z]\\d&);
还可以使用如下方法://查询username字段的值含有“sm”的数据
query.addWhereContains(&username&, &sm&);
//查询username字段的值是以“sm“字开头的数据
query.whereStartsWith(&username&, &sm&);
// 查询username字段的值是以“ile“字结尾的数据
query.whereEndsWith(&username&, &ile&);
列值是否存在
如果你想查询某个列的值存在,那么可以使用addWhereExists方法://查询username有值的数据
query.addWhereExists(&username&);
如果想查询某个列的值不存在,则可以用addWhereDoesNotExists方法//查询username字段没有值的数据
query.addWhereDoesNotExists(&username&);
有时,在数据比较多的情况下,你希望查询出的符合要求的所有数据能按照多少条为一页来显示,这时可以使用setLimit方法来限制查询结果的数据条数来进行分页。默认情况下,Limit的值为100,最大有效设置值1000(设置的数值超过1000还是视为1000)。query.setLimit(10); // 限制最多10条数据结果作为一页
在数据较多的情况下,在setLimit的基础上分页显示数据是比较合理的解决办法。setSKip方法可以做到跳过查询的前多少条数据来实现分页查询的功能。默认情况下Skip的值为10。query.setSkip(10); // 忽略前10条数据(即第一页数据结果)
大家也可以直接下载我们提供的Demo源码(),查看如何使用分页查询,结合ListView开发下拉刷新查看更多内容的应用。排序
对应数据的排序,如数字或字符串,你可以使用升序或降序的方式来控制查询数据的结果顺序:// 根据score字段升序显示数据
query.order(&score&);
// 根据score字段降序显示数据
query.order(&-score&);
// 多个排序字段可以用(,)号分隔
query.order(&-score,createdAt&);
说明:多个字段排序时,先按第一个字段进行排序,再按第二个字段进行排序,依次进行。复合查询
与查询(and)
有些查询需要使用到复合“与”的查询条件,例如:你想查询出Person表中年龄在6-29岁之间且姓名以&y&或者&e&结尾的人,那么,可以采用and查询,示例代码如下://查询年龄6-29岁之间的人,每一个查询条件都需要New一个BmobQuery对象
//--and条件1
BmobQuery&Person& eq1 = new BmobQuery&Person&();
eq1.addWhereLessThanOrEqualTo(&age&, 29);//年龄&=29
//--and条件2
BmobQuery&Person& eq2 = new BmobQuery&Person&();
eq2.addWhereGreaterThanOrEqualTo(&age&, 6);//年龄&=6
//查询姓名以&y&或者&e&结尾的人--这个需要使用到复合或查询(or)
//--and条件3
BmobQuery&Person& eq3 = new BmobQuery&Person&();
eq3.addWhereEndsWith(&name&, &y&);
BmobQuery&Person& eq4 = new BmobQuery&Person&();
eq4.addWhereEndsWith(&name&, &e&);
List&BmobQuery&Person&& queries = new ArrayList&BmobQuery&Person&&();
queries.add(eq3);
queries.add(eq4);
BmobQuery&Person& mainQuery = new BmobQuery&Person&();
BmobQuery&Person& or = mainQuery.or(queries);
//最后组装完整的and条件
List&BmobQuery&Person&& andQuerys = new ArrayList&BmobQuery&Person&&();
andQuerys.add(eq1);
andQuerys.add(eq2);
andQuerys.add(or);
//查询符合整个and条件的人
BmobQuery&Person& query = new BmobQuery&Person&();
query.and(andQuerys);
query.findObjects(this, new FindListener&Person&() {
public void onSuccess(List&Person& object) {
// TODO Auto-generated method stub
toast(&查询年龄6-29岁之间,姓名以'y'或者'e'结尾的人个数:&+object.size());
public void onError(int code, String msg) {
// TODO Auto-generated method stub
toast(&复合与查询失败:&+code+&,msg:&+msg);
或查询(or)
有些情况,在查询的时候需要使用到复合的“或”的查询条件。例如,你想查出 Person 表中 age 等于 29 或者 age 等于 6 的人,可以这样:BmobQuery&Person& eq1 = new BmobQuery&Person&();
eq1.addWhereEqualTo(&age&, 29);
BmobQuery&Person& eq2 = new BmobQuery&Person&();
eq2.addWhereEqualTo(&age&, 6);
List&BmobQuery&Person&& queries = new ArrayList&BmobQuery&Person&&();
queries.add(eq1);
queries.add(eq2);
BmobQuery&Person& mainQuery = new BmobQuery&Person&();
mainQuery.or(queries);
mainQuery.findObjects(this, new FindListener&Person&() {
public void onSuccess(List&Person& object) {
// TODO Auto-generated method stub
public void onError(int code, String msg) {
// TODO Auto-generated method stub
你还可以在此基础上添加更多的约束条件到新创建的 BmobQuery 对象上,表示一个 and 查询操作。查询结果计数
如果你只是想统计满足查询对象的数量,你并不需要获取所有匹配对象的具体数据信息,可以直接使用count替代findObjects。例如,查询一个特定玩家玩的游戏场数:BmobQuery&GameSauce& query = new BmobQuery&GameSauce&();
query.addWhereEqualTo(&playerName&, &Barbie&);
query.count(this, GameSauce.class, new CountListener() {
public void onSuccess(int count) {
// TODO Auto-generated method stub
toast(&Barbie has played& + count + &games&);
public void onFailure(int code, String msg) {
// TODO Auto-generated method stub
toast(&count failure:&+msg);
查询指定列
有的时候,一张表的数据列比较多,而我们只想查询返回某些列的数据时,我们可以使用BmobQuery对象提供的addQueryKeys方法来实现。如下所示://只返回Person表的objectId这列的值
BmobQuery&Person& bmobQuery = new BmobQuery&Person&();
bmobQuery.addQueryKeys(&objectId&);
bmobQuery.findObjects(this, new FindListener&Person&() {
public void onSuccess(List&Person& object) {
// TODO Auto-generated method stub
toast(&查询成功:共& + object.size() + &条数据。&);
//注意:这里的Person对象中只有指定列的数据。
public void onError(int code, String msg) {
// TODO Auto-generated method stub
toast(&查询失败:& + msg);
指定多列时用,号分隔每列,如:addQueryKeys(&objectId,name,age&);统计查询
从BmobSDKV3.3.6开始,Bmob为开发者提供了以下关键字或其组合的统计查询操作,分别用于计算总和、平均值、最大值、最小值,同时支持分组和过滤条件。 方法名
String[] sumKeys(多个列名)
求某列或多列的和 averageString[] aveKeys(多个列名)求某列或多列的平均值maxString[] maxKeys(多个列名)求某列或多列的最大值minString[] minKeys(多个列名)求某列或多列的最小值groupbyString[] groupKeys(多个列名)分组havingHashMap map(键(String)值(Object)对的形式)分组的过滤条件setHasGroupCountboolean hasCount是否返回每个分组的记录数
注:1、为避免和用户创建的列名称冲突,Bmob约定以上查询返回的字段采用_(关键字)+首字母大写的列名 的格式:例:计算玩家得分表(GameScore)中列名为score的总和,那么返回的结果集会有一个列名为_sumScore,若设置了setHasGroupCount(true),则结果集中会返回_count。2、以上方法可自由组合且与之前的查询语句中的where, order, limit, skip等组合一起使用。3、因为返回格式不固定,故使用findStatistics来专门处理统计查询。统计查询方法
例如,如果要计算所有玩家的得分总和,那么代码如下:BmobQuery&GameScore& query = new BmobQuery&GameScore&();
query.sum(new String[] { &playScore& });
query.findStatistics(this, GameScore.class,new FindStatisticsListener() {
public void onSuccess(Object object) {
JSONArray ary = (JSONArray)
if(ary!=null){//
JSONObject obj = ary.getJSONObject(0);
int sum = obj.getInt(&_sumPlayScore&);//_(关键字)+首字母大写的列名
showToast(&游戏总得分:& + sum);
} catch (JSONException e) {
showToast(&查询成功,无数据&);
public void onFailure(int code, String msg) {
// TODO Auto-generated method stub
showToast(&查询出错:code =& + &,msg = & + msg);
注:sum方法的参数只能查询Number类型的列名(对应Java的Integer类型),即要计算哪个列的值的总和。查询平均值、最大、最小和上面的求和类似,在这里也一并提示下:BmobQuery&GameScore& query = new BmobQuery&GameScore&();
//query.average(new String[]{&playScore&});//查询某列的平均值
query.min(new String[]{&playScore&});//查询最小值
//query.max(new String[]{&playScore&});//查询最大值
query.groupby(new String[]{&createdAt&});
query.findStatistics(this, GameScore.class, new FindStatisticsListener() {
public void onSuccess(Object result) {
// TODO Auto-generated method stub
JSONArray ary = (JSONArray)
if (ary!=null) {
JSONObject obj = ary.getJSONObject(0);
int playscore = obj.getInt(&_avgPlayScore&);
int minscore = obj.getInt(&_minPlayScore&);
int maxscore = obj.getInt(&_maxPlayScore&);
String createDate = obj.getString(&createdAt&);
showToast(&minscore = & + minscore+ &,统计时间 = &+ createDate);
} catch (JSONException e) {
e.printStackTrace();
showToast(&查询成功,无数据&);
public void onFailure(int code, String msg) {
// TODO Auto-generated method stub
showToast(&查询出错:code =& + &,msg = & + msg);
如果你需要对查询结果进行分组,可使用groupby方法,支持根据多个列名进行分组。//我们以创建时间按天和游戏分别统计玩家的得分,并按时间降序
BmobQuery&GameScore& query = new BmobQuery&GameScore&();
query.sum(new String[] { &playScore&, &signScore& });//求多个列的总和
query.groupby(new String[] { &createdAt&, &game& });//按照时间和游戏名进行分组
query.order(&-createdAt&);//降序排列
query.findStatistics(this, GameScore.class,new FindStatisticsListener() {
public void onSuccess(Object object) {
// TODO Auto-generated method stub
JSONArray ary = (JSONArray)
if(ary!=null){
int length = ary.length();
for (int i = 0; i & i++) {
JSONObject obj = ary.getJSONObject(i);
int playscore = obj.getInt(&_sumPlayScore&);
int signscore = obj.getInt(&_sumSignScore&);
String createDate = obj.getString(&createdAt&);
String game = obj.getString(&game&);
showToast(&游戏总得分:& + playscore + &,签到得分:&+ signscore + &,时间 = & + createDate+&,game = &+game);
} catch (JSONException e) {
e.printStackTrace();
showToast(&查询成功,无数据&);
public void onFailure(int code, String msg) {
// TODO Auto-generated method stub
showToast(&查询出错:code =& + &,msg = & + msg);
有时候,我们需要知道分组统计时每个分组有多少条记录,可使用setHasGroupCount(true),如下:// 查询创建时间按天统计所有玩家的得分和每一天有多少条玩家的得分记录,并按时间降序:
BmobQuery&GameScore& query = new BmobQuery&GameScore&();
query.sum(new String[] { &playScore& });
// 统计总得分
query.groupby(new String[] { &createdAt& });// 按照时间分组
query.order(&-createdAt&);
// 降序排列
query.setHasGroupCount(true);
// 统计每一天有多少个玩家的得分记录,默认不返回分组个数
query.findStatistics(this, GameScore.class,new FindStatisticsListener() {
public void onSuccess(Object object) {
// TODO Auto-generated method stub
JSONArray ary = (JSONArray)
if (ary!=null) {
int length = ary.length();
for (int i = 0; i & i++) {
JSONObject obj = ary.getJSONObject(i);
int playscore = obj.getInt(&_sumPlayScore&);
String createDate = obj.getString(&createdAt&);
int count = obj.getInt(&_count&);//setHasGroupCount设置为true时,返回的结果中含有&_count&字段
showToast(&游戏总得分:& + playscore + &,总共统计了&
+ count + &条记录,统计时间 = &+ createDate);
} catch (JSONException e) {
e.printStackTrace();
showToast(&查询成功,无数据&);
public void onFailure(int code, String msg) {
// TODO Auto-generated method stub
showToast(&查询出错:code =& + &,msg = & + msg);
添加过滤条件
如果需要对分组计算后的结果再进行过滤,可使用having来继续过滤部分结果。//我们按游戏名统计所有玩家的总得分,并只返回总得分大于100的记录,并按时间降序
BmobQuery&GameScore& query = new BmobQuery&GameScore&();
query.sum(new String[] {&playScore&});//计算总得分数
query.groupby(new String[] {&game&});//分组条件:按游戏名进行分组
query.order(&-createdAt&);// 降序排列
HashMap&String, Object& map = new HashMap&String, Object&();
JSONObject js = new JSONObject();
js.put(&$gt&, 100);
} catch (JSONException e1) {
map.put(&_sumPlayScore&, js);//过滤条件:总得分数大于100
query.having(map);
query.setLimit(100);
query.findStatistics(this, GameScore.class,new FindStatisticsListener() {
public void onSuccess(Object object) {
// TODO Auto-generated method stub
JSONArray ary = (JSONArray)
if(ary!=null){
int length = ary.length();
for (int i = 0; i & i++) {
JSONObject obj = ary.getJSONObject(i);
int playscore = obj.getInt(&_sumPlayScore&);//过滤条件的key是什么,返回的数据中就有什么
String game = obj.getString(&game&);
//返回的数据中同样包含groupby里面的列名
showToast(&游戏得分:& + playscore + &,游戏名 = &+ game);
} catch (JSONException e) {
e.printStackTrace();
showToast(&查询成功,无数据&);
public void onFailure(int code, String msg) {
// TODO Auto-generated method stub
showToast(&查询出错:code =& + &,msg = & + msg);
缓存查询通常是将查询结果缓存在磁盘上。当用户的设备处于离线状态时,就可以从缓存中获取数据来显示。或者在应用界面刚刚启动,从网络获取数据还未得到结果时,先使用缓存数据来显示。这样可以让用户不必在按下某个按钮后进行枯燥的等待。默认的查询操作是没有启用缓存的,开发者可以使用setCachePolicy方法来启用缓存功能。例如:优先从缓存获取数据,如果获取失败再从网络获取数据。bmobQuery.setCachePolicy(CachePolicy.CACHE_ELSE_NETWORK);
// 先从缓存获取数据,如果没有,再从网络获取。
bmobQuery.findObjects(this, new FindListener&Person&() {
public void onSuccess(List&Person& object) {
// TODO Auto-generated method stub
toast(&查询成功:共&+object.size()+&条数据。&);
public void onError(int code, String msg) {
// TODO Auto-generated method stub
toast(&查询失败:&+msg);
Bmob SDK提供了几种不同的缓存策略,以适应不同应用场景的需求:
IGNORE_CACHE
:只从网络获取数据,且不会将数据缓存在本地,这是默认的缓存策略。
CACHE_ONLY
:只从缓存读取数据,如果缓存没有数据会导致一个BmobException,可以忽略不处理这个BmobException.
NETWORK_ONLY
:只从网络获取数据,同时会在本地缓存数据。
NETWORK_ELSE_CACHE:先从网络读取数据,如果没有,再从缓存中获取。
CACHE_ELSE_NETWORK:先从缓存读取数据,如果没有,再从网络获取。
CACHE_THEN_NETWORK:先从缓存取数据,无论结果如何都会再次从网络获取数据。也就是说会产生2次调用。
建议的做法:第一次进入应用的时候,设置其查询的缓存策略为CACHE_ELSE_NETWORK,当用户执行上拉或者下拉刷新操作时,设置查询的缓存策略为NETWORK_ELSE_CACHE。缓存方法
如果需要操作缓存内容,可以使用BmobQuery提供的方法做如下操作:
检查是否存在当前查询条件的缓存数据
boolean isInCache = query.hasCachedResult(context,Class&?& clazz);
注:缓存和查询条件有关,此方法必须放在所有的查询条件(where、limit、order、skip、include等)都设置完之后,否则会得不到缓存数据。
清除当前查询的缓存数据
query.clearCachedResult(context,Class&?& clazz);
清除所有查询结果的缓存数据
BmobQuery.clearAllCachedResults(this);
设置缓存的最长时间(以毫秒为单位)
query.setMaxCacheAge(TimeUnit.DAYS.toMillis(1));//此表示缓存一天
示例如下:BmobQuery&Person& query
= new BmobQuery&Person&();
query.addWhereEqualTo(&age&, 25);
query.setLimit(10);
query.order(&createdAt&);
//判断是否有缓存,该方法必须放在查询条件(如果有的话)都设置完之后再来调用才有效,就像这里一样。
boolean isCache = query.hasCachedResult(context,Person.class);
if(isCache){--此为举个例子,并不一定按这种方式来设置缓存策略
query.setCachePolicy(CachePolicy.CACHE_ELSE_NETWORK);
// 如果有缓存的话,则设置策略为CACHE_ELSE_NETWORK
query.setCachePolicy(CachePolicy.NETWORK_ELSE_CACHE);
// 如果没有缓存的话,则设置策略为NETWORK_ELSE_CACHE
query.findObjects(this, new FindListener&Person&() {
public void onSuccess(List&Person& object) {
// TODO Auto-generated method stub
Log.i(&smile&,&查询个数:&+object.size())
public void onError(int code, String msg) {
// TODO Auto-generated method stub
Log.i(&smile&,&查询失败:&+object.size())
注:1、只有当缓存查询的条件一模一样时才会获取到缓存到本地的缓存数据。2、设置的默认的最大缓存时长为5小时。BQL查询
Bmob Query Language(简称 BQL) 是 Bmob 自 BmobSDKV3.3.7 版本开始,为查询 API 定制的一套类似 SQL 查询语法的子集和变种,主要目的是降低大家学习 Bmob 查询API 的成本,可以使用传统的 SQL 语法来查询 Bmob 应用内的数据。 具体的 BQL 语法,请参考 。基本BQL查询
可以通过以下方法来进行SQL查询:例如:需要查询所有的游戏得分记录String bql =&select * from GameScore&;//查询所有的游戏得分记录
new BmobQuery&GameScore&().doSQLQuery(context,bql,new SQLQueryListener&GameScore&(){
public void done(BmobQueryResult&GameScore& result, BmobException e) {
if(e ==null){
List&GameScore& list = (List&GameScore&) result.getResults();
if(list!=null && list.size()&0){
Log.i(&smile&, &查询成功,无数据返回&);
Log.i(&smile&, &错误码:&+e.getErrorCode()+&,错误描述:&+e.getMessage());
上面的示例也等价于(此方法自BmobV3.3.8版本提供)://查询所有的游戏得分记录
String bql =&select * from GameScore&;
BmobQuery&GameScore& query=new BmobQuery&GameScore&();
//设置查询的SQL语句
query.setSQL(bql);
query.doSQLQuery(context,new SQLQueryListener&GameScore&(){
public void done(BmobQueryResult&GameScore& result, BmobException e) {
if(e ==null){
List&GameScore& list = (List&GameScore&) result.getResults();
if(list!=null && list.size()&0){
Log.i(&smile&, &查询成功,无数据返回&);
Log.i(&smile&, &错误码:&+e.getErrorCode()+&,错误描述:&+e.getMessage());
如果需要查询个数,则可以这样:String bql = &select count(*),* from GameScore&;//查询GameScore表中总记录数并返回所有记录信息
new BmobQuery&GameScore&().doSQLQuery(context,bql, new SQLQueryListener&GameScore&(){
public void done(BmobQueryResult&GameScore& result, BmobException e) {
// TODO Auto-generated method stub
if(e ==null){
int count = result.getCount();//这里得到符合条件的记录数
List&GameScore& list = (List&GameScore&) result.getResults();
if(list.size()&0){
Log.i(&smile&, &查询成功,无数据&);
Log.i(&smile&, &错误码:&+e.getErrorCode()+&,错误描述:&+e.getMessage());
注:当查询的表为系统表(目前系统表有User、Installation、Role)时,需要带上下划线 _。比如,你想查询的是用户smile的信息,则:select * from _User where username = smile
统计BQL查询
由于统计查询的结果是不定的,故BQL提供了另外一种查询方法来进行统计查询,可以使用doStatisticQuery方法来进行://按照姓名分组求和,并将结果按时间降序排列
String bql = &select sum(playScore) from GameScore group by name order by -createdAt&;
new BmobQuery&GameScore&().doStatisticQuery(context, bql,new StatisticQueryListener(){
public void done(Object result, BmobException e) {
// TODO Auto-generated method stub
if(e ==null){
JSONArray ary = (JSONArray)
if(ary!=null){//开发者需要根据返回结果自行解析数据
showToast(&查询成功,无数据&);
Log.i(&smile&, &错误码:&+e.getErrorCode()+&,错误描述:&+e.getMessage());
占位符查询
在更多的时候,一个查询语句中间会有很多的值是可变值,为此,我们也提供了类似 Java JDBC 里的 PreparedStatement 使用占位符查询的语法结构。普通查询
String bql=&select * from GameScore where player = ? and game = ?&;//查询玩家1的地铁跑酷的GameScore信息
new BmobQuery&GameScore&().doSQLQuery(context, bql,new SQLQueryListener&GameScore&(){
public void done(BmobQueryResult&GameScore& result, BmobException e) {
// TODO Auto-generated method stub
if(e ==null){
List&GameScore& list = (List&GameScore&) result.getResults();
if(list!=null && list.size()&0){
Log.i(&smile&, &查询成功,无数据返回&);
Log.i(&smile&, &错误码:&+e.getErrorCode()+&,错误描述:&+e.getMessage());
},&玩家1&,&地铁跑酷&);
最后的可变参数 玩家1 和 地铁跑酷 会自动替换查询语句中的问号位置(按照问号的先后出现顺序)。上面的示例也等价于如下代码(此方法自BmobV3.3.8版本提供):String bql=&select * from GameScore where player = ? and game = ?&;
BmobQuery&GameScore& query=new BmobQuery&GameScore&();
//设置SQL语句
query.setSQL(bql);
//设置占位符参数
query.setPreparedParams(new Object[]{&玩家1&,&地铁跑酷&});
query.doSQLQuery(context,new SQLQueryListener&GameScore&(){
public void done(BmobQueryResult&GameScore& result, BmobException e) {
// TODO Auto-generated method stub
if(e ==null){
List&GameScore& list = (List&GameScore&) result.getResults();
if(list!=null && list.size()&0){
Log.i(&smile&, &查询成功,无数据返回&);
Log.i(&smile&, &错误码:&+e.getErrorCode()+&,错误描述:&+e.getMessage());
对于包含内置函数的占位符查询,比较特殊,请使用Bmob Query Language 详细指南中的内置函数中列出的形式进行查询操作:举例:我想查询当前用户在日之后,在特定地理位置附近的游戏记录,可以这样:String sql = &select * from GameScore where createdAt & date(?) and player = pointer(?,?) and gps near geopoint(?,?)&;
new BmobQuery&GameScore&().doSQLQuery(this, sql,new SQLQueryListener&GameScore&(){
public void done(BmobQueryResult&GameScore& result, BmobException e) {
// TODO Auto-generated method stub
if(e ==null){
List&GameScore& list = (List&GameScore&) result.getResults();
if(list!=null && list.size()&0){
Log.i(&smile&, &查询成功,无数据返回&);
Log.i(&smile&, &错误码:&+e.getErrorCode()+&,错误描述:&+e.getMessage());
},& 00:00:00&,&_User&,user.getObjectId(),112..52065);
注1、我们更推荐使用占位符语法,理论上会降低 BQL 转换的性能开销;2、最后的可变参数会自动替换查询语句中的问号位置(按照问号的先后出现顺序),有多少个问号,最后的可变参数就应该有多少个;3、同样的,统计查询也支持占位符,只需要将doSQLQuery替换成doStatisticQuery方法即可;4、只有查询条件where``limit子句支持占位符查询,和统计查询有关的group by、order by、having等字句是不支持占位符的。例如:正确查询://按照游戏名进行分组并获取总得分数大于200的统计信息,同时统计各分组的记录数
String bql = &select sum(playScore),count(*) from GameScore group by game having _sumPlayScore&200&;
new BmobQuery&GameScore&().doStatisticQuery(this, bql,new StatisticQueryListener(){
public void done(Object result, BmobException e) {
// TODO Auto-generated method stub
错误查询:String bql = &select sum(playScore),count(*) from GameScore group by ? having ?&;
new BmobQuery&GameScore&().doStatisticQuery(this, bql,new StatisticQueryListener(){
public void done(Object result, BmobException e) {
// TODO Auto-generated method stub
},&game&,&_sumPlayScore&200&);
BQL缓存查询
BQL查询同步支持缓存查询,只需要调用BmobQuery的setCachePolicy方法设置缓存策略即可,建议使用如下方式进行BQL缓存查询:String sql = &select * from GameScore order by playScore,signScore desc&;
BmobQuery&GameScore& query = new BmobQuery&GameScore&();
//设置sql语句
query.setSQL(sql);
//判断此查询本地是否存在缓存数据
boolean isCache = query.hasCachedResult(this,GameScore.class);
if(isCache){
query.setCachePolicy(CachePolicy.CACHE_ELSE_NETWORK);
// 如果有缓存的话,则设置策略为CACHE_ELSE_NETWORK
query.setCachePolicy(CachePolicy.NETWORK_ELSE_CACHE);
// 如果没有缓存的话,则设置策略为NETWORK_ELSE_CACHE
query.doSQLQuery(this,new SQLQueryListener&GameScore&(){
public void done(BmobQueryResult&GameScore& result, BmobException e) {
// TODO Auto-generated method stub
if(e ==null){
Log.i(&smile&, &查询到:&+result.getResults().size()+&符合条件的数据&);
Log.i(&smile&, &错误码:&+e.getErrorCode()+&,错误描述:&+e.getMessage());
注:doSQLQuery目前有三种查询方式进行SQL查询,分别是:1、doSQLQuery(Context context,SQLQueryListener listener)2、doSQLQuery(Context context, String bql, SQLQueryListener listener)----基本BQL查询3、doSQLQuery(Context context, String bql, SQLQueryListener listener,Object... params)----占位符查询只有第一种查询方式才能和query.hasCachedResult(context,class)或者query.clearCachedResult(context,class)并列使用。建议使用第一种查询方式进行BQL缓存查询。数组
对于数组类型数据,BmobSDK提供了3种操作来原子性地修改一个数组字段的值:
add、addAll 在一个数组字段的后面添加一些指定的对象(包装在一个数组内)
addUnique、addAllUnique 只会在原本数组字段中没有这些对象的情形下才会添加入数组,插入数组的位置随机
removeAll 从一个数组字段的值内移除指定数组中的所有对象
举例子:public class Person extends BmobObject {
private List&String&
// 爱好-对应服务端Array类型:String类型的集合
private List&BankCard&
// 银行卡-对应服务端Array类型:Object类型的集合
getter、setter方法
其中BankCard类结构如下:
public class BankCard{
private String cardN
private String bankN
public BankCard(String bankName, String cardNumber){
this.bankName = bankN
this.cardNumber = cardN
getter、setter方法
添加数组数据
给Person对象中的数组类型字段添加数据,有以下两种方式:使用add、addAll添加
Person p = new Person();
p.setObjectId(&d32143db92&);
//添加String类型的数组
p.add(&hobbys&, &唱歌&);
// 添加单个String
//p.addAll(&hobbys&, Arrays.asList(&游泳&, &看书&));
// 添加多个String
//添加Object类型的数组
p.add(&cards&,new BankCard(&工行卡&, &工行卡账号&))
//添加单个Object
List&BankCard& cards =new ArrayList&BankCard&();
for(int i=0;i&2;i++){
cards.add(new BankCard(&建行卡&+i, &建行卡账号&+i));
//p.addAll(&cards&, cards);
//添加多个Object值
p.save(this, new SaveListener() {
public void onSuccess() {
// TODO Auto-generated method stub
Log.i(&bmob&,&保}

我要回帖

更多关于 camera 软件下载 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信