㈠ android输入事件模拟
在一些自动化测试等情景下,输入Android应用程序产生一些屏幕点击等的输入事件以实现特定需求。本文总结了几种Android中模拟产生输入事件的方式。
在Android中有两个shell中运行的工具可以模拟培棚产生输入事件 input 和 sendevent 。由于sendevent需要用到相应的设备,需要考虑权限问题,因此一般不常用,这里只介绍input。
如点击屏幕(200,300)处只需要如下命令即可:
Instrumentation是Android提供的一个测试工具,可以通过它监测系统与应用程序之间的交互。使用此方法需要如下的 system 权限:
Instrumentation模拟点击屏幕(200,300)事件的方法如下:
Android Inputmanager的 injectEvent() 方法配让则也可以模拟产生输入事件(API16以上版本)。不过此方法属于隐藏方法,需要滑嫌反射调用,这里不作具体描述。
1 https://www.pocketmagic.net/injecting-events-programatically-on-android/#.VKn42M2UfCI
㈡ 如何让所有 View 都可以带上点击的水波纹效果
V2EX›Android
如何让所有 View 都可以带上点击的水波纹效果?
AtlantisZ· 2015-11-12 23:49:00 +08:00
这是一个创建于 483 天前的主题,其中的信息可能已经有所发展或是发生改变。
根据 G官方文档
定制触摸反馈
材料设计中的触摸反馈可在用户与 UI 元素互动时,在接触点上提供即时视觉确认。适用于按钮的默认触摸动画使用全新 RippleDrawable 类别,以波纹效果实现不同状态间的转换。
在大多数情况下,您应以下列方式指定视图背景,在您的视图 XML 中应用此功能:
?android:attr/selectableItemBackground 指定有界的波纹
?android:attr/ 指定越界的波纹
注意: 是 API 级别 21 中推出的新属性。
此外,您可利用 ripple 元素将 RippleDrawable 定义为一个 XML 资源。
您可以为 RippleDrawable 对象指定一种颜色。如果要改变默认触摸反馈颜色,请使用主题的 android:colorControlHighlight 属性。
但是发现有时候一个 LinearLayout 设置 android:background="?android:attr/selectableItemBackground"
就带上了水波纹效果,有的不行,,TextView 也是,设置 android:background="?android:attr/selectableItemBackground"有的带上了,有的不行.
RecyclerView 的 Item layout 根布局加上了这个属性也无效果.
后来辗转反侧,找到了 Stackflow 找到的回答,也不奏效.
FrameLayout view = (FrameLayout) View.inflate(context, R.layout.item_top_news, null);
RippleDrawable drawable = (RippleDrawable) mActivity.getResources()
.getDrawable(R.drawable.ripple_background);
view.setClickable(true);
view.setForeground(drawable);
求解如何实现 BiliBili MD 客户端,几乎每个 View 点击都有的水波纹效果.
波纹
attr
Android
drawable
12 回复 |直到 2015-11-19 21:41:40 +08:00
1
little_cup 2015-11-13 00:04:55 +08:00
从设计的角度说,你不应该让所有的 View 都带上 Ripple 效果,只应该让可点击的元素带上。
从程序的角度说,你无法让所有的 View 都带上 Ripple 效果,只能让拿到点击事件的元素带上。
2
AtlantisZ 2015-11-13 00:15:38 +08:00
@little_cup额,我只是感觉很难有短文字叙述清楚问题,原来标题是如何让 RecyclerView 的子 Item 带上水波纹效果了.感觉太局限了.
请问现在 RecyclerView 的子 Item 已经可以响应点击事件跳转 Activity 了,请问如何才能带上水波纹的点击效果.我在 Item 的 layout 根布局修改 android:background="?android:attr/selectableItemBackground"没有效果.
3
little_cup 2015-11-13 00:25:24 +08:00
@AtlantisZ哪个 view 绑定 click 就给哪个设 selectableItemBackground 。当然注意不要被其他 view 在视觉上覆盖了。
4
AtlantisZ 2015-11-13 00:42:01 +08:00
在 onBindViewHolder 中
TypedValue typedValue = new TypedValue();
mActivity.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, typedValue, true);
Drawable background = getResources().getDrawable(typedValue.resourceId);
// Drawable background = getResources().getDrawable(R.drawable.ripple_background);
holder.rootView.setBackground(background);
holder.rootView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(getContext(), VideoDetailActivity.class));
// ToastUtils.showToast(mActivity, "av :: " + mRecommendList.get(position).av);
}
});
还是没有用额.
5
AtlantisZ 2015-11-13 11:17:22 +08:00
@little_cup
在 onBindViewHolder 中
TypedValue typedValue = new TypedValue();
mActivity.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, typedValue, true);
Drawable background = getResources().getDrawable(typedValue.resourceId);
// Drawable background = getResources().getDrawable(R.drawable.ripple_background);
holder.rootView.setBackground(background);
holder.rootView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(getContext(), VideoDetailActivity.class));
}
});
还是没有用额.
6
miao1007 2015-11-15 19:55:46 +08:00
这样写不会报错?
ClassNoFound 这个错误在低 API 下会出现
7
ybjaychou 2015-11-17 20:53:35 +08:00
我也是在愁这个问题,同样是在 RecyclerView 的 Item 里面,不知道怎么才能有点击效果,就算不是水纹也可以啊。。
顺便搭个车,就是怎么在 RecyclerView 里面做多选操作,然后 Toolbar 上面出现操作按钮,不知道有人做过没
8
ecma 2015-11-18 19:01:06 +08:00
同表示弄不出波纹点击效果,不知道是不是 SDK 版本的原因。
目前暂时通过 github 上一个开源项目实现那个效果了。。
https://github.com/balysv/material-ripple
9
ecma 2015-11-18 19:05:55 +08:00
@ybjaychou
我自己是在 itemView 上加入了一个 checkBox ,平常处于隐藏状态,需要批量删除的适合,重新加载 RecyclerView 让 checkBox 显示。而 checkBox 的点击事件则是往一个数组里面扔 item 的 id ,那样就知道选了那些。
toolbar 的改变的话可以通过 onPrepareOptionsMenu 和 invalidateOptionsMenu()来改变,当然也可以通过 ActionMode.Callback 来实现
通过这种方法来实现的话需要对 checkBox 的点击进行标示优化,避免列表滑动的适合 checkBox 错误问题
10
ybjaychou 2015-11-19 12:52:08 +08:00 via Android
@ecma好,谢谢,我试试!
11
AtlantisZ 2015-11-19 16:49:47 +08:00
@ybjaychou
@ecma
参考http://stackoverflow.com/questions/26961147/touch-feedback-with-recyclerview-and-cardview/29033353解决了 RecyclerView 中 Item 无水波纹效果的问题额.
12
ecma 2015-11-19 21:41:40 +08:00
@AtlantisZ
THX!等下就去试试喽
㈢ android系统开发要用哪些知识
android 技术内幕系统卷
第1章 准备工作 /1 1.1 深入认识android /2 1.1.1 android的系统构架 /2 1.1.2 android的初始化流程 /5 1.1.3 各个层次之间的相互关系 /8 1.1.4 android系统开发(移植)和应用开发 /11 1.2 获取和编译android的源码 /13 1.2.1 环境配置 /13 1.2.2 获取android源码 /14 1.2.3 编译android的源码及其工具包 /16 1.2.4 运行android系统 /21 1.3 开发环境搭建 /23 1.3.1 应用开发环境搭建 /23 1.3.2 源码开发环境搭建 /26 1.4 android源码结构 /32 1.5 小结 /33 第2章 android的内核机制和结构剖析 /34 2.1 linux与android的关系 /35 .2.1.1 为什么会选择linux /35 2.1.2 android不是linux /35 2.2 android对linux内核的改动 /37 2.2.1 goldfish /37 2.2.2 yaffs2 /38 2.2.3 蓝牙 /39 2.2.4 调度器(scheler)/39 2.2.5 android新增的驱动 /40 2.2.6 电源管理 /41 2.2.7 杂项 /41 2.3 android对linux内核的增强 /42 2.3.1 alarm(硬件时钟)/43 2.3.2 ashmem(匿名内存共享)/46 2.3.3 low memory killer(低内存管理)/52 2.3.4 logger(日志设备)/56 2.3.5 android pmem /65 2.3.6 switch /79 2.3.7 timed gpio /88 2.3.8 android ram console /94 2.4 小结 /99 第3章 android的ipc机制--binder /100 3.1 binder概述 /101 3.1.1 为什么选择binder /101 3.1.2 初识binder /102 3.2 binder驱动的原理和实现 /102 3.2.1 binder驱动的原理 /102 3.2.2 binder驱动的实现 /103 3.3 binder的构架与实现 /132 3.3.1 binder的系统构架 /132 3.3.2 binder的机制和原理 /133 3.4 小结 /150 第4章 电源管理 /151 4.1 电源管理概述 /152 4.2 电源管理结构 /152 4.3 android的电源管理机制 /153 4.4 android电源管理机制的实现 /154 4.5 小结 /187 第5章 驱动的工作原理及实现机制 /188 5.1 显示驱动(framebuffer)/189 5.1.1 framebuffer的工作原理 /189 5.1.2 framebuffer的构架 /190 5.1.3 framebuffer驱动的实现机制 /190 5.2 视频驱动(v4l和v4l2)/201 5.2.1 v4l2介绍 /201 5.2.2 v4l2的原理和构架 /201 5.2.3 v4l2的实现 /202 5.3 音频驱动(oss和alsa)/208 5.3.1 oss与alsa介绍 /208 5.3.2 oss的构架与实现 /209 5.3.3 alsa的构架与实现 /213 5.4 mtd驱动 /214 5.4.1 mtd驱动的功能 /214 5.4.2 mtd驱动的构架 /215 5.4.3 mtd驱动的原理及实现 /215 5.5 event输入设备驱动 /223 5.5.1 input的系统构架 /223 5.5.2 event输入驱动的构架 /224 5.5.3 event输入驱动的原理 /224 5.5.4 event输入驱动的实现 /225 5.6 蓝牙驱动(bluetooth)/235 5.6.1 bluetooth驱动的构架 /235 5.6.2 bluez的原理及实现 /237 5.7 wlan驱动(wi-fi)/244 5.7.1 wlan构架 /244 5.7.2 wi-fi驱动的实现原理 /245 5.8 小结 /245 第6章 原生库的原理及实现 /246 6.1 系统c库(bionic libc)/247 6.1.1 bionic libc功能概述 /247 6.1.2 bionic libc实现原理 /248 6.2 功能库 /258 6.2.1 webkit构架与实现 /258 6.2.2 多媒体框架与实现 /275 6.2.3 android sqlite框架及原理 /285 6.3 扩展库 /289 6.3.1 skia底层库分析 /289 6.3.2 opengl底层库分析 /299 6.3.3 android-openssl实现及运用 /306 6.3.4 freetype及font engine manager /317 6.3.5 freetype结构体系和渲染流程 /317 6.4 原生服务 /328 6.4.1 audioflinger实现 /328 6.4.2 surfaceflinger实现 /341 6.5 小结 /353 第7章 硬件抽象层的原理与实现 /354 7.1 硬件抽象层的实现原理 /355 7.1.1 android hal构架 /355 7.1.2 android hal的实现 /357 7.2 android overlay构架与实现 /361 7.2.1 android overlay系统构架 /361 7.2.2 overlay hal框架与实现 /362 7.2.3 overlay与surfacefinger /369 7.3 android camera 构架与实现 /375 7.3.1 android camera系统构架 /375 7.3.2 camera hal框架与实现 /377 7.3.3 camera本地实现 /385 7.4 android audio hal实现 /394 7.4.1 audio hal框架 /395 7.4.2 android默认的audio hal实现 /398 7.4.3 mp功能的audio hal实现 /400 7.4.4 基于a2dp的蓝牙音频设备hal实现 /402 7.4.5 模拟器上的audio hal实现 /403 7.5 android ril实现 /404 7.5.1 android ril构架 /404 7.5.2 radiooptiongs实现 /407 7.5.3 libril库实现 /409 7.5.4 reference-ril库实现 /415 7.5.5 rild守护进程实现 /418 7.5.6 request流程分析 /423 7.5.7 response流程分析 /427 7.6 android sensor hal实现 /434 7.6.1 android sensor构建 /434 7.6.2 sensor hal接口 /435 7.6.3 sensor hal实现 /438 7.7 android wifi hal实现 /441 7.7.1 android wifi系统构架 /441 7.7.2 wpa_supplicant框架 /442 7.7.3 wifi hal实现 /444 7.8 android蓝牙本地实现 /447 7.8.1 android蓝牙构架 /447 7.8.2 bluez结构体系 /448 7.8.3 bluez适配层 /452 7.9 android 定位实现 /453 7.9.1 定位系统构架 /453 7.9.2 gps hal实现 /454 7.10 android power hal实现 /459 7.11 android vibrator hal实现 /461 7.12 小结 /462 第8章 dalvik虚拟机的构架、原理与实现 /463 8.1 dalvik虚拟机概述 /464 8.1.1 什么是dalvik虚拟机 /464 8.1.2 dalvik虚拟机的功能 /464 8.1.3 dalvik虚拟机与java虚拟机的区别 /465 8.2 dalvik构架与实现 /466 8.2.1 dalvik系统构架 /466 8.2.2 dx和dexmp工具 /468 8.2.3 .dex文件格式解析 /470 8.2.4 dalvik内部机制 /487 8.2.5 dalvik进程管理 /492 8.2.6 dalvik内存管理 /501 8.2.7 dalvik加载器 /509 8.2.8 dalvik解释器 /517 8.2.9 dalvik jit /519 8.3 jni的构架与实现 /523 8.3.1 jni构架 /523 8.3.2 jni实现 /524 8.4 小结 /526 第9章 android 核心库 /527 9.1 android核心库简介 /528 9.2 android系统api /529 9.2.1 android包 /529 9.2.2 android资源包 /529 9.2.3 apicheck机制 /529 9.3 小结 /532 后记 /533
㈣ 度十大游戏API
应用开发者利用内容,先抓眼球,引导下载,然后坐收新用户,通过社交应用分享传根据ESA(Entertainment Software Association)最近一项报告,美国有超过1亿5千万视频 游戏 玩家,其中大约42%的人每周在视频 游戏 上花费3小时以上。根据PwC的预测:到,全球视频游戏收入将接近931.8亿美元,而全球社交/休闲游戏市场则接近225.2亿美元。如此惊人的数据摆在眼前,难怪游戏成为了ProgrammableWeb上最热门API搜索项。最近传出了很多游戏API的趣闻。9月,DMCA侵权通知(DMCA notice)发出,包括Bukkit,CraftBukkit,Spigot和Cauldron在内的一众Minecraft游戏社区项目被关闭。DMCA侵权通知事件后不久,Minecraft的开发公司Mojang就被微软公司以25亿美元的价格收购。上个月343 Instries对外宣布,他们计划专为Halo 5推出一个公共数据(public stats)API:Guardians视频游戏最近为Xbox One推出了公共数据API。今年年初,ArenaNet为Guild Wars 2 API发布了一个额外的OAuth 2.0支持,2个月后又代之以API key system。此文推荐的Top 10精品游戏API涵盖各种丰富内容,基于热度(Popularity)、潜力(Potential)、文档(Documentation)、便捷(Ease of Use)、功能(Functionality)进行对比,包括(但不仅限于)检索视频游戏数据,游戏货币化,视频游戏串流和录像,视频游戏评论和模型等等。
1. EVE Online
科幻网游巨作EVE Online(星战前夜)是最风靡的大型多人在线角色扮演游戏(MMORPG),曾获奖无数,位列时代PC游戏排行榜前100第36位。Eve Online还永久入驻了纽约现代艺术博物馆(MoMA)的应用设计(Applied Design)区,访客可在4K超高清视频前欣赏Eve Online中宏伟的宇宙景观。
EVE Online CREST和XML APIs可用于对游戏中的角色、行业、市场、太阳系、联盟和公司等数据进行编程。EVE Online开发者网站的资源页面上能找到Eve Online API, API文档,客户端库和论坛等内容。EVE Online CREST RESTful API的API文档为简单好上手的Wiki格式;Eve Online XML API的API文档已迁移至第三方开发者文档网站。
2. Riot Games
Riot Games(拳头游戏公司)开发了炙手可热的多人联机在线竞技游戏(MOBA)“英雄联盟(LOL)”。根据该公司官网数据:每天在线人数约为2700万,每月在线人数约为6700万。今年7月份,由于版本更新后游戏内存在严重缺陷,Riot Games关闭了“英雄联盟”排位赛,但游戏仍旧热度不减, 位列时代PC游戏排行榜前100第35位。
Riot Games API用于对“英雄联盟”中最近的游戏、玩家排名、符文、熟练度级别等信息进行编程。Riot Games的开发者网站设计精美,API状态页面、开发者论坛和API互动文档等内容有序呈现。
3. Battle.net
在线视频游戏网站Battle.net主要推广Blizzard Entertainment公司开发的游戏:从动作角色扮演游戏(ARPG)“暗黑破坏神(Diablo)III”,到大型多人在线角色扮演游戏(MMORPG)“魔兽世界(WoW)”;从军事科幻即时战略游戏“星际争霸(StarCraft)II”,到在线战略纸牌游戏“炉石传说(Hearthstone)”。“暗黑破坏神III”,“星际争霸II”,“魔兽世界”分别位列时代PC游戏排行榜前100第79、29、31位。
最近经Blizzard Entertainment重新设计之后,开发者网站呈现开发者论坛、OAuth、游戏社区API指南和API互动文档(I/O Docs)有机组合的新面貌。如今Battle.net API又多了暗黑破坏神III、魔兽世界、星际争霸II、Community API以及游戏数据 API。而最近该公司又在Battle.net论坛上宣布“炉石传说:魔兽英雄传(Hearthstone: Heroes of Warcraft)API即将上线。
4. Facebook Game Services
当下Facebook游戏已破2000大关,其中不乏大热门,例如“Candy Crush Saga(糖果粉碎传奇)”、“Clash of Clans(部落战争)”,“Farm Heroes Saga(农场英雄传奇)”,“Pet Rescue Saga(宠物大营救)”和“Words With Friends”。
Facebook用户主要在智能手机和平板电脑上玩游戏,还有一些选择了台式电脑。年初,Facebook开始推出一些台式电脑视频应用广告来增加游戏安装量。
Facebook Games Developer Center为游戏开发者提供包括(但不仅限于)Achievements API、Scores API、应用通知、请求、游戏中心、Facebook Unity SDK等服务。在这里可以找到游戏概览。API迁移(migration)指南、教程、清单、游戏货币化等有用信息。
5. Google Play Games Services
3月上线的Google Play集音乐、电子书、游戏、电影、期刊及其他Android应用于一身。今年3月,Google又宣布为Android游戏开发者新添游戏分析、AdMob原生广告、AdMob应用内付费广告及针对Android TV(安卓TV)的Nearby Connections第二屏API。
Google Developers:Games(谷歌开发者游戏网站)上很多API、SDK及包括(但不仅限于)game publishing API,Unity插件、Play Games Services(成就、排行榜、玩家级别等)和Google AdMob的各类服务唾手可得。Google Play Games Services网站内容虽多,但条理清晰,多而不杂。
6. Guild Wars 2
Guild Wars 2(激战2)是风靡当下的一款大型多人在线角色扮演游戏(MMORPG),故事以虚幻的泰瑞亚大陆为背景,上演着波澜壮阔的英雄史诗。上个月ArenaNet推出了首次对Guild War2的扩展版本——Guild Wars 2:Heart of Thorns(激战2:疯王)。
Guild War2的新建账户超700万,游戏时间超14亿小时,玩家互送礼物超223,484,104份,大大鼓励ArenaNet扩展了Guild War 2。Guild War 2位列时代PC游戏排行榜前100第47位。
Guild War 2 API用于对游戏道具、地图、交易站、World vs. World游戏模式及成就等游戏数据进行编程。Guild Wars 2的API文档是简单好上手的Wiki格式,使用广泛。Guild Wars 2 API论坛也很活跃,可以找到API更新和API相关问题,还能与其他开发者讨论错误和漏洞,参与API CDI线程等。
7. Steam
风靡当下的视频游戏和娱乐平台Steam有超过6,000款游戏供玩家选择,其游戏社区坐拥超过1亿用户。GameStop称Steam从去年起就“蒸蒸日上”了,游戏数量从的3,700上升到8月的6,000。今年早些时候Valve公司宣布:内容创作者可通过Steam Workshop出售针对现有游戏的mods
Steam网页API可以检索应用新闻,搜索游戏全球数据、玩家评论、玩家成就、最近玩过的游戏等数据。Steam网页API文档为1页,以Wiki模式呈现,还有很多现成的客户端库。API可以用JSON、XML、CSV和VDF(Valve Data Format)格式返回数据。
8. TwitchTV
炙手可热的实时流媒体视频平台和游戏社区Twitch当下的月均独立访客超过1亿,直播用户超过170万。虽然该平台主攻游戏,但最近Twitch Interactive公司又宣布推出Twitch Creative社区,为艺术家、工匠、开发者等创意人士提供交流空间。Twitch还跟Battle.net、Google Play Games等流行视频游戏平台进行合作,支持用Twitch账户登录进行游戏串流录像、在线直播游戏等
TwitchTV API可实现Twitch Connect、视频、串流、搜索及其他内容与第三方应用的整合。GitHub上有完整的API文档,另外Twitch网页上还有开发者论坛。
9. Giant Bomb
Giant Bomb网站不仅提供视频游戏信息,还有新闻(news)、评论(reviews)、网络(wiki)、视频(videos)、播客(podcasts)、论坛(forums)等板块。3月,Giant Bomb被CBS Interactive收购,该公司旗下还有与Giant Bomb相似的网站GameSpot。
Giant Bomb API可对Giant Bomb网页上的游戏标题、评分、视频、公司、主题、风格等内容进行编程。API文档为1页,以Wiki格式呈现;API开发者论坛上还有API快速入门指南,API改进日志等丰富信息可供参考。
10. SpongeAPI
Sponge是Minecraft服务端支持的全新modding API,既可以充当服务器,也可以用来作客户端API,修改Minecraft游戏,服务器拥有者也可以使用。Sponge这一项目是在9月份DMCA侵权通知引发CraftBukkit关闭不久后建立起来的。CraftBukkit作为Minecraft官方服务器的有益补充,用Bukkit API来建立插件,为Minecraft服务器增添新功能。
Sponge API更新很勤快,稳定的版本预计会在年末上线,但不少开发者已经开始使用和测试了,火热程度可见一斑。Sponge Web网页和GitHub上都能找到简单好上手的完整API文档。开发者还可以在官方网站上的论坛中了解更多关于Sponge项目开发和Sponge API的信息。
㈤ 如何在Android中使用OpenCV
如何在Android程序中使用OpenCV
有两种方式(重点讲后面一种):
1.使用OpenCV Java API。
OpenCV安装路径"F:OpenCV-2.3.1-android-bin"下有两个文件夹,
将文件夹"OpenCV-2.3.1"拷贝到你的Eclipse工作空间所在的目录,也就是在你的项目的上一级目录中,然后导入到工作空间中,在Package Explorer中选择你的项目,单机右键在弹出菜单中选择Properties,然后在弹出的Properties窗口中左侧选择Android,然后点击右下方的Add按钮,选择OpenCV-2.3.1并点击OK,
此时,展开你的项目树,你可以看到新加了一个OpenCV-2.3.1_src目录,如下图,那么就是正确添加了OpenCV Java API,否则就是你放置OpenCV-2.3.1的目录路径不正确。
然后就可以在你的Java源文件中导入OpenCV的API包,并且使用OpenCV API了,OpenCV API的包的形式如下:
Org.opencv.(OpenCV模块名).(OpenCV类名)
例如:
Org.opencv.core.Mat
2.利用JNI编写C++ OpenCV代码,通过Android NDK创建动态库(.so)
新建一个工作空间,例如"TestOpenCV",在Window->Preferences中设置好Android SDK的路径。
然后新建一个Android项目,Build Target选择Android2.2,命名为"HaveImgFun",活动名改为HaveImgFun,Package name中填写com.testopencv.haveimgfun,最后点击finish。
如同使用OpenCV Java API那样,将OpenCV-2.3.1文件夹拷贝到与工作空间同一级目录中;另外,将"F:OpenCV-2.3.1-android-binsamples"下的includeOpenCV.mk文件拷贝到和项目HaveImgFun同一级目录中:
(上面这个各个文件夹和文件的放置很重要,因为OpenCV-2.3.1下的OpenCV.mk中有很多相对路径的指定,如果不是这样放置,在NDK生成动态库时可能会报文件或文件夹无法找到的错误)
选择Package Explorer中你的项目,右键选择new->folder,新建一个名为jni的文件夹,用来存放你的c/c++代码。
然后把res->layout下的main.xml的内容改为下面所示:
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:orientation="vertical"
4 android:layout_width="fill_parent"
5 android:layout_height="fill_parent"
6 >
7 <Button android:layout_height="wrap_content"
8 android:layout_width="fill_parent"
9 android:id="@+id/btnNDK"
10 android:text="使用C++ OpenCV进行处理" />
11 <Button android:layout_height="wrap_content"
12 android:layout_width="fill_parent"
13 android:id="@+id/btnRestore"
14 android:text="还原" />
15 <ImageView android:id="@+id/ImageView01"
16 android:layout_width="fill_parent"
17 android:layout_height="fill_parent" />
18 </LinearLayout>
上面的代码就是一个线性布局里面包含2个按钮加上一个显示图像的ImageView
在文件夹src下的com.testopencv.haveimgfun包中新建一个类用于包装使用了opencv c++代码的动态库的导出函数,类名为LibImgFun。
Eclipse会为你创建一个新的文件LibImgFun.java,将里面的内容改为:
1 package com.testopencv.haveimgfun;
2 public class LibImgFun {
3 static {
4 System.loadLibrary("ImgFun");
5 }
6 /**
7 * @param width the current view width
8 * @param height the current view height
9 */
10 public static native int[] ImgFun(int[] buf, int w, int h);
11 }
从上面的代码可以得知,我们的动态库名字应该为“libImgFun.so”,注意"public static native int[] ImgFun(int[] buf, int w, int h)"中的native关键字,表明这个函数来自native code。static表示这是一个静态函数,这样就可以直接用类名去调用。
在jni文件夹下建立一个"ImgFun.cpp"的文件,内容改为下面所示:
1 #include <jni.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <opencv2/opencv.hpp>
5 using namespace cv;
6
7 extern "C"
8 {
9 JNIEXPORT jintArray JNICALL Java_com_testopencv_haveimgfun_LibImgFun_ImgFun(JNIEnv* env, jobject obj, jintArray buf, int w, int h);
10 JNIEXPORT jintArray JNICALL Java_com_testopencv_haveimgfun_LibImgFun_ImgFun(JNIEnv* env, jobject obj, jintArray buf, int w, int h){
11
12 jint *cbuf;
13 cbuf = env->GetIntArrayElements(buf, false);
14 if(cbuf == NULL)
15 {
16 return 0;
17 }
18
19 Mat myimg(h, w, CV_8UC4, (unsigned char*)cbuf);
20 for(int j=0;j<myimg.rows/2;j++)
21 {
22 myimg.row(j).setTo(Scalar(0,0,0,0));
23 }
24
25 int size=w * h;
26 jintArray result = env->NewIntArray(size);
27 env->SetIntArrayRegion(result, 0, size, cbuf);
28 env->ReleaseIntArrayElements(buf, cbuf, 0);
29 return result;
30 }
31 }
上面的代码中#include <jni.h>是必须要包含的头文件,#include <opencv2/opencv.hpp>是opencv要包含的头文件。
动态库要导出的函数如下声明:
JNIEXPORT jintArray JNICALL Java_com_testopencv_haveimgfun_LibImgFun_ImgFun(JNIEnv* env, jobject obj, jintArray buf, int w, int h);
JNIEXPORT 和JNICALL是必须要加的关键字
jintArray就是int[],这里返回类型要么为空,要么为jni中定义的类型,事实上就是CC++类型前面加上j,如果是数组,则在后面加上Array。
函数名的命名规则如下:
Java_(包路径)_(类名)_(函数名) (JNIEnv *env, jobject obj, 自己定义的参数...)
包路径中的"."用"_"(下划线)代替,类名就是上面包装该动态库函数的类的名字,最后一个才是真正的函数名;JNIEnv *env和jobject obj这两个参数时必须的,用来调用JNI环境下的一些函数;后面就是你自己定义的参数。在这里,jintArray buf代表了传进来的图像的数据,int w是图像的宽,int h是图像的高。
这个函数的功能是将传进来的图像的上半部分涂成黑色。
然后再在jni下新建两个文件"Android.mk"文件和"Application.mk"文件,这两个文件事实上就是简单的Makefile文件。
其中将Android.mk的内容改为如下所示:
LOCAL_PATH:=$(callmy-dir)
include$(CLEAR_VARS)
include../includeOpenCV.mk
ifeq("$(wildcard$(OPENCV_MK_PATH))","")
#trytoloadOpenCV.mkfromdefaultinstalllocation
include$(TOOLCHAIN_PREBUILT_ROOT)/user/share/OpenCV/OpenCV.mk
else
include$(OPENCV_MK_PATH)
endif
LOCAL_MODULE:=ImgFun
LOCAL_SRC_FILES:=ImgFun.cpp
include$(BUILD_SHARED_LIBRARY)
Application.mk的内容改为如下所示:
APP_STL:=gnustl_static
APP_CPPFLAGS:=-frtti-fexceptions
APP_ABI:=armeabiarmeabi-v7a
其中APP_ABI指定的是目标平台的CPU架构。(经过很多测试,android2.2必须指定为armeabi,android2.2以上的使用armeabi-v7a,如果没有设置对,很有可能安装到android虚拟机失败,当然你同时如上面写上也是可以的)
上面的步骤完成后,就可以使用NDK生成动态库了,打开cygwin,cd到项目目录下:
输入$NDK/ndk-build命令,开始创建动态库。
这时候刷新Eclipse的Package Explorer会出现两个新的文件夹obj和libs。
现在,只剩最后一步完成这个测试程序。
将一张图片,例如"lena.jpg"放到项目res->drawable-hdpi目录中并刷新该目录。
然后将HaveImgFun.java的内容改为下面所示:
1 package com.testopencv.haveimgfun;
2
3 import android.app.Activity;
4 import android.graphics.Bitmap;
5 import android.graphics.Bitmap.Config;
6 import android.graphics.drawable.BitmapDrawable;
7 import android.os.Bundle;
8 import android.widget.Button;
9 import android.view.View;
10 import android.widget.ImageView;
11
12 public class HaveImgFun extends Activity{
13 /** Called when the activity is first created. */
14 ImageView imgView;
15 Button btnNDK, btnRestore;
16
17 @Override
18 public void onCreate(Bundle savedInstanceState) {
19 super.onCreate(savedInstanceState);
20 setContentView(R.layout.main);
21
22 this.setTitle("使用NDK转换灰度图");
23 btnRestore=(Button)this.findViewById(R.id.btnRestore);
24 btnRestore.setOnClickListener(new ClickEvent());
25 btnNDK=(Button)this.findViewById(R.id.btnNDK);
26 btnNDK.setOnClickListener(new ClickEvent());
27 imgView=(ImageView)this.findViewById(R.id.ImageView01);
28 Bitmap img=((BitmapDrawable) getResources().getDrawable(R.drawable.lena)).getBitmap();
29 imgView.setImageBitmap(img);
30 }
31
32 class ClickEvent implements View.OnClickListener{
33 public void onClick(View v){
34 if(v == btnNDK){
35 long current=System.currentTimeMillis();
36 Bitmap img1=((BitmapDrawable) getResources().getDrawable(R.drawable.lena)).getBitmap();
37 int w=img1.getWidth(),h=img1.getHeight();
38 int[] pix = new int[w * h];
39 img1.getPixels(pix, 0, w, 0, 0, w, h);
40 int[] resultInt=LibImgFun.ImgFun(pix, w, h);
41 Bitmap resultImg=Bitmap.createBitmap(w, h, Config.RGB_565);
42 resultImg.setPixels(resultInt, 0, w, 0, 0,w, h);
43 long performance=System.currentTimeMillis()-current;
44 imgView.setImageBitmap(resultImg);
45 HaveImgFun.this.setTitle("w:"+String.valueOf(img1.getWidth())+",h:"+String.valueOf(img1.getHeight())+"NDK耗时"+String.valueOf(performance)+" 毫秒");
46 } else if(v == btnRestore){
47 Bitmap img2=((BitmapDrawable) getResources().getDrawable(R.drawable.lena)).getBitmap();
48 imgView.setImageBitmap(img2);
49 HaveImgFun.this.setTitle("使用OpenCV进行图像处理");
50 }
51 }
52 }
53 }
点击全部保存,OK,现在可以选择一个Android虚拟机运行看一下效果,配置好Run Configuration然后点击Run,得到下面的结果: