首页 文章 精选 留言 我的

精选列表

搜索[通用人工智能],共10006篇文章
优秀的个人博客,低调大师

关于Unity 2018的实体组件系统(通用名称ECS)

将介绍如何在Unity上使用实体组件系统(通常称为ECS)。这次的内容是Unity提供的ECS API的基本用法,一个小应用程序和并行化。它不包括与Unity的GameObject / Component的合作,以及实际使用。获取可以使用ECS的编辑器Unity2018 和之后的版本都可以!创建一个可以使用ECS的项目要启用ECS,需要两件事。· 使使用 .NET 4.x· 重写 manifest.json正常启动Unity并打开 Edit> PlayerSettings> PlayerSettings。之后,将Scripting Runtime Version脚本运行时版本更改为Stable (.net 4.x)。接下来是重写manifest.json。由于在项目的Root文件夹/ Packages中有一个名为manifest.json的文件,因此我们将按照https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/TwoStickShooter/Pure/Packages/manifest.json与此处相同的方式重写内容。准备工作完成。最小的ECS项目首先,尝试尽可能地构建最有意义的功能。这次要组织的功能就是这样· 统计每个帧1、 没有使用 ECS的代码 :首先我会试着用MonoBehaviour来组织它。这是一个非常简单的代码。编写完成后,您可以将Counter组件添加到适当的GameObject中。using UnityEngine;public class Counter : MonoBehaviour{ public int count;void Update () { count++; }}接下来,让我们对应于ECS。有三件事要做它是什么?麻烦? ECS就是这样· CountData 计数的值· CountSystem 实际计数· ECSMain 实体ComponentDatas.csusing Unity.Entities; // 实体public struct CountData : IComponentData{public int count;}CountSystem.csusing Unity.Entities; public class CountSystem : ComponentSystem{// System所需的ComponentData列表struct Group{public int Length;public ComponentDataArray<CountData> countData;} [Inject] Group group; // 注入请求的ComponentData // 调用每一帧protected override void OnUpdate(){for(int i=0; i<group.Length; i++){var countData = group.countData[i];countData.count++;group.countData[i] = countData;}}}ECSMain.csusing UnityEngine;using Unity.Entities; public class ECSMain : MonoBehaviour{void Start (){// 获取EntityManagervar entityManager = World.Active.GetOrCreateManager<EntityManager>(); // 定义实体的原型var sampleArchetype = entityManager.CreateArchetype(typeof(CountData)); // 实际上基于原型生成实体entityManager.CreateEntity(sampleArchetype);}}之后,如果您将ECSMain附加到适当的对象并Play,则第一步完成。在Play期间,打开Window > EntityDebugger,当它从Systems列表中找到CountSystem时,它会变白,并且如果实体存在 。如果没有实体,那么您有可能在没有CountData的情况下创建实体,或者您没有首先创建实体。另外,如果您没有系统,则创建ComponentSystem的代码有问题。更多unity2018的功能介绍请到paws3d学习中心查找。

优秀的个人博客,低调大师

foy: 轻量级的基于 nodejs 的通用 build 工具

npm 的 scripts 下写的命令太多就很容易很乱,各种第三方轮子都只能解决一部分问题,总感觉不是很好用,想找个类似 make 的工具只能找到 jake, 可是 jake 的 API 太老,居然很多都不支持 promise, 代码也不多,就干脆自己造轮子了, 感觉效果还行。 项目地址: https://github.com/zaaack/foy gitee 地址: https://gitee.com/zane_young/foy 特点: 基于 promise 的任务和内置工具函数(fs/shell), 无缝支持 async/await 类似于 shelljs 的跨平台 shell dsl, 人人都会写 shell 易学易用,无需为写仅仅几个 build 命令而花费几个小时去寻找和学习第三方包 很小的安装成本 foy: gulp: grunt: 无缝和第三方支持 promise 的工具包整合,不需要封装成插件就能用 使用: 安装 yarn add -D foy # or npm i -D foy # Or Install globally with yarn add -g foy # or npm i -g foy 在项目根目录下增加一个 Foyfile.js (或者 Foyfile.ts, 需要安装 ts-node) import { task, desc, option, strict, fs } from 'foy' task('build', async ctx => { await ctx.exec('tsc') }) desc('Build ts files with tsc') option('-w, --watch', 'watch file changes') strict() // This will throw an error if you passed some options that doesn't defined via `option()` task('build2', async ctx => { await ctx.exec(`tsc ${ctx.options.watch ? '-w' : ''}`) }) task('task', async ctx => { await fs.rmrf('/some/dir/or/file') // Remove directory or file await fs.copy('/src', '/dist') // Copy folder or file let json = await fs.readJson('./xx.json') await ctx.env('NODE_ENV', 'production') await ctx.cd('./src') await ctx.exec('some command') // Execute an command let { stdout } = await ctx.exec('ls', { stdio: 'pipe' }) // Get the stdout, default is empty because it's redirected to current process via `stdio: 'inherit'`. }) 然后就可以运行任务了 # 安装在本地 node_modules 目录下 npx foy build npx foy build1 npx foy task # 安装在全局 foy build foy build1

优秀的个人博客,低调大师

Android采访开发——2.通用Android基础笔试题

注意finddreams博客:http://blog.csdn.net/finddreams/article/details/44219231 正值跳槽的热季。整理一下Android面试中最常考的笔试题。为下次找工作时做好充分准备。这是Android的基础部分: 1、Android四大组件是什么?作用以及应用场景? Android 的四大组件各自是是Activity,Service,BroadcastReceiver和ContentProvider; Activity: 从字面上理解,Activity是活动的意思。一个Activity通常展现为一个可视化的用户界面。是Android程序与用户交互的窗体,也是Android组件中最基本也是最复杂的一个组件。从视觉效果来看,一个Activity占领当前的窗体,响应全部窗体事件。具备有控件,菜单等界面元素。从内部逻辑来看,Activity须要为了保持各个界面状态,须要做非常多持久化的事情,还须要妥善管理生命周期。和一些转跳逻辑。 Service 服务是运行在后台的一个组件。从某从意义上说,服务就像一个没有界面的Activity。 它们在非常多Android的概念方面比較接近。封装有一个完整的功能逻辑实现,接受上层指令,完毕相关的事件,定义好须要接受的Intent提供同步和异步的接口。 BroadcastReceiver 广播接收者,不运行不论什么任务,广播是一种广泛运用的在应用程序之间传输信息的机制 。而 BroadcastReceiver 是对发送出来的广播进行过滤接收并响应的一类组件。Broadcast Receiver 不包括不论什么用户界面。 然而它们能够启动一个Activity以响应接受到的信息,或者通过NotificationManager通知用户。 能够通过多种方式使用户知道有新的通知产生:闪动背景灯、震动设备、发出声音等等。 通常程序会在状态栏上放置一个持久的图标,用户能够打开这个图标并读取通知信息。 在Android中另一个非常重要的概念就是Intent,假设说Intent是一个对动作和行为的抽象描写叙述,负责组件之间程序之间进行消息传递。那么Broadcast Receiver组件就提供了一种把Intent作为一个消息广播出去,由全部对其感兴趣的程序对其作出反应的机制。 Content Provider 即内容提供者。作为应用程序之间唯一的共享数据的途径,Content Provider 基本的功能就是存储并检索数据以及向其它应用程序提供訪问数据。 相应用而言,也能够将底层数据封装成ContentProvider。这样能够有效的屏蔽底层操作的细节。并且使程序保持良好的扩展性和开放性。 Android提供了一些主要数据类型的Contentprovider,比方音频、视频、图片和私人通讯录等。 可在android.provider包以下找到一些android提供的Contentprovider。 能够获得这些Contentprovider。查询它们包括的数据,当然前提是已获得适当的读取权限。假设我们想公开自己应用程序的数据,能够创建自己的 Content provider 的接口。 2、android中的动画有哪几类,它们的特点和差别是什么? 两种,一种是Tween动画、另一种是Frame动画。Tween动画,这样的实现方式能够使视图组件移动、放大、缩小以及产生透明度的变化;另一种Frame动画,传统的动画方法。通过顺序的播放排列好的图片来实现,相似电影。 3、后台的activity被系统回收怎么办?怎样在被系统回收之前保存当前状态? 当一个Activity被pause或者stop的时候,这个Activity的对象实际上还是保存在内存中,因此这个Activity中的信息(成员和状态信息)还能够又一次获取到. 假设系统为了整理内存而销毁了Activity对象时,系统没法简单的原封不动地恢复先前的Activity对象及其状态信息. Activity中提供了一个方法:onSavedInstanceState(Bundle obj).当系统销毁一个Activity时,会将Activity的状态信息已键值对形式存放在bundle对象中. 第一次启动Activity时,这个bundle对象是空的,null.假设Activity被系统销毁了,然后用户要回退回去看的话,系统会调用这个Activity的onCreate方法,并把bundle对象传递过去. 4. 请描写叙述一下Activity 生命周期。 5. 怎样将一个Activity设置成窗体的样式。 在AndroidManifest.xml 中定义Activity的地方一句话android:theme=”@android:style/Theme.Dialog”或android:theme=”@android:style/Theme.Translucent”就变成半透明的 6.注冊广播有几种方式,有何优缺点? 有两种,一种是代码动态注冊: //生成广播处理 smsBroadCastReceiver = new SmsBroadCastReceiver(); //实例化过滤器并设置要过滤的广播 IntentFilter intentFilter = new IntentFilter(“android.provider.Telephony.SMS_RECEIVED”); //注冊广播 BroadCastReceiverActivity.this.registerReceiver(smsBroadCastReceiver, intentFilter); 一种是在AndroidManifest.xml中配置广播 <!--广播注冊--> <receiver android:name=".SmsBroadCastReceiver"> <intent-filter android:priority="20"> <action android:name="android.provider.Telephony.SMS_RECEIVED"/> </intent-filter> </receiver> 两种注冊类型的差别是: 1)第一种不是常驻型广播。也就是说广播尾随程序的生命周期 2)另外一种是常驻型,也就是说当应用程序关闭后,假设有信息广播来,程序也会被系统调用自己主动运行。 注冊的方法有两种。一种是静态注冊,一种是动态注冊。 动态注冊长处: 在 Android 的广播机制中, 动态注冊的优先级是要高于静态注冊优先级的 。 因此在必要的情况下,我们是须要动态注冊广播接收器的。 静态注冊长处:动态注冊广播接收器另一个特点。就是当用来注冊的 Activity 关掉后 ,广播也就失效了。同一时候反映了静态注冊的一个优势,就是无需担忧广播接收器是否被关闭 , 仅仅要设备是开启状态。广播接收器就是打开着的。 7.IntentService有何长处? 普通的service ,默认运行在ui main 主线程 这是带有异步处理的service类, 异步处理的方法 OnHandleIntent() OnHandleIntent() 处理耗时的操作 Android的进程处理器如今会尽可能的不kill掉你 8.横竖屏切换时候activity的生命周期? 1、不设置Activity的android:configChanges时,切屏会又一次调用各个生命周期,切横屏时会运行一次。切竖屏时会运行两次 2、设置Activity的android:configChanges=”orientation”时。切屏还是会又一次调用各个生命周期。切横、竖屏时仅仅会运行一次 3、设置Activity的android:configChanges=”orientation|keyboardHidden”时,切屏不会又一次调用各个生命周期,仅仅会运行onConfigurationChanged方法 9、怎样将SQLite数据库(dictionary.db文件)与apk文件一起公布? 怎样将打开res raw文件夹中的数据库文件? 解答:以将dictionary.db文件拷贝到res raw文件夹中 。在Android中不能直接打开res raw文件夹中的数据库文件,而须要在程序第一次启动时将该文件拷贝到手机内存或SD卡的某个文件夹中,然后再打开该数据库文件。复制的基本方法是使用getResources().openRawResource方法获得res raw文件夹中资源的 InputStream对象,然后将该InputStream对象中的数据写入其它的文件夹中相应文件里。在Android SDK中能够使用SQLiteDatabase.openOrCreateDatabase方法来打开随意文件夹中的SQLite ; 10.AndroidManifest.xml文件里主要包括哪些信息 说明应用程序的java 包。该包名是应用程序的唯一标识。 描写叙述应用程序的组件:该应用程序由哪些activity,service,broadcast receiver和content provider组成; 声明应用程序所必须具备的权限。用以訪问受保护的部分API,以及与其它应用程序的交互; 声明应用程序所须要的Android API的最低版本号级别。比方1.0,1.1,1.5; manifest:根节点,描写叙述了 package 中全部的内容。 uses-permission:请求你的 package 正常运作所需赋予的安全许可。 permission: 声明了安全许可来限制哪些程序能你 package 中的组件和功能。 instrumentation:声明了用来測试此 package 或其它 package 指令组件的代码。 application:包括 package 中 application 级别组件声明的根节点。 activity:Activity 是用来与用户交互的主要工具。 receiver:IntentReceiver 能使的 application 获得数据的改变或者发生的操作,即使它当 前不在运行。 service:Service 是能在后台运行随意时间的组件。 provider:ContentProvider 是用来管理持久化数据并公布给其它应用程序使用的组件。 11.Android数据储存方式 一.SharedPreferences方式:它是 Android提供的用来存储一些简单配置信息的一种机制,採用了 XML 格式将数据存储到设备中。仅仅能在同一个包内使用。不能在不同的包之间使用。 二.文件存储方式 /data/data/包名/files 内存里面 / context.openFileInput(name) 默认是私有的訪问权限 三.SQLite数据库方式:SQLite 是 Android 所带的一个标准的数据库, 它支持 SQL语句,它是一个轻量级的嵌入式数据库。 四.内容提供器(Content provider)方式:主要用于应用程序之间进行数据交换。从而能够让其它的应用保存或读取此 Content Provider 的各种数据类型。 五. 网络存储方式: 通过网络上提供给我们的存储空间来上传(存储)和下载(获取)我们存储 在网络空间中的数据信息。 12.Android中常见五种布局介绍 FrameLayout(帧布局): 从屏幕的左上角開始布局,叠加显示, 实际应用 播放器的暂停button. LinearLayout (线性布局):可分为垂直布局。水平布局。 AbsoluteLayout(绝对布局):用X,Y坐标来指定元素的位置; RelativeLayout(相对布局): 相对布局能够理解为某一个元素为參照物,来定位的布局方式。 TableLayout(表格布局):表格布局相似Html里面的Table。每个TableLayout里面有表格行TableRow。TableRow里面能够详细定义每个元素,设定他的对齐方式 android:gravity=”” 。 每个布局都有自己适合的方式,另外,这五个布局元素能够相互嵌套应用,做出美观的界面。 13.Activity的四种启动模式?,activity与task的启动方式有哪些,她们的含义详细说明 standard: 标准模式,一调用 startActivity()方法就会产生一个新的实例。 singleTop: 假设已经有一个实例位于 Activity 栈的顶部时, 就不产生新的实例。 而仅仅是调用Activity 中的 newInstance()方法。 假设不位于栈顶,会产生一个新的实例。 singleTask: 会在一个新的 task 中产生这个实例,以后每次调用都会使用这个,不会去产生 新的实例了。 singleInstance: 这个跟 singleTask 基本上是一样, 仅仅有一个差别: 在这个模式下的 Activity实例所处的 task 中,仅仅能有这个 activity实例,不能有其它的实例。 14.Android 中的长度单位详细解释 假设设置表示长度 、 高度等属性时能够使用 dp 或 sp。但假设设置字体,须要使用 sp。dp 是与密度无关,sp 除了与密度无关外,还与 scale 无关。 假设屏幕密度为160,这时 dp 和 sp 和 px 是一样 的。1dp=1sp=1px, 也就是说,假设使用 dp 和 sp,系统会依据屏幕密度的变化自己主动进行转换 px :表示屏幕实际的象素 in:表示英寸,是屏幕的物理尺寸。 每英寸等于2.54 厘米。 15.android 析 中有哪几种解析 l xml 的类, , , , 官方推荐哪种?以及它们的原 理和差别 DOM 解析 长处: 1.XML 树在内存中完整存储,因此能够直接改动其数据和结构. 2.能够通过该解析器随时訪问 XML 树中的不论什么一个节点. 3.DOM 解析器的 API 在使用上也相对照较简单. 缺点:假设 XML 文档体积比較大时,将文档读入内存是非常消耗系统资源的 Ø SAX 解析 长处: SAX 对内存的要求比較低,由于它让开发人员自己来决定所要处理的标签.特别是当开发人 员仅仅须要处理文档中所包括的部分数据时,SAX 这样的扩展能力得到了更好的体现. 缺点: 用 SAX 方式进行 XML 解析时,须要顺序运行,所以非常难訪问到同一文档中的不同数据.此外,在基于该方式的解析编码过程也相对复杂 Ø Xmlpull 解析(官方推荐使用) android SDK 提供了 xmlpull api,xmlpull 和 sax 相似,是基于流(stream)操作文件,然后依据节点事件回调开发人员编写的处理程序.由于是基于流的处理,因此 xmlpull 和 sax 都比較节 约内存资源,不会象 dom 那样要把全部节点以对橡树的形式展如今内存中.xmlpull 比 sax 更 简明,并且不须要扫描完整个流. 16.ListView 的 优化方案 (1),假设自己定义适配器。那么在 getView 方法中要考虑方法传进来的參数 contentView 是否 为 null,假设为 null 就创建 contentView 并返回,假设不为 null 则直接使用。 在这种方法中,尽可能少创建 view。 (2)。给 contentView 设置 tag(setTag()),传入一个 viewHolder 对象,用于缓存要显示的数 据,能够达到图像数据异步载入的效果 (3),假设 listview 须要显示的 item 非常多,就要考虑分页载入。比方一共要显示100条或者很多其它的时候。我们能够考虑先载入20条。等用户拉到列表底部的时候,再去载入接下来的20 条。 (4) 高速滑动时不载入图片 (5) 假设自己定义的item中有图片,须要处理图片(降低图片所占内存) 1.对图片进行边界压缩 2.用option类来保存图片大小 3.避免图片的实时缩放,最好预先缩放到视图大小 (6)尽量避免在listview适配器中使用线程。由于线程是产生内存泄露的主要原因在于线程的生命周期不可控。 17.Android中intent的作用 在一个 Android 应用中,主要是由一些组件组成(Activity,Service,ContentProvider,etc.) 在这些组件之间的通讯中。由 Intent 协助完毕。 Intent 负责相应用中一次操作的动作、动作涉及数据、附加数据 进行描写叙述,Android 则依据此 Intent 的描写叙述。负责找到相应的组件。将 Intent 传递给调用的组件,并完毕组件的调用。 Intent 在这里起着实现调用者与被调用者之间的解耦作用。 有两种方式,一种是显示匹配,一种是隐示匹配。 显示:明白的指定要跳转的Activity,或者Service等。 隐示:隐式匹配。首先要匹配 Intent 的几项值:Action,Category, Data/Type,Component假设填写了 Componet 就是这就形成了显示匹配。 1.假设你填写了 Action, 假设有一个程序的 Manifest.xml 中的某一个 Activity 的 IntentFilter 段中定义了包括了同样的 Action 那么这个 Intent 就与这个目标 Action 匹配, 假设这个 Filter段中未定义 Type,Category,那么这个 Activity 就匹配了。可是假设手机中有两个以上的程序匹配,那么就会弹出一个对话可框来提示说明。 2,data/type,你能够用 Uri 来做为 data,比方 Uri uri = Uri.parse(http://www.google.com); Intent i = new Intent(Intent.ACTION_VIEW,uri);手机的 Intent 分发过程中,会依据http://www.google.com的 scheme 推断出数据类型 type手机的 Brower 则能匹配它,在 Brower 的 Manifest.xml 中的 IntenFilter中首先有ACTION_VIEW Action,也能处理 http:的 type; 3,至于分类 Category。一般不要去在 Intent 中设置它,假设你写 Intent 的接收者,就在Manifest.xml 的 Activity 的 IntentFilter 中包括 android.category.DEFAULT,这样全部不设置Category(Intent.addCategory(String c);)的 Intent 都会与这个 Category 匹配。 4,extras(附加信息) ,是其它全部附加信息的集合。使用 extras 能够为组件提供扩展信息 ,比方,假设要运行“发送电子邮件”这个动作,能够将电子邮件的标题、正文等保存在 extras里,传给电子邮件发送组件。 18.怎样退出 Activity ?怎样安全退出? 对于单一 Activity 的应用来说,退出非常easy,直接 finish()就可以。 当然。也能够用 killProcess()和 System.exit()这样的方法。 为了编程方便,最好定义一个 Activity 基类。处理这些共通问题。 1、记录打开的 Activity: 每打开一个 Activity,就记录下来。在须要退出时,关闭每个 Activity 就可以。 2、发送特定广播: 在须要结束应用时,发送一个特定的广播,每个 Activity 收到广播后。关闭就可以。 版权声明:本文博客原创文章。博客,未经同意,不得转载。 本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/4651012.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android应用开发—通用的GridView网格分割线

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/voidreturn/article/details/77622289 注:本文基于 Android RecyclerView 使用完全解析 体验艺术般的控件 中关于GridView网格分割线部分代码扩展而来。 原接口代码: import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.LayoutManager; import android.support.v7.widget.RecyclerView.State; import android.support.v7.widget.StaggeredGridLayoutManager; import android.view.View; public class DividerGridItemDecoration extends RecyclerView.ItemDecoration { private static final int[] ATTRS = new int[]{android.R.attr.listDivider}; private Drawable mDivider; public DividerGridItemDecoration(Context context) { final TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); a.recycle(); } @Override public void onDraw(Canvas c, RecyclerView parent, State state) { drawHorizontal(c, parent); drawVertical(c, parent); } private int getSpanCount(RecyclerView parent) { // 列数 int spanCount = -1; LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { spanCount = ((GridLayoutManager) layoutManager).getSpanCount(); } else if (layoutManager instanceof StaggeredGridLayoutManager) { spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount(); } return spanCount; } public void drawHorizontal(Canvas c, RecyclerView parent) { int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); final int left = child.getLeft() - params.leftMargin; final int right = child.getRight() + params.rightMargin + mDivider.getIntrinsicWidth(); final int top = child.getBottom() + params.bottomMargin; final int bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } public void drawVertical(Canvas c, RecyclerView parent) { final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); final int top = child.getTop() - params.topMargin; final int bottom = child.getBottom() + params.bottomMargin; final int left = child.getRight() + params.rightMargin; final int right = left + mDivider.getIntrinsicWidth(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } private boolean isLastColum(RecyclerView parent, int pos, int spanCount, int childCount) { LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { // 如果是最后一列,则不需要绘制右边 if ((pos + 1) % spanCount == 0) { return true; } } else if (layoutManager instanceof StaggeredGridLayoutManager) { int orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation(); if (orientation == StaggeredGridLayoutManager.VERTICAL) { // 如果是最后一列,则不需要绘制右边 if ((pos + 1) % spanCount == 0) { return true; } } else { childCount = childCount - childCount % spanCount; if (pos >= childCount)// 如果是最后一列,则不需要绘制右边 return true; } } return false; } private boolean isLastRaw(RecyclerView parent, int pos, int spanCount, int childCount) { LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { childCount = childCount - childCount % spanCount; if (pos >= childCount)// 如果是最后一行,则不需要绘制底部 return true; } else if (layoutManager instanceof StaggeredGridLayoutManager) { int orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation(); // StaggeredGridLayoutManager 且纵向滚动 if (orientation == StaggeredGridLayoutManager.VERTICAL) { childCount = childCount - childCount % spanCount; // 如果是最后一行,则不需要绘制底部 if (pos >= childCount) return true; } else { // 如果是最后一行,则不需要绘制底部 if ((pos + 1) % spanCount == 0) { return true; } } } return false; } @Override public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { int spanCount = getSpanCount(parent); int childCount = parent.getAdapter().getItemCount(); // 如果是最后一行,则不需要绘制底部 if (isLastRaw(parent, itemPosition, spanCount, childCount)) { outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } else if (isLastColum(parent, itemPosition, spanCount, childCount)) { // 如果是最后一列,则不需要绘制右边 outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); } else { outRect.set(0, 0, mDivider.getIntrinsicWidth(), mDivider.getIntrinsicHeight()); } } } 扩展后的代码: import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.LayoutManager; import android.support.v7.widget.RecyclerView.State; import android.support.v7.widget.StaggeredGridLayoutManager; import android.view.View; public class DividerGridItemDecoration extends RecyclerView.ItemDecoration { private static final int[] ATTRS = new int[]{android.R.attr.listDivider}; private Drawable mDivider; private Paint mColorPaint; private int mDividerHeight = 1; public DividerGridItemDecoration(Context context) { final TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); a.recycle(); } public DividerGridItemDecoration(Context context, int color, int height) { this(context); mColorPaint = new Paint(); mColorPaint.setColor(color); mDividerHeight = height; } @Override public void onDraw(Canvas c, RecyclerView parent, State state) { drawHorizontal(c, parent); drawVertical(c, parent); } private int getSpanCount(RecyclerView parent) { // 列数 int spanCount = -1; LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { spanCount = ((GridLayoutManager) layoutManager).getSpanCount(); } else if (layoutManager instanceof StaggeredGridLayoutManager) { spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount(); } return spanCount; } public void drawHorizontal(Canvas c, RecyclerView parent) { int childCount = parent.getChildCount(); int spanCount = getSpanCount(parent); int count = 0; if (childCount % spanCount != 0) { count = childCount; } else { count = childCount - spanCount; } for (int i = 0; i < count; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); final int left = child.getLeft() - params.leftMargin; final int right = child.getRight() + params.rightMargin + mDivider.getIntrinsicWidth(); final int top = child.getBottom() + params.bottomMargin; final int bottom = top + mDivider.getIntrinsicHeight(); if (mColorPaint != null) { c.drawRect(left, top, right, top + mDividerHeight, mColorPaint); } else { mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } } public void drawVertical(Canvas c, RecyclerView parent) { final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); final int top = child.getTop() - params.topMargin; final int bottom = child.getBottom() + params.bottomMargin; final int left = child.getRight() + params.rightMargin; final int right = left + mDivider.getIntrinsicWidth(); if (mColorPaint != null) { c.drawRect(left, top, left + mDividerHeight, bottom, mColorPaint); } else { mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } } private boolean isLastColum(RecyclerView parent, int pos, int spanCount, int childCount) { LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { // 如果是最后一列,则不需要绘制右边 if ((pos + 1) % spanCount == 0) { return true; } } else if (layoutManager instanceof StaggeredGridLayoutManager) { int orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation(); if (orientation == StaggeredGridLayoutManager.VERTICAL) { // 如果是最后一列,则不需要绘制右边 if ((pos + 1) % spanCount == 0) { return true; } } else { childCount = childCount - childCount % spanCount; if (pos >= childCount)// 如果是最后一列,则不需要绘制右边 return true; } } return false; } private boolean isLastRaw(RecyclerView parent, int pos, int spanCount, int childCount) { LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { childCount = childCount - childCount % spanCount; if (pos >= childCount)// 如果是最后一行,则不需要绘制底部 return true; } else if (layoutManager instanceof StaggeredGridLayoutManager) { int orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation(); // StaggeredGridLayoutManager 且纵向滚动 if (orientation == StaggeredGridLayoutManager.VERTICAL) { childCount = childCount - childCount % spanCount; // 如果是最后一行,则不需要绘制底部 if (pos >= childCount) return true; } else { // 如果是最后一行,则不需要绘制底部 if ((pos + 1) % spanCount == 0) { return true; } } } return false; } @Override public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { int spanCount = getSpanCount(parent); int childCount = parent.getAdapter().getItemCount(); // 如果是最后一行,则不需要绘制底部 if (isLastRaw(parent, itemPosition, spanCount, childCount)) { outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } else if (isLastColum(parent, itemPosition, spanCount, childCount)) { // 如果是最后一列,则不需要绘制右边 outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); } else { outRect.set(0, 0, mDivider.getIntrinsicWidth(), mDivider.getIntrinsicHeight()); } } } 扩展的内容: 最后一行不画分割线。通常我们的需求是边框都不进行分割的绘制,而原来的代码没有做这部分的处理。(原接口只处理了最后一列的情况) 支持分割线的颜色和宽度绘制的定制化。(原接口只支持系统属性分割线的绘制)。绘制方式:DividerGridItemDecoration(Context context, int color, int height) 通过传递color和height进行绘制定制化。

优秀的个人博客,低调大师

Openstack_通用模块_Oslo_vmware 创建 vSS PortGroup

目录 目录 vSS vSSPG vSphere SDK 中相关的网络对象 创建 vSS PortGroup vSS & vSSPG vSS(Standard vSwitch 标准交换机) 为在同一 ESXi/ESX 或不同 ESXi/ESX 上 VirtualMachine 之间的连接, 也可以让 VirtualMachine 连接到外部网络. vSSPG(Standard vSwitch PortGroup 标准交换机端口组) 是 vSphere 的基本网络对象模型, VirtualMachine 会通过一个 PortGroup 来访问网络. 使用 oslo.vmware 模块结合 vSphere API 来创建 vSSPG 是一个相对综合的调用过程, 在实现的过程中能让我们理解 vSphere SDK 定义的相关概念模型, 以及熟悉 VMware vSphere API Reference Docs. vSphere SDK 中相关的网络对象 vSphere Web Services SDK 包括下列对象和方法来管理网络配置: HostNetworkSystem(Managed Object): 代表了主机的网路配置, 拥有检索和改变网络配置的方法. 所以我们能够使用 HostNetworkSystem MO 对象来访问和控制 ESX/ESXi 的网络概念模型. HostNetworkConfig(Data Object): 用于规划 ESXi Host 详细的网络配置. 创建 vSS PortGroup 首先我们已经知道创建标准交换机端口组需要使用 HostNetowrkSystem MO 的 AddPortGroup 方法, 所以调用该方法的前提就是能够获取到HostNetowrkSystem MO. 但遗憾的是我们无法通过 oslo.vmware 模块提供的 get_objects invoke_api 来直接获取, 这就需要我们费些心思去找到其上级且可使用 get_objects invoke_api 来获取的 MO. NOTE: 下述多数截图出自于 VMware vSphere API Reference Docs. 从下图可知 HostNetworkSystem MO 的上级 Property 是 HostConfigManager, 那么我们首先进入到 HostConfigManager 的 Docs. 然后从下图可知 HostConfigManager 是一个 Data object, 我们仍无法通过 get_object invoke_api 的方式来获取这个对象, 所以继续进入 HostConfigManager 对象的上级 Property. 直到现在我们看到了非常熟悉的 HostSystem MO, 这是一个非常常用的 MO, 并且支持 get_object invoke_api 的获取方式, 所以从 HostSystem 开始, 我们就能够其属性, 直到得到 HostNetowrkSystem MO 为止. Step 1: 连接到 vCenter 或 ESXi/ESX from oslo_vmware import api from oslo_vmware import vim_util # Create the vmware session session = api.VMwareAPISession( '200.21.102.7', 'root', 'vmware', 1, 0.1) Step 2: 获取 HostSystem MO hosts = session.invoke_api( vim_util, 'get_objects', session.vim, 'HostSystem', 100) # 我们随意选取一个 ESXi Host, 并且打印其 Object host_obj = hosts.objects[0].obj In [17]: hosts.objects[0].obj Out[17]: (obj){ value = "host-10" _type = "HostSystem" } Step 3: 从下图可以看出 HostSystem 的 Properties configManager 就是 HostConfigManager 对象, HostConfigManager 的 Properties networkSystem 就是 HostNetworkSystem 对象. (HostSystem ==> HostConfigManager) (HostConfigManager ==> HostNetworkSystem) # 获取 HostNetworkSystem MO, 并打印其 Value host_network_system_val = session.invoke_api( vim_util, 'get_object_properties_dict', session.vim, host_obj, 'configManager.networkSystem') In [24]: host_network_system_val Out[24]: {configManager.networkSystem: (val){ value = "networkSystem-10" _type = "HostNetworkSystem" }} Step 4: 在得到了 host_network_system_val 对象之后, 我们就能够通过 session.invoke_api 来调用该对象的 AddPortGroup 方法了. 但仍有一个前提, 就是我们需要为 AddPortGroup 准备好需要传入的实参 portgrp(HostPortGroupSpec). 再如下图, 我们得知 HostPortGroupSpec 是一个 Data Object, 所以我们能够通过 session.vim.client.factory.create 方法来获取该对象的数据结构. # 获取 HostPortGroupSpec 对象的数据结构, 并打印 client_factory = session.vim.client.factory vswitch_port_group_spec = client_factory.create('ns0:HostPortGroupSpec') In [26]: vswitch_port_group_spec Out[26]: (HostPortGroupSpec){ dynamicType = None dynamicProperty[] = <empty> name = None vlanId = None vswitchName = None policy = (HostNetworkPolicy){ dynamicType = None dynamicProperty[] = <empty> security = (HostNetworkSecurityPolicy){ dynamicType = None dynamicProperty[] = <empty> allowPromiscuous = None macChanges = None forgedTransmits = None } nicTeaming = (HostNicTeamingPolicy){ dynamicType = None dynamicProperty[] = <empty> policy = None reversePolicy = None notifySwitches = None rollingOrder = None failureCriteria = (HostNicFailureCriteria){ dynamicType = None dynamicProperty[] = <empty> checkSpeed = None speed = None checkDuplex = None fullDuplex = None checkErrorPercent = None percentage = None checkBeacon = None } nicOrder = (HostNicOrderPolicy){ dynamicType = None dynamicProperty[] = <empty> activeNic[] = <empty> standbyNic[] = <empty> } } offloadPolicy = (HostNetOffloadCapabilities){ dynamicType = None dynamicProperty[] = <empty> csumOffload = None tcpSegmentation = None zeroCopyXmit = None } shapingPolicy = (HostNetworkTrafficShapingPolicy){ dynamicType = None dynamicProperty[] = <empty> enabled = None averageBandwidth = None peakBandwidth = None burstSize = None } } } Step 5: 通过设置 HostPortGroupSpec 的项目值来达到设置 PortGroup 属性的目的 一般我们需要关注的项目值在 Docs 中都有明确的指示: # 其中 policy 项的值有必须是一个 HostNetworkPolicy Data Object # 所以我们需要使用与获取 HostPortGroupSpec 相同的方式来获取 HostNetworkPolicy 对象的数据结构. policy = client_factory.create('ns0:HostNetworkPolicy') nicteaming = client_factory.create('ns0:HostNicTeamingPolicy') nicteaming.notifySwitches = True policy.nicTeaming = nicteaming port_group_name = 'fanguiju-test' vswitch_name = 'vSwitch0' vlan_id = '0' vswitch_port_group_spec.policy = policy vswitch_port_group_spec.name = port_group_name vswitch_port_group_spec.vswitchName = vswitch_name vswitch_port_group_spec.vlanId = int(vlan_id) 直到现在, 我们终于准备好了 AddPortGroup 方法的实参, 接下来就能够调用这个方法实现标准交换机端口组的创建. Step 6: 调用 AddPortGroup 方法 session.invoke_api(session.vim, 'AddPortGroup', host_network_system_val['configManager.networkSystem'], portgrp=vswitch_port_group_spec) # session.invoke_api() 的使用方法: # - 第二个参数是我们要调用的目标方法: AddPortGroup # - 第三个参数是我们要调用的目标方法 AddPortGroup 的属主 MO: HostNetowrkSystem # - 第四个~第 n 个参数是传递给目标方法 AddPortGroup 的实参 Step 7: 验证结果

优秀的个人博客,低调大师

C++ FFLIB之ffcount:通用数据分析系统

摘要: 数据分析已经变得不可或缺,几乎每个公司都依赖数据分析进行决策。在我从事的网游领域,数据分析是策划新功能、优化游戏体验最重要的手段之一。网游领域的数据分析有如下特点(开发角度): 数据量大;网游用户量大,用户行为多,存储数据量较大。 实时性要求高;比如新上的游戏功能,玩家体验和反馈希望尽快的被分析出来。 需求变化快。网游的需求变化日新月异,故要求数据分析系统能够快速的响应需求变化。 常见的数据分析系统 数据分析系统应该分为数据存储和数据分析,常见的数据分析架构有: 直接在逻辑服务中定制数据分析;这种情况往往使用mysql或这mongodb作为数据存储,优点是定制化的数据存储更加节省空间,缺点是mysql和mongodb的数据存储服务器往往成本更高,并且若增加新需求,定制化需要的开发量极大,并且维护老的数据分析代码往往十分困难,因为是高度定制化的,往往会绑定在特殊的应用背景下。 使用scribe做数据存储,使用hadoop分析数据。Facabook scribe server 可以利用hadoop分布式文件系统来存储大数据,电子商务或者sns网站往往使用这种可扩展的成熟的方案,缺点是部署和维护成本较高,中小型团队要建立hadoop集群无论从人力还是物力都相对困难。 确定需求: 数据存储尽量简单和低成本,由于日志数据的读取效率要求并不高,所以使用普通机器一般磁盘存储即可,而不需要另外使用mysql及其他nosql等。 数据分析尽量简单易开发,目前来讲,sql查询是最方便最基础的方式,所以数据应该是sql结构化的。 hadoop的部署对于中小团队仍然是望而生畏的,故要求数据分析系统部署要简单,配置容易。 ffcount 的架构 内部工作机制 时序图说明内部工作机制: 示例C++客户端代码: #include "count/ffcount.h" #include "rpc/broker_application.h" #include "base/daemon_tool.h" #include "base/arg_helper.h" using namespace ff; #include <stdio.h> #define NUM 0 int main(int argc, char* argv[]) { arg_helper_t arg_helper(argc, argv); if (false == arg_helper.is_enable_option("-l")) { printf("usage: app -l tcp://127.0.0.1:10241\n"); return 1; } assert(0 == singleton_t<msg_bus_t>::instance().open(arg_helper.get_option_value("-l")) && "can't connnect to broker"); assert(singleton_t<msg_bus_t>::instance().get_service_group("event_log_service") && "event_log_service group not exist"); assert(singleton_t<msg_bus_t>::instance().get_service_group("event_log_service")->get_service(0) && "event_log_service 0 not exist"); event_log_t el("test"/*dbname*/,"dumy"/*tablename*/, "A,B,C"/*fields name*/);el.def(100, "p\"T'p", 5.4); singleton_t<msg_bus_t>::instance().get_service_group("event_log_service")->get_service(0)->async_call(el); for (int i = 0; i < NUM; ++i) { char buff[64]; snprintf(buff, sizeof(buff), "dumy_%d", i%8); event_log_t el(buff, "A,B,C");el.def(100, "pp", 5.4); singleton_t<msg_bus_t>::instance().get_service_group("event_log_service")->get_service(0)->async_call(el); } event_queryt_t::in_t in_msg; in_msg.db_name = "test"; in_msg.sql = "select * from dumy"; struct lambda_t { static void callback(event_queryt_t::out_t& msg_) { printf("=====>>>>> callback dump data [%s]<<<<<<=======\n", msg_.err_msg.c_str()); ffdb_t::dump(msg_.ret_data, msg_.col_names); event_log_t el("test", "dumy", "A,B,C");el.def(100, "p\"T'p", 5.4); singleton_t<msg_bus_t>::instance().get_service_group("event_log_service")->get_service(0)->async_call(el); for (int i = 0; i < NUM; ++i) { char buff[64]; snprintf(buff, sizeof(buff), "dumy_%d", i%8); event_log_t el(buff, "A,B,C");el.def(100, "pp", 5.4); singleton_t<msg_bus_t>::instance().get_service_group("event_log_service")->get_service(0)->async_call(el); } sleep(1); event_queryt_t::in_t in_msg; //in_msg.str_time = "2013/2";//! 查询1月的数据 in_msg.db_name = "test"; in_msg.sql = "select * from dumy order by logtime desc limit 5"; singleton_t<msg_bus_t>::instance().get_service_group("event_log_service")->get_service(0)->async_call(in_msg, &lambda_t::callback); } }; singleton_t<msg_bus_t>::instance().get_service_group("event_log_service")->get_service(0)->async_call(in_msg, &lambda_t::callback); signal_helper_t::wait(); singleton_t<msg_bus_t>::instance().close(); return 0; } 示例php客户端 <?php function ffcount_query($host, $port, $str_time, $db_name, $sql) { //以下为引用的内容: // 1. 初始化 $ch = curl_init(); // 2. 设置选项,包括URL $url = "http://".$host.":".$port."/".$str_time."/".$db_name."/".rawurlencode($sql); //echo $url."\n"; curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HEADER, 0); // 3. 执行并获取HTML文档内容 $output = curl_exec($ch); // 4. 释放curl句柄 curl_close($ch); if ($output === FALSE) { //echo "cURL Error: " . curl_error($ch); $ret = array("err_msg" =>"http request failed by curl", "col_names"=>array(), "ret_data"=>array()); } else { $ret = json_decode($output); if (!$ret) { $ret = array("err_msg" =>$output, "col_names"=>array(), "ret_data"=>array()); } } return $ret; } $host = "127.0.0.1"; $port = 8080; $str_time = "2013/2"; $db_name = "test"; $sql = "select * from dumy"; $ret = ffcount_query($host, $port, $str_time, $db_name, $sql); print_r($ret); ?> 示例C++ server启动: ./app_count -l tcp://127.0.0.1:10241 -http tcp://127.0.0.1:8080 总结: ffcount 根本上提供的是数据日志存储 ffcount 使用sql来组织日志文件,从而拥有了sql数据分析能力 ffcount 数据文件按照每月归档 ffcount 自动创建表和字段,默认创建autoid和logtime两字段,前者为自增主键,后者为timestamp类型,默认为当前时间 ffcount 支持http查询,数据存储接口已经有C++ 类库接口 build server: git clone https://github.com/fanchy/fflib cd fflib/example/book/count && make && ./app_count -l tcp://127.0.0.1:10241 -http tcp://127.0.0.1:8080 build client: cd fflib/example/book/count_client && make && ./app_client -l tcp://127.0.0.1:10241 php client: cd fflib/example/book/count_client/php && php test.php

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册