找遍了全网,没有一个完整的可用的框架。ndk自带的android_native_app_glue确实不太好用,闭关几天,写出了一个框架。完全的消息队列调用,目前测试的主体框架是没有什么问题了,程序入口还是android_main。调用过程:

void android_main(android_app* app)
{//APP_LOG("main : 程序启动");//设置消息回调函数,就一个,整体和win32编程差不多了。app->onEvent = on_app_event;//循环等待事情以进行处理。while (app->running){//app处于运行状态app->process_message();//处理消息主函数if(!app->pause()){//draw_frame();//绘制我们的游戏,相当于MainLoop事件}else{//APP_LOG("PAUSE");}}//APP_LOG("main : 程序结束");
}

消息事件结构:

#pragma pack(push, 1)
struct APP_EVENT
{int id;union{void* data;struct{//input motionint16_t x, y, z, w;};struct{//input_keyboardint32_t key;int32_t flag;};struct{//ARectint16_t left, top, right, bottom;};};
};
#pragma pack(pop)

主消息处理函数,完全防win32编程设计,当然,事件处理做的还不够全面。现在只是初期框架,但这个框架已经比glue那个清晰多了。

主消息回调函数:

void on_app_event(android_app* app, APP_EVENT& event)
{switch(event.id){case APP_START://activity启动break;case APP_STOP://停止break;case APP_RESUME://返回break;case APP_PAUSE://暂停break;case APP_DESTROY://销毁退出break;case APP_SAVE://保存状态break;case APP_WINDOW_CREATE://窗口创建,app->window有效break;case APP_WINDOW_CLOSE://窗口销毁break;case APP_WINDOW_ACTIVATE://窗口获得焦点break;case APP_WINDOW_DEACTIVATE://窗口失去焦点break;case APP_WINDOW_RESIZE://窗口大小改变break;case APP_TOUCH_DOWN://触摸按下//这三个事件,都使用event.x, event.y作为坐标//event.z代表pointeridbreak;case APP_TOUCH_MOVE://触摸滑动break;case APP_TOUCH_UP:break;default://APP_LOG("unknow msg:%d", cmd);break;}
}

ndk的activity入口函数其实是:

void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, size_t savedStateSize);

这个函数由主进程调用,主进程创建一个activity,通知native库创建环境并处理,如果这个函数不返回,app就会卡死无响应。所以我们native库的过程要在一个新的线程里面处理。直接使用主线程的回调也不是不可以,但无法处理MainLoop这个事件,这个事件主线程没给。如果新建一个线程,如何处理主线程回调的事件,就是一个根本的问题。glue库用了pipe,并大把大把的mutex lock处理。下面这个库,把lock基本都去掉了,不再使用ALooper进行消息处理。主线程和线程之间的通信还是用的pipe,因为简单易用。

方式很简单:(设计执行标准)

一:所有ANativeActivity_onCreate里面指定的回调函数,执行过程都在主线程里面,这个我们要打包。用APP_EVENT把事件封装,通过pipe发送到我们线程的事件队列,主线程不对android_app内部数据进行操作。

二:android_main()过程里面,循环执行process_message(),进行事件处理。process_message()的执行过程就是,从pipe里面读取打包的APP_EVENT,并进行预处理、回调执行、后续处理。

三:所有事件方法,过程尽量保证清晰,可读性高。

目前库封装了部分输入交互操作,后续会继续封装。也欢迎大家评论,有用的着的尽可拿去用,public domain协议!

#ifndef ANDROID_APP_HPP
#define ANDROID_APP_HPP#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <pthread.h>
#include <sched.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/resource.h>#include<sys/ioctl.h>#include <jni.h>#include <android/configuration.h>
#include <android/looper.h>
#include <android/native_activity.h>
#include <android/log.h>#include "pipefile.hpp"//封装的pipe操作,之后会发表#include <cgl/public.h>//#define null NULL
#include <cgl/thread/mutex.hpp>//封装的锁操作,之后发表using namespace cgl;#define ANDROID_APP_LOG(...) ((void)__android_log_print(ANDROID_LOG_INFO, "android_app", __VA_ARGS__))
#define ANDROID_APP_ERROR(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "android_app", __VA_ARGS__))#define ANDROID_APP_DEBUG//debug 模式#ifdef ANDROID_APP_DEBUG
#define ANDROID_APP_LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "android_app", __VA_ARGS__))
#else
#define ANDROID_APP_LOGV(...) ((void)0)
#endif//android app events
enum ANDROID_APP_EVENT
{APP_START,APP_STOP,APP_RESUME,APP_PAUSE,APP_DESTROY,APP_SAVE,APP_CONFIG,APP_LOW_MEMORY,APP_WINDOW_CREATE,    //set app.windowAPP_WINDOW_CLOSE,    //reset app.windowAPP_WINDOW_ACTIVATE,APP_WINDOW_DEACTIVATE,APP_WINDOW_RESIZE,APP_WINDOW_RECT_CHANGED,APP_WINDOW_PAINT,APP_INPUT,        //set app.inputQueueAPP_TOUCH_DOWN,APP_TOUCH_UP,APP_TOUCH_MOVE,APP_KEY_UP,APP_KEY_DOWN,APP_KEY_PRESS
};#pragma pack(push, 1)
struct APP_EVENT
{int id;union{void* data;struct{//input motionint16_t x, y, z, w;};struct{//input_keyboardint32_t key;int32_t flag;};struct{//ARectint16_t left, top, right, bottom;};};
};
#pragma pack(pop)class android_app;extern void android_main(android_app* app);void android_app_post_event(android_app* app, const APP_EVENT& event);
void android_app_post_event(android_app* app, int id);class android_app
{
public:ANativeActivity* activity;AConfiguration* config;ALooper* looper;ANativeWindow* window;void* savedState;size_t savedStateSize;int stateSaved;void* userData;void (*onEvent)(android_app* app, APP_EVENT& event);int activityState;bool running;
public:pthread_t thread;mutex_t mutex;cond_t  cond;
public:io::pipefile message;AInputQueue* inputQueue;int destroyed;
public:android_app() : activity(null), config(null), looper(null), window(null),savedState(null), savedStateSize(0), stateSaved(0),userData(null),onEvent(null),activityState(0),thread(), mutex(), cond(),message(),inputQueue(null),destroyed(0){running = false;}void dispose();bool pause()const{return activityState == APP_PAUSE;// || activityState == APP_STOP;}int process_message(){APP_EVENT event;int bytes;ioctl(message.in(), FIONREAD, &bytes);while(bytes){if(this->read_event(event)){//ANDROID_APP_LOGV("process message %d - %p", event.id, event.data);this->process_begin(event);if(this->onEvent){this->onEvent(this, event);}this->process_end(event);}ioctl(message.in(), FIONREAD, &bytes);}ALooper_pollAll(0, NULL, NULL, NULL);//如果传感器有数据,立即处理。ident == USER//ANDROID_APP_LOG("pollAll %d", ident);return 0;}public://logvoid print_config();
public:void cond_wait(){cond.wait(mutex);}public:static int on_input(int fd, int events, void* data);int on_input_event(AInputEvent* event);
private:bool read_event(APP_EVENT& event);void process_begin(APP_EVENT& event);void process_end(APP_EVENT& event);int on_input_motion(AInputEvent* event);int on_input_keyboard(AInputEvent* event);
};void free_saved_state(android_app* app)
{//auto_lock lock(app->mutex);if (app->savedState != NULL) {free(app->savedState);app->savedState = NULL;app->savedStateSize = 0;}
}void android_app::print_config()
{char lang[2], country[2];AConfiguration_getLanguage(config, lang);AConfiguration_getCountry(config, country);ANDROID_APP_LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d ""keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d ""modetype=%d modenight=%d",AConfiguration_getMcc(config),AConfiguration_getMnc(config),lang[0], lang[1], country[0], country[1],AConfiguration_getOrientation(config),AConfiguration_getTouchscreen(config),AConfiguration_getDensity(config),AConfiguration_getKeyboard(config),AConfiguration_getNavigation(config),AConfiguration_getKeysHidden(config),AConfiguration_getNavHidden(config),AConfiguration_getSdkVersion(config),AConfiguration_getScreenSize(config),AConfiguration_getScreenLong(config),AConfiguration_getUiModeType(config),AConfiguration_getUiModeNight(config));
}#ifdef ANDROID_APP_DEBUG
const char* input_motion_name(int action)
{switch(action){case AMOTION_EVENT_ACTION_DOWN://触摸按下return "MOTION_DOWN";case AMOTION_EVENT_ACTION_UP://触摸弹起return "MOTION_UP";case AMOTION_EVENT_ACTION_MOVE://触摸移动return "MOTION_MOVE";case AMOTION_EVENT_ACTION_CANCEL:return "MOTION_CACEL";case AMOTION_EVENT_ACTION_OUTSIDE:return "MOTION_OUTSIDE";default:break;}return null;
}
#endifint android_app::on_input_motion(AInputEvent* inputEvent)
{APP_EVENT event;//motion sourceswitch(AInputEvent_getSource(inputEvent)){case AINPUT_SOURCE_TOUCHSCREEN://消息来源于触摸屏break;case AINPUT_SOURCE_TRACKBALL://消息来源于trackball,轨迹球 or 鼠标?break;default:break;}switch(AMotionEvent_getAction(inputEvent)){case AMOTION_EVENT_ACTION_DOWN://触摸按下event.id = APP_TOUCH_DOWN;break;case AMOTION_EVENT_ACTION_UP://触摸弹起event.id = APP_TOUCH_UP;break;case AMOTION_EVENT_ACTION_MOVE://触摸移动event.id = APP_TOUCH_MOVE;break;case AMOTION_EVENT_ACTION_CANCEL:break;case AMOTION_EVENT_ACTION_OUTSIDE:break;default:break;}//getX()    是表示view相对于自身左上角的x坐标,//getRawX()    是表示相对于物理屏幕左上角的x坐标值//AMotionEvent_getXPrecisionsize_t count = AMotionEvent_getPointerCount(inputEvent);for(int i=0; i < count; ++i){event.x = AMotionEvent_getX(inputEvent, i);event.y = AMotionEvent_getY(inputEvent, i);event.z = i;if(this->onEvent){this->onEvent(this, event);}#ifdef ANDROID_APP_DEBUGANDROID_APP_LOGV("%s : index=%d, pointer=%d, flag=%d state=%d x=%d, y=%d\n", input_motion_name(AMotionEvent_getAction(inputEvent)),i,AMotionEvent_getPointerId(inputEvent, i),AMotionEvent_getFlags(inputEvent), AMotionEvent_getMetaState(inputEvent),event.x, event.y);#endif}return this->onEvent ? 1 : 0;
}int android_app::on_input_keyboard(AInputEvent* inputEvent)
{//键盘控制键管用,字符键不管用ANDROID_APP_LOGV("keyinput : action=%d flag=%d keycode=%d",AKeyEvent_getAction(inputEvent),AKeyEvent_getFlags(inputEvent),AKeyEvent_getKeyCode(inputEvent));APP_EVENT event;switch(AKeyEvent_getAction(inputEvent)){case AKEY_STATE_UNKNOWN:break;case AKEY_STATE_UP:event.id = APP_KEY_UP;break;case AKEY_STATE_DOWN:event.id = APP_KEY_DOWN;break;case AKEY_STATE_VIRTUAL:event.id = APP_KEY_PRESS;break;default:break;}event.key = AKeyEvent_getKeyCode(inputEvent);event.flag = AKeyEvent_getFlags(inputEvent);if(this->onEvent){//if processed, reutrn 1this->onEvent(this, event);return 1;}return 0;
}// input event callback
int android_app::on_input_event(AInputEvent* inputEvent)
{if(AInputEvent_getType(inputEvent) == AINPUT_EVENT_TYPE_MOTION){return this->on_input_motion(inputEvent);}else if(AInputEvent_getType(inputEvent) == AINPUT_EVENT_TYPE_KEY){return this->on_input_keyboard(inputEvent);        }return 0;
}// inputQueue callback
int android_app::on_input(int fd, int events, void* data)
{ANDROID_APP_LOGV("on_input %p", data);android_app* app = (android_app*)data;AInputEvent* event = NULL;while (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {//ANDROID_APP_LOGV("New input event: type=%d\n", AInputEvent_getType(event));if (AInputQueue_preDispatchEvent(app->inputQueue, event)) {continue;}AInputQueue_finishEvent(app->inputQueue, event, app->on_input_event(event));}return 1;
}//读取事件
bool android_app::read_event(APP_EVENT& event)
{return message.read(&event, sizeof(event)) == sizeof(event);
}#ifdef ANDROID_APP_DEBUG
const char* app_event_name(int id)
{switch (id){case APP_START:                return "APP_START";case APP_STOP:                return "APP_STOP";case APP_RESUME:            return "APP_RESUME";case APP_PAUSE:                return "APP_PAUSE";case APP_DESTROY:            return "APP_DESTROY";case APP_SAVE:                return "APP_SAVE";case APP_CONFIG:            return "APP_CONFIG";case APP_WINDOW_CREATE:        return "APP_WINDOW_CREATE";case APP_WINDOW_CLOSE:        return "APP_WINDOW_CLOSE";case APP_WINDOW_ACTIVATE:    return "APP_WINDOW_ACTIVATE";case APP_WINDOW_DEACTIVATE: return "APP_WINDOW_DEACTIVATE";case APP_WINDOW_RESIZE:        return "APP_WINDOW_RESIZE";case APP_INPUT:                return "APP_INPUT";default:break;}return null;
}
#endif//预处理事件
void android_app::process_begin(APP_EVENT& event)
{switch (event.id){case APP_START:case APP_STOP:case APP_RESUME:case APP_PAUSE:ANDROID_APP_LOGV("APP_STATE = %s\n", app_event_name(event.id));this->activityState = event.id;break;case APP_DESTROY:ANDROID_APP_LOGV("APP_DESTROY\n");this->running = false;break;case APP_SAVE://free_saved_state(this);break;case APP_CONFIG:ANDROID_APP_LOGV("APP_CONFIG\n");AConfiguration_fromAssetManager(this->config, this->activity->assetManager);this->print_config();break;case APP_WINDOW_CREATE:ANDROID_APP_LOGV("APP_WINDOW_CREATE : %p\n", event.data);this->window = (ANativeWindow*)event.data;break;case APP_INPUT:{ANDROID_APP_LOGV("APP_INPUT : %p\n", event.data);if(this->inputQueue){AInputQueue_detachLooper(this->inputQueue);}this->inputQueue = (AInputQueue*)event.data;if(this->inputQueue){AInputQueue_attachLooper(this->inputQueue, this->looper, 0, android_app::on_input, this);}break;}default:ANDROID_APP_LOGV("APP_EVENT : %s", app_event_name(event.id));break;}
}//后续处理事件
void android_app::process_end(APP_EVENT& event)
{switch (event.id) {case APP_WINDOW_CLOSE:ANDROID_APP_LOGV("APP_WINDOW_CLOSE\n");this->window = NULL;break;case APP_SAVE:ANDROID_APP_LOGV("APP_SAVE\n");this->stateSaved = 1;break;case APP_RESUME://free_saved_state(this);break;default:break;}
}void android_app::dispose()
{ANDROID_APP_LOGV("android_app::dispose!");free_saved_state(this);//auto_lock lock(app->mutex);if(this->inputQueue){AInputQueue_detachLooper(this->inputQueue);}AConfiguration_delete(this->config);this->destroyed = 1;this->cond.broadcast();// Can't touch android_app object after this.
}// app main thread
void* android_app_main(void* param)
{android_app* app = (android_app*)param;app->config = AConfiguration_new();AConfiguration_fromAssetManager(app->config, app->activity->assetManager);app->print_config();app->looper = ALooper_prepare(0);app->running = true;android_main(app);    //android_mainapp->dispose();return NULL;
}// --------------------------------------------------------------------
//
// Native activity interaction (主线程调用的函数)
//
// --------------------------------------------------------------------android_app* android_app_create(ANativeActivity* activity, void* savedState, size_t savedStateSize)
{android_app* app = new android_app;app->activity = activity;if (savedState != NULL) {/*app->savedState = malloc(savedStateSize);app->savedStateSize = savedStateSize;memcpy(app->savedState, savedState, savedStateSize);*/}if(app->message.create()){ANDROID_APP_ERROR("could not create pipe: %s", strerror(errno));return NULL;}//int flag = fcntl(app->message.in(), F_GETFL, 0 );//fcntl(app->message.in(), F_SETFL, flag | O_NONBLOCK);pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);pthread_create(&app->thread, &attr, android_app_main, app);return app;
}void android_app_post_event(android_app* app, const APP_EVENT& event)
{//ANDROID_APP_LOGV("write event %d", event.id);if(app->message.write(&event, sizeof(event)) != sizeof(event)) {ANDROID_APP_ERROR("Failure writing android_app event: %s\n", strerror(errno));}
}void android_app_post_event(android_app* app, int id)
{APP_EVENT event = {id};android_app_post_event(app, event);
}//
// 主线程回调函数
////
// app
//void onStart(ANativeActivity* activity)
{ANDROID_APP_LOGV("Activity Start: %p\n", activity);android_app_post_event((android_app*)activity->instance, APP_START);
}void onStop(ANativeActivity* activity)
{ANDROID_APP_LOGV("Activity Stop: %p\n", activity);android_app_post_event((android_app*)activity->instance, APP_STOP);
}void onResume(ANativeActivity* activity)
{ANDROID_APP_LOGV("Activity Resume: %p\n", activity);android_app_post_event((android_app*)activity->instance, APP_RESUME);
}void onPause(ANativeActivity* activity)
{ANDROID_APP_LOGV("Activity Pause: %p\n", activity);android_app_post_event((android_app*)activity->instance, APP_PAUSE);
}void onDestroy(ANativeActivity* activity)
{ANDROID_APP_LOGV("Activity Destroy: %p\n", activity);android_app* app = (android_app*)activity->instance;//auto_lock lock(app->mutex);android_app_post_event(app, APP_DESTROY);while (!app->destroyed) {//app->cond_wait();}app->message.close();delete app;
}void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen)
{android_app* app = (android_app*)activity->instance;void* savedState = NULL;ANDROID_APP_LOGV("Activity SaveInstanceState: %p\n", activity);/*auto_lock lock(app->mutex);app->stateSaved = 0;android_app_post_event(app, APP_SAVE);while (!app->stateSaved) {app->cond_wait();}if (app->savedState != NULL) {savedState = app->savedState;*outLen = app->savedStateSize;app->savedState = NULL;app->savedStateSize = 0;}*/return savedState;
}void onConfigurationChanged(ANativeActivity* activity) {ANDROID_APP_LOGV("Activity ConfigurationChanged: %p\n", activity);android_app_post_event((android_app*)activity->instance, APP_CONFIG);
}void onLowMemory(ANativeActivity* activity)
{ANDROID_APP_LOGV("Activity LowMemory: %p\n", activity);android_app_post_event((android_app*)activity->instance, APP_LOW_MEMORY);
}//
// window
//void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window)
{ANDROID_APP_LOGV("NativeWindowCreated: %p -- %p\n", activity, window);APP_EVENT event;event.id = APP_WINDOW_CREATE;event.data = window;android_app_post_event((android_app*)activity->instance, event);
}void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window)
{ANDROID_APP_LOGV("NativeWindowDestroyed: %p -- %p\n", activity, window);android_app_post_event((android_app*)activity->instance, APP_WINDOW_CLOSE);
}void onWindowFocusChanged(ANativeActivity* activity, int focused)
{ANDROID_APP_LOGV("WindowFocusChanged: %p -- %d\n", activity, focused);android_app_post_event((android_app*)activity->instance, focused ? APP_WINDOW_ACTIVATE : APP_WINDOW_DEACTIVATE);
}void onNativeWindowResized(ANativeActivity* activity, ANativeWindow* window)
{ANDROID_APP_LOGV("NativeWindowResized: %p -- %p\n", activity, window);android_app_post_event((android_app*)activity->instance, APP_WINDOW_RESIZE);
}void onContentRectChanged(ANativeActivity* activity, const ARect* rect)
{ANDROID_APP_LOGV("ContentRectChanged: [%d, %d - %d, %d]\n", rect->left, rect->top, rect->right, rect->bottom);/*APP_EVENT event;event.id     = APP_WINDOW_RECT_CHANGED;event.left   = rect->left;event.top    = rect->top;event.right  = rect->right;event.bottom = rect->bottom;android_app_post_event((android_app*)activity->instance, event);*/
}void onNativeWindowRedrawNeeded(ANativeActivity* activity, ANativeWindow* window)
{ANDROID_APP_LOGV("NativeWindowRedrawNeeded: %p -- %p\n", activity, window);android_app_post_event((android_app*)activity->instance, APP_WINDOW_PAINT);
}//
// input
//void android_app_set_input(android_app* app, AInputQueue* inputQueue)
{APP_EVENT event;event.id = APP_INPUT;event.data = inputQueue;android_app_post_event(app, event);
}void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue)
{ANDROID_APP_LOGV("InputQueueCreated: %p -- %p\n", activity, queue);android_app_set_input((android_app*)activity->instance, queue);
}void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue)
{ANDROID_APP_LOGV("InputQueueDestroyed: %p -- %p\n", activity, queue);android_app_set_input((android_app*)activity->instance, NULL);
}//
// native activity entry
//JNIEXPORT
void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, size_t savedStateSize)
{ANDROID_APP_LOGV("NativeActivity create: %p\n", activity);//appactivity->callbacks->onStart   = onStart;activity->callbacks->onStop    = onStop;activity->callbacks->onResume  = onResume;activity->callbacks->onPause   = onPause;activity->callbacks->onDestroy = onDestroy;activity->callbacks->onSaveInstanceState    = onSaveInstanceState;activity->callbacks->onConfigurationChanged = onConfigurationChanged;activity->callbacks->onLowMemory = onLowMemory;//windowactivity->callbacks->onNativeWindowCreated      = onNativeWindowCreated;activity->callbacks->onNativeWindowDestroyed    = onNativeWindowDestroyed;activity->callbacks->onWindowFocusChanged       = onWindowFocusChanged;activity->callbacks->onNativeWindowResized      = onNativeWindowResized;activity->callbacks->onContentRectChanged       = onContentRectChanged;activity->callbacks->onNativeWindowRedrawNeeded = onNativeWindowRedrawNeeded;//inputactivity->callbacks->onInputQueueCreated   = onInputQueueCreated;activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;//create android appactivity->instance = android_app_create(activity, savedState, savedStateSize);//ANDROID_APP_LOGV("NativeActivity create successed.");
}#endif /* ANDROID_APP_HPP  */

ANDROID_APP C++框架相关推荐

  1. ssh(Struts+spring+Hibernate)三大框架整合-简述

    ssh(Struts+spring+Hibernate)三大框架配合使用来开发项目,是目前javaee最流行的开发方式,必须掌握: 注意: 为了稳健起见,每加入一个框架,我们就需要测试一下,必须通过才 ...

  2. Gin 框架学习笔记(03)— 输出响应与渲染

    在 Gin 框架中,对 HTTP 请求可以很方便有多种不同形式的响应.比如响应为 JSON . XML 或者是 HTML 等. ​ Context 的以下方法在 Gin 框架中把内容序列化为不同类型写 ...

  3. Gin 框架学习笔记(02)— 参数自动绑定到结构体

    参数绑定模型可以将请求体自动绑定到结构体中,目前支持绑定的请求类型有 JSON .XML .YAML 和标准表单 form数据 foo=bar&boo=baz 等.换句话说,只要定义好结构体, ...

  4. QT学习之状态机框架

    状态机框架 创建状态机

  5. 【Spring】框架简介

    [Spring]框架简介 Spring是什么 Spring是分层的Java SE/EE应用full-stack轻量级开源框架,以IOC(Inverse Of Control:反转控制)和AOP(Asp ...

  6. 开源自动化机器学习框架

    20211101 在 Airbnb 使用机器学习预测房源的价格 https://blog.csdn.net/weixin_33735077/article/details/87976278?spm=1 ...

  7. Keras框架下的保存模型和加载模型

    在Keras框架下训练深度学习模型时,一般思路是在训练环境下训练出模型,然后拿训练好的模型(即保存模型相应信息的文件)到生产环境下去部署.在训练过程中我们可能会遇到以下情况: 需要运行很长时间的程序在 ...

  8. Adam那么棒,为什么还对SGD念念不忘 (1) —— 一个框架看懂优化算法

    机器学习界有一群炼丹师,他们每天的日常是: 拿来药材(数据),架起八卦炉(模型),点着六味真火(优化算法),就摇着蒲扇等着丹药出炉了. 不过,当过厨子的都知道,同样的食材,同样的菜谱,但火候不一样了, ...

  9. 一个框架看懂优化算法之异同 SGD/AdaGrad/Adam

    Adam那么棒,为什么还对SGD念念不忘 (1) -- 一个框架看懂优化算法 机器学习界有一群炼丹师,他们每天的日常是: 拿来药材(数据),架起八卦炉(模型),点着六味真火(优化算法),就摇着蒲扇等着 ...

最新文章

  1. 清华体质优良可降5分录取;窃取密钥者奖百万;阿里投入1亿保护方言;腾讯不正当竞争被罚;这就是今天的大新闻...
  2. c语言float二进制输出代码_下面C语言中这十四大谜题,不看答案你能做出来吗?...
  3. jQuery 入口函数主要有4种写法
  4. grid列的值格式化
  5. php打印预览jquery,php 实现打印预览的功能
  6. xss攻击突破转义_每个人都应该了解的7种xss漏洞
  7. Eclipse“ctrl+左键”链到实现类
  8. mac 上使用docker
  9. 【LeetCode 剑指offer刷题】特殊数题3:204 Count Primes
  10. Tensorflow Timeline介绍及简单使用
  11. 详解: Spark 相对于MapReduce的优势(为什么MapReduce性能不理想)
  12. 解决办法:安装cuda时一直失败(如提示Reboot required to continue)
  13. 去除winrar广告
  14. python输入个人所得税计算_Python实现的个人所得税计算器示例
  15. web漏洞类型概述(owasp top10笔记)
  16. 佛说五百年的回眸才换来今生的擦肩而过
  17. erwfgergve
  18. 互联网+大赛作品_“颂中国力量 绘美好梦想”全市中小学生互联网+书画大赛作品展示(三)...
  19. python坦克大战
  20. mybatis-plus lambda表达式学习笔记

热门文章

  1. 新川抖音短视频营销平台是怎么样帮助企业运营抖音蓝V号的?
  2. 最新速卖通提前放款服务解读,帮助商家减轻资金压力!
  3. 在 Debian 11 Bullseye 上安装 Proxmox VE 7国内镜像源
  4. app模式会被第三方平台模式取代吗_手机 App 不能取代第三方浏览器的原因是什么?...
  5. Js出库入库数量变化
  6. 毕设 电脑维修_入库出库结算论文
  7. Unity中摄像机跟随
  8. JDBC连接数据库遇到的“驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。”问题解决方法
  9. 访问hadoop集群时错误:Access denied for user Administrator. Superuser privilege is required
  10. 雷军的本命年:轮回中的挫败、幸运和逆袭