Android 中加载几百张图片做帧动画防止 OOM 的解决方案

最近,项目中有个需求:就是要做一个帧动画,按理说这个是很简单的!但是我能说这个帧动画拥有几百张图片吗?。。。。。。

填坑一 ---帧动画

一开始我的想法是直接用帧动画来做,可是我太天真了,当帧数放到 50 几张的时候,已经在有些机器上奔溃了!所以这个方案否决!

填坑二 ---GIF动图

虽然可以显示,但是已经卡的我,已经不想看了,直接放弃

填坑三 ---视频

在这里,我突然想到我可以直接把他做成一个小视频啊,而且可以极限压缩视频。最终,视频大小被压缩到 500K 左右。此时已经基本可以满足需求了,但是我们有好多类似的动画,要求在每个动画切换的时候要有衔接感,不能有突兀的感觉,所有在这里视频就不能很好的完成任务了,所有再次放弃,已经泪牛满面了!!!!

填坑四 --- SurfaceView + BitmapRegionDecoder +缓存

首先回答一下:为什么会想到这个解决方案?

  1. 首先在做帧动画的时候,大约每帧之间的时间差值是 40ms 可以说速度非常快了,在如此快速的图片切换上,自然而然的想到来了使用SurfaceView。
  2. 现在再来说说为什么想到要使用这个类 BitmapRegionDecoder .这个也是从我司游戏开发人员那儿得到的经验?他们在做游戏的时候,游戏中的切图都是放在一张大图上的,然后在根据对应的 xml,json 文件,获取相应的图片,接着再来切图。对此,我想能不能把所有的动图都放到同一张的图片上呢,之后在根据对应的描述文件,裁剪出我想要的图片呢!所以就用到了 BitmapRegionDecoder. 它的作用是:于显示图片的某一块矩形区域!之后,我在找设计人员商量一一下,把图片在尽量的压缩。之后从美工那儿获取的信息是这样的:

    json格式的描述文件:

  1. {"frames": [
  2. {
  3. "filename": "kidbot-正常闭眼0000",
  4. "frame": {"x":0,"y":0,"w":360,"h":300},
  5. "rotated": false,
  6. "trimmed": false,
  7. "spriteSourceSize": {"x":0,"y":0,"w":360,"h":300},
  8. "sourceSize": {"w":360,"h":300}
  9. }
  10. .....
  11. }

png图片:

接下来就好做了,解析 json 格式的文件,裁剪图片。

  1. 最后说一下为什么使用缓存,其实很简单,因为切换的频率实在太高了,没有必要每次都从图片中裁剪,这里就把裁剪出来的 bitmap 缓存起来在用。从而介绍内存开销!

最后给出代码:

  1. public class AnimView extends SurfaceView implements SurfaceHolder.Callback {
  2. private BitmapRegionDecoder bitmapRegionDecoder;
  3. private SurfaceHolder mHolder;
  4. private boolean isrunning = true;
  5. private AnimThread thread;
  6. private Paint mPaint;
  7. private int WIDTH = 0;
  8. private int HEIGHT = 0;
  9. private int state = -1;
  10. private boolean isstart = false;
  11. private boolean isblinkfirst = false;
  12. private int rate = 40;
  13. private int index = 0;
  14. private Matrix matrix;
  15. private Random rand;
  16. private Handler handler = new Handler() {
  17. public void handleMessage(android.os.Message msg) {
  18. isblinkfirst = true;
  19. };
  20. };
  21. private SparseArray<WeakReference<Bitmap>> weakBitmaps;
  22. private SparseArray<WeakReference<Bitmap>> cweakBitmaps;
  23. private BitmapFactory.Options options;
  24. public AnimView(Context context) {
  25. super(context);
  26. init();
  27. }
  28. public AnimView(Context context, AttributeSet attrs) {
  29. super(context, attrs);
  30. init();
  31. }
  32. public AnimView(Context context, AttributeSet attrs, int defStyleAttr) {
  33. super(context, attrs, defStyleAttr);
  34. init();
  35. }
  36. @SuppressLint("NewApi")
  37. private void init() {
  38. weakBitmaps = new SparseArray<WeakReference<Bitmap>>();
  39. cweakBitmaps = new SparseArray<WeakReference<Bitmap>>();
  40. mHolder = getHolder();
  41. mHolder.addCallback(this);
  42. mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  43. setState(FaceBean.BLINK);
  44. mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  45. matrix = new Matrix();
  46. float[] values = { -1f, 0.0f, 0.0f, 0.0f, 1f, 0.0f, 0.0f, 0.0f, 1.0f };
  47. matrix.setValues(values);
  48. WindowManager manger = (WindowManager) getContext().getSystemService(
  49. Context.WINDOW_SERVICE);
  50. DisplayMetrics displayMetrics = new DisplayMetrics();
  51. manger.getDefaultDisplay().getMetrics(displayMetrics);
  52. WIDTH = displayMetrics.widthPixels / 2;
  53. HEIGHT = displayMetrics.heightPixels / 2;
  54. rand = new Random();
  55. options = new Options();
  56. options.inPreferredConfig = Bitmap.Config.RGB_565;
  57. }
  58. @Override
  59. public void surfaceCreated(SurfaceHolder holder) {
  60. handler.sendEmptyMessageDelayed(0, 1000 * (4 + rand.nextInt(4)));
  61. thread = new AnimThread();
  62. thread.start();
  63. }
  64. @Override
  65. public void surfaceChanged(SurfaceHolder holder, int format, int width,
  66. int height) {
  67. }
  68. @Override
  69. public void surfaceDestroyed(SurfaceHolder holder) {
  70. if (thread != null) {
  71. thread.stopThread();
  72. }
  73. }
  74. public class AnimThread extends Thread {
  75. @Override
  76. public void run() {
  77. super.run();
  78. SurfaceHolder holder = mHolder;
  79. while (isrunning) {
  80. Canvas canvas = holder.lockCanvas();
  81. if (canvas == null)
  82. continue;
  83. synchronized (AnimThread.class) {
  84. AnimBean.Frames frames;
  85. switch (state) {
  86. case FaceBean.BLINK:
  87. frames = KidbotRobotApplication.animBlink.getFrames()
  88. .get(index);
  89. if (frames.getFrame().getW() <= 0) {
  90. } else {
  91. Rect rect = new Rect(frames.getFrame().getX(),
  92. frames.getFrame().getY(), frames.getFrame()
  93. .getX()
  94. + frames.getSourceSize().getW(),
  95. frames.getFrame().getY()
  96. + frames.getSourceSize().getH());
  97. WeakReference<Bitmap> weakBitmap = weakBitmaps
  98. .get(index);
  99. Bitmap map = null;
  100. if (weakBitmap == null) {
  101. map = bitmapRegionDecoder.decodeRegion(rect,
  102. options);
  103. weakBitmaps.put(index,
  104. new WeakReference<Bitmap>(map));
  105. } else {
  106. map=weakBitmap.get();
  107. if (map == null) {
  108. map = bitmapRegionDecoder.decodeRegion(
  109. rect, options);
  110. weakBitmaps.put(index,
  111. new WeakReference<Bitmap>(map));
  112. }
  113. }
  114. if (map == null) {
  115. holder.unlockCanvasAndPost(canvas);
  116. continue;
  117. }
  118. mPaint.setXfermode(new PorterDuffXfermode(
  119. Mode.CLEAR));
  120. canvas.drawPaint(mPaint);
  121. mPaint.setXfermode(new PorterDuffXfermode(Mode.SRC));
  122. canvas.drawBitmap(map,
  123. (int) (WIDTH - (map.getWidth() * 1) - 150),
  124. (int) (HEIGHT - (map.getHeight() / 2)),
  125. mPaint);
  126. canvas.drawBitmap(map, (int) (WIDTH + 150),
  127. (int) (HEIGHT - (map.getHeight() / 2)),
  128. mPaint);
  129. if (index == 0) {
  130. }
  131. if (map.isRecycled()) {
  132. map.recycle();
  133. }
  134. }
  135. if (!isstart) {
  136. if (index < KidbotRobotApplication.animBlink
  137. .getFrames().size()) {
  138. index++;
  139. if (index == KidbotRobotApplication.animBlink
  140. .getFrames().size()) {
  141. index--;
  142. isstart = true;
  143. if (rand.nextInt(10) <= 2) {
  144. index = 1;
  145. }
  146. }
  147. } else {
  148. index--;
  149. isstart = true;
  150. }
  151. } else {
  152. if (index > 0) {
  153. index--;
  154. if (index == 0) {
  155. isstart = false;
  156. }
  157. } else {
  158. index++;
  159. isstart = false;
  160. }
  161. }
  162. if (!isblinkfirst) {
  163. index = 0;
  164. } else {
  165. if (index == KidbotRobotApplication.animBlink
  166. .getFrames().size() - 1) {
  167. isblinkfirst = false;
  168. index = 0;
  169. handler.sendEmptyMessageDelayed(0,
  170. 1000 * (4 + rand.nextInt(4)));
  171. }
  172. }
  173. break;
  174. case FaceBean.ANGRY:
  175. frames = KidbotRobotApplication.animAngry.getFrames()
  176. .get(index);
  177. if (frames.getFrame().getW() <= 0) {
  178. } else {
  179. Rect rect = new Rect(frames.getFrame().getX(),
  180. frames.getFrame().getY(), frames.getFrame()
  181. .getX() + frames.getFrame().getW(),
  182. frames.getFrame().getH()
  183. + frames.getFrame().getX());
  184. WeakReference<Bitmap> weakBitmap = weakBitmaps
  185. .get(index);
  186. Bitmap map = null;
  187. if (weakBitmap == null) {
  188. map = bitmapRegionDecoder.decodeRegion(rect,
  189. options);
  190. weakBitmaps.put(index,
  191. new WeakReference<Bitmap>(map));
  192. } else {
  193. map=weakBitmap.get();
  194. if (map == null) {
  195. map = bitmapRegionDecoder.decodeRegion(
  196. rect, options);
  197. weakBitmaps.put(index,
  198. new WeakReference<Bitmap>(map));
  199. }
  200. }
  201. if (map == null) {
  202. holder.unlockCanvasAndPost(canvas);
  203. continue;
  204. }
  205. mPaint.setXfermode(new PorterDuffXfermode(
  206. Mode.CLEAR));
  207. canvas.drawPaint(mPaint);
  208. mPaint.setXfermode(new PorterDuffXfermode(Mode.SRC));
  209. Bitmap dstbmp =null;
  210. weakBitmap=cweakBitmaps.get(index);
  211. if(weakBitmap==null){
  212. dstbmp = Bitmap.createBitmap(map, 0, 0,
  213. map.getWidth(), map.getHeight(),
  214. matrix, true);
  215. cweakBitmaps.put(index,
  216. new WeakReference<Bitmap>(dstbmp));
  217. }else{
  218. dstbmp=weakBitmap.get();
  219. if(dstbmp==null){
  220. dstbmp = Bitmap.createBitmap(map, 0, 0,
  221. map.getWidth(), map.getHeight(),
  222. matrix, true);
  223. cweakBitmaps.put(index,
  224. new WeakReference<Bitmap>(dstbmp));
  225. }
  226. }
  227. canvas.drawBitmap(
  228. map,
  229. frames.getSpriteSourceSize().getX()
  230. + (int) (WIDTH
  231. - (map.getWidth() * 1) - 150),
  232. frames.getSpriteSourceSize().getY()
  233. + (int) (HEIGHT - (map.getHeight() / 2)),
  234. mPaint);
  235. canvas.drawBitmap(dstbmp, frames
  236. .getSpriteSourceSize().getX()
  237. + (int) (WIDTH + 150), frames
  238. .getSpriteSourceSize().getY()
  239. + (int) (HEIGHT - (map.getHeight() / 2)),
  240. mPaint);
  241. if (dstbmp.isRecycled()) {
  242. dstbmp.recycle();
  243. }
  244. if (map.isRecycled()) {
  245. map.recycle();
  246. }
  247. }
  248. if (!isstart) {
  249. if (index < KidbotRobotApplication.animAngry
  250. .getFrames().size()) {
  251. index++;
  252. if (index == KidbotRobotApplication.animAngry
  253. .getFrames().size()) {
  254. index--;
  255. isstart = true;
  256. }
  257. } else {
  258. index--;
  259. isstart = true;
  260. }
  261. } else {
  262. if (index > 0) {
  263. index--;
  264. if (index == 0) {
  265. isstart = false;
  266. }
  267. } else {
  268. index++;
  269. isstart = false;
  270. }
  271. }
  272. break;
  273. case FaceBean.HAPPY:
  274. frames = KidbotRobotApplication.animHappy.getFrames()
  275. .get(index);
  276. if (frames.getFrame().getW() <= 0) {
  277. } else {
  278. Rect rect = new Rect(frames.getFrame().getX(),
  279. frames.getFrame().getY(), frames.getFrame()
  280. .getX()
  281. + frames.getSourceSize().getW(),
  282. frames.getFrame().getY()
  283. + frames.getSourceSize().getH());
  284. WeakReference<Bitmap> weakBitmap = weakBitmaps
  285. .get(index);
  286. Bitmap map = null;
  287. if (weakBitmap == null) {
  288. map = bitmapRegionDecoder.decodeRegion(rect,
  289. options);
  290. weakBitmaps.put(index,
  291. new WeakReference<Bitmap>(map));
  292. } else {
  293. map=weakBitmap.get();
  294. if (map == null) {
  295. map = bitmapRegionDecoder.decodeRegion(
  296. rect, options);
  297. weakBitmaps.put(index,
  298. new WeakReference<Bitmap>(map));
  299. }
  300. }
  301. if (map == null) {
  302. holder.unlockCanvasAndPost(canvas);
  303. continue;
  304. }
  305. mPaint.setXfermode(new PorterDuffXfermode(
  306. Mode.CLEAR));
  307. canvas.drawPaint(mPaint);
  308. mPaint.setXfermode(new PorterDuffXfermode(Mode.SRC));
  309. Bitmap dstbmp =null;
  310. weakBitmap=cweakBitmaps.get(index);
  311. if(weakBitmap==null){
  312. dstbmp = Bitmap.createBitmap(map, 0, 0,
  313. map.getWidth(), map.getHeight(),
  314. matrix, true);
  315. cweakBitmaps.put(index,
  316. new WeakReference<Bitmap>(dstbmp));
  317. }else{
  318. dstbmp=weakBitmap.get();
  319. if(dstbmp==null){
  320. dstbmp = Bitmap.createBitmap(map, 0, 0,
  321. map.getWidth(), map.getHeight(),
  322. matrix, true);
  323. cweakBitmaps.put(index,
  324. new WeakReference<Bitmap>(dstbmp));
  325. }
  326. }
  327. canvas.drawBitmap(
  328. map,
  329. frames.getSpriteSourceSize().getX()
  330. + (int) (WIDTH
  331. - (map.getWidth() * 1) - 150),
  332. frames.getSpriteSourceSize().getY()
  333. + (int) (HEIGHT - (map.getHeight() / 2)),
  334. mPaint);
  335. canvas.drawBitmap(dstbmp, frames
  336. .getSpriteSourceSize().getX()
  337. + (int) (WIDTH + 150), frames
  338. .getSpriteSourceSize().getY()
  339. + (int) (HEIGHT - (map.getHeight() / 2)),
  340. mPaint);
  341. // if (dstbmp.isRecycled()) {
  342. // dstbmp.recycle();
  343. // }
  344. // if (map.isRecycled()) {
  345. // map.recycle();
  346. // }
  347. }
  348. if (!isstart) {
  349. if (index < KidbotRobotApplication.animHappy
  350. .getFrames().size()) {
  351. index++;
  352. if (index == KidbotRobotApplication.animHappy
  353. .getFrames().size()) {
  354. index--;
  355. isstart = true;
  356. }
  357. } else {
  358. index--;
  359. isstart = true;
  360. }
  361. } else {
  362. if (index > 0) {
  363. index--;
  364. if (index == 0) {
  365. isstart = false;
  366. }
  367. } else {
  368. index++;
  369. isstart = false;
  370. }
  371. }
  372. break;
  373. case FaceBean.RESOLVE:
  374. break;
  375. case FaceBean.RISUS:
  376. break;
  377. case FaceBean.SEERIGHT:
  378. break;
  379. case FaceBean.SAD:
  380. frames = KidbotRobotApplication.animSad.getFrames()
  381. .get(index);
  382. if (frames.getFrame().getW() <= 0) {
  383. } else {
  384. Rect rect = new Rect(frames.getFrame().getX(),
  385. frames.getFrame().getY(), frames.getFrame()
  386. .getX()
  387. + frames.getSourceSize().getW(),
  388. frames.getFrame().getY()
  389. + frames.getSourceSize().getH());
  390. WeakReference<Bitmap> weakBitmap = weakBitmaps
  391. .get(index);
  392. Bitmap map = null;
  393. if (weakBitmap == null) {
  394. map = bitmapRegionDecoder.decodeRegion(rect,
  395. options);
  396. weakBitmaps.put(index,
  397. new WeakReference<Bitmap>(map));
  398. } else {
  399. map=weakBitmap.get();
  400. if (map == null) {
  401. map = bitmapRegionDecoder.decodeRegion(
  402. rect, options);
  403. weakBitmaps.put(index,
  404. new WeakReference<Bitmap>(map));
  405. }
  406. }
  407. if (map == null) {
  408. holder.unlockCanvasAndPost(canvas);
  409. continue;
  410. }
  411. mPaint.setXfermode(new PorterDuffXfermode(
  412. Mode.CLEAR));
  413. canvas.drawPaint(mPaint);
  414. mPaint.setXfermode(new PorterDuffXfermode(Mode.SRC));
  415. Bitmap dstbmp =null;
  416. weakBitmap=cweakBitmaps.get(index);
  417. if(weakBitmap==null){
  418. dstbmp = Bitmap.createBitmap(map, 0, 0,
  419. map.getWidth(), map.getHeight(),
  420. matrix, true);
  421. cweakBitmaps.put(index,
  422. new WeakReference<Bitmap>(dstbmp));
  423. }else{
  424. dstbmp=weakBitmap.get();
  425. if(dstbmp==null){
  426. dstbmp = Bitmap.createBitmap(map, 0, 0,
  427. map.getWidth(), map.getHeight(),
  428. matrix, true);
  429. cweakBitmaps.put(index,
  430. new WeakReference<Bitmap>(dstbmp));
  431. }
  432. }
  433. canvas.drawBitmap(
  434. map,
  435. frames.getSpriteSourceSize().getX()
  436. + (int) (WIDTH
  437. - (map.getWidth() * 1) - 150),
  438. frames.getSpriteSourceSize().getY()
  439. + (int) (HEIGHT - (map.getHeight() / 2)),
  440. mPaint);
  441. canvas.drawBitmap(dstbmp, frames
  442. .getSpriteSourceSize().getX()
  443. + (int) (WIDTH + 150), frames
  444. .getSpriteSourceSize().getY()
  445. + (int) (HEIGHT - (map.getHeight() / 2)),
  446. mPaint);
  447. if (dstbmp.isRecycled()) {
  448. dstbmp.recycle();
  449. }
  450. if (map.isRecycled()) {
  451. map.recycle();
  452. }
  453. }
  454. if (!isstart) {
  455. if (index < KidbotRobotApplication.animSad
  456. .getFrames().size()) {
  457. index++;
  458. if (index == KidbotRobotApplication.animSad
  459. .getFrames().size()) {
  460. index--;
  461. isstart = true;
  462. }
  463. } else {
  464. index--;
  465. isstart = true;
  466. }
  467. } else {
  468. if (index > 0) {
  469. index--;
  470. if (index == 0) {
  471. isstart = false;
  472. }
  473. } else {
  474. index++;
  475. isstart = false;
  476. }
  477. }
  478. break;
  479. default:
  480. break;
  481. }
  482. }
  483. holder.unlockCanvasAndPost(canvas);
  484. try {
  485. Thread.sleep(rate);
  486. } catch (InterruptedException e) {
  487. e.printStackTrace();
  488. }
  489. }
  490. }
  491. public void stopThread() {
  492. isrunning = false;
  493. try {
  494. join();
  495. } catch (InterruptedException e) {
  496. e.printStackTrace();
  497. }
  498. }
  499. }
  500. public synchronized void setRate(int rate) {
  501. this.rate = rate;
  502. }
  503. public int getState() {
  504. return this.state;
  505. }
  506. public synchronized void setState(int state) {
  507. // if (FaceBean.BLINK == this.state) {
  508. // while ((index != KidbotRobotApplication.animBlink.getFrames()
  509. // .size() - 1)) {
  510. // continue;
  511. // }
  512. // }
  513. cweakBitmaps.clear();
  514. weakBitmaps.clear();
  515. this.state = state;
  516. this.index = 0;
  517. switch (state) {
  518. case FaceBean.BLINK:
  519. try {
  520. bitmapRegionDecoder = BitmapRegionDecoder.newInstance(
  521. getContext().getAssets().open("kidbot_blink.png"),
  522. false);
  523. } catch (IOException e) {
  524. e.printStackTrace();
  525. }
  526. break;
  527. case FaceBean.ANGRY:
  528. try {
  529. bitmapRegionDecoder = BitmapRegionDecoder.newInstance(
  530. getContext().getAssets().open("kidbot_angry.png"),
  531. false);
  532. } catch (IOException e) {
  533. e.printStackTrace();
  534. }
  535. break;
  536. case FaceBean.HAPPY:
  537. try {
  538. bitmapRegionDecoder = BitmapRegionDecoder.newInstance(
  539. getContext().getAssets().open("kidbot_happy.png"),
  540. false);
  541. } catch (IOException e) {
  542. e.printStackTrace();
  543. }
  544. break;
  545. case FaceBean.RESOLVE:
  546. try {
  547. bitmapRegionDecoder = BitmapRegionDecoder.newInstance(
  548. getContext().getAssets().open("kidbot_blink.png"),
  549. false);
  550. } catch (IOException e) {
  551. e.printStackTrace();
  552. }
  553. break;
  554. case FaceBean.RISUS:
  555. try {
  556. bitmapRegionDecoder = BitmapRegionDecoder.newInstance(
  557. getContext().getAssets().open("kidbot_blink.png"),
  558. false);
  559. } catch (IOException e) {
  560. e.printStackTrace();
  561. }
  562. break;
  563. case FaceBean.SEERIGHT:
  564. break;
  565. case FaceBean.SAD:
  566. try {
  567. bitmapRegionDecoder = BitmapRegionDecoder.newInstance(
  568. getContext().getAssets().open("kidbot_sad.png"), false);
  569. } catch (IOException e) {
  570. e.printStackTrace();
  571. }
  572. break;
  573. }
  574. }
  575. public synchronized void setRunning(boolean isrunning) {
  576. this.isrunning = isrunning;
  577. }
  578. public synchronized void addIndex() {
  579. this.index++;
  580. }
  581. }

Android 中加载几百张图片做帧动画防止 OOM 的解决方案的更多相关文章

  1. Android中加载位图的方法

    Android中加载位图的关键的代码: AssetManager assets =context.getAssets(); //用一个AssetManager 对象来从应用程序包的已编译资源中为工程加 ...

  2. Android中加载事件的方式

    Android中加载事件的方式 通过内部类的方式实现 通过外部类的方式实现 通过属性的方式实现 通过自身实现接口的方式实现 通过内部类的方式实现 Demo btn_Login.setOnClickLi ...

  3. android中加载的html获取的宽高不正确

    wap页面使用 js库是zepto,按照惯例在$(function(){})中,来获取当前可视区的宽高,但得到的宽高却与预想的相差十万八千里. 原本android手机的浏览器设定的宽高基本是360*6 ...

  4. Android 中加载本地Html 跨域问题,http协议允许加载

    一.需求: 后台加载HTML的包时间太长,太卡,让把所有的HTML包放到前台:使用的是file://协议,有些内容和样式加载不出来,H5那边说需要用http://协议来加载: 二.处理过程: 安卓最简 ...

  5. Android高效加载大图、多图解决方案,有效避免程序内存溢出现象

    好久没有写博客了,今天就先写一个小的关于在Android中加载大图如何避免内存溢出的问题. 后面会写如何使用缓存技术的核心类,android.support.v4.util.LruCache来加载图片 ...

  6. Android图片加载框架Picasso最全使用教程1

    Picasso介绍 Picasso是Square公司开源的一个Android图形缓存库 A powerful image downloading and caching library for And ...

  7. Android图片加载库:最全面的Picasso讲解

    前言 上文已经对当今 Android主流的图片加载库 进行了全面介绍 & 对比 如果你还没阅读,我建议你先移步这里阅读 今天我们来学习其中一个Android主流的图片加载库的使用 - Pica ...

  8. Android动态加载so文件

    在Android中调用动态库文件(*.so)都是通过jni的方式,而且往往在apk或jar包中调用so文件时,都要将对应so文件打包进apk或jar包,工程目录下图: 以上方式的存在的问题: 1.缺少 ...

  9. Android应用开发提高系列(4)——Android动态加载(上)——加载未安装APK中的类

    前言 近期做换肤功能,由于换肤程度较高,受限于平台本身,实现起来较复杂,暂时搁置了该功能,但也积累了一些经验,将分两篇文章来写这部分的内容,欢迎交流! 关键字:Android动态加载 声明 欢迎转载, ...

随机推荐

  1. TocControl控件图层无法显示问题

    在窗口里的层层嵌套SplitContainer后,出现最内层SplitContainer内部TocControl控件图层无法显示问题:加载完mxd后代后加上axTOCControl1.SetBuddy ...

  2. msado.tli

    // Created by Microsoft (R) C/C++ Compiler Version 10.00.40219.01 (d0b01b1b).//// e:\threadpool\mysq ...

  3. 从pdf 文件中抽取特定的页面

    前段时间买了一个kindle 电子书阅读器.我想用它来读的pdf文档.当然最主要是用来读python标准库&mysql的官方文档. 问题就来了.这两个都是大头书.之前用mac看还好.用kind ...

  4. JVM虚拟机(五):JDK8内存模型—消失的PermGen

    一.JVM 内存模型 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 1.虚拟机栈: 每个线程有一个私有的栈,随着线程的创建而创建.栈里面存着的是一种叫“ ...

  5. 【Android】14.1 内部文件存储和读取

    分类:C#.Android.VS2015: 创建日期:2016-02-27 一.简介 内部存储(Internal storage)是指将应用程序建立的私有文件保存在内部存储器(移动经销商卖的那种容量较 ...

  6. echarts报表

    <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding= ...

  7. [基础]sizeof和strlen

    转自网络 首先切记,sizeof不能用来求字符串长度 1.sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型.该类型保证能容纳实现所建立的最大对象的字 ...

  8. 用c++封装linux系统调用

    #include <pthread.h> #include <cstdlib> #include <ctime> #include <iostream> ...

  9. linux进程同步机制_转

    转自:Linux进程同步机制 具体应用可参考:线程同步       IPC之信号量 为了能够有效的控制多个进程之间的沟通过程,保证沟通过程的有序和和谐,OS必须提供一 定的同步机制保证进程之间不会自说 ...

  10. 深入分析DDR(转载)

    深入分析:我们为何需要DDR2内存技术 http://www.cnblogs.com/thx-bj/archive/2008/04/02/1134040.html 文/IT168评测室特约 Myddn ...