Android中贪吃蛇游戏的学习(三)

文章分类:移动开发

视图VIew的类的Snake的,主要关注的学习的类。

Java代码
  1. packagecom.easyway.dev.android.snake;
  2. importjava.util.ArrayList;
  3. importjava.util.Random;
  4. importandroid.content.Context;
  5. importandroid.content.res.Resources;
  6. importandroid.os.Bundle;
  7. importandroid.os.Handler;
  8. importandroid.os.Message;
  9. importandroid.util.AttributeSet;
  10. importandroid.util.Log;
  11. importandroid.view.KeyEvent;
  12. importandroid.view.View;
  13. importandroid.widget.TextView;
  14. /**
  15. *View类是Android的一个超类,这个类几乎包含了所有的屏幕类型。但它们之间有一些不同。每一个view
  16. *都有一个用于绘画的画布。这个画布可以用来进行任意扩展。
  17. *
  18. *一个项目的R.java文件是一个定义所有资源的索引文件。使用这个类就像使用一种速记方式来引用你项
  19. *目中包含的资源。这个有点特别的强大像对于Eclipse这类IDE的代码编译特性,因为它使你快速的,互动
  20. *式的定位你正在寻找的特定引用。
  21. *
  22. *到目前需要注意的重要事情是叫做”layout”的内部类和他的成员变量”main”,插件会通知你添加一个新
  23. *的XML布局文件,然后从新产生这个R.java文件,比如你添加了新的资源到你的项目,你将会看到R.java
  24. *也相应的改变了。放在你的项目目录的res/文件夹下。“res”是”resources”的缩写,它是存放所有非
  25. *代码资源的文件夹,包含象图片,本地化字符串和XML布局文件。
  26. *
  27. *
  28. *SnakeView:implementationofasimplegameofSnake
  29. *创建的view中一般要传入一个Context的实例,Context可以控制系统的调用,它提供了诸如资源解析
  30. *,访问数据库等。Activty类继承自Context类。
  31. *
  32. *视图也可以被嵌套,但和J2ME不同,我们可以将定制的视图和Android团队发布的Widgets一起使用。
  33. *在J2ME中,开发人员被迫选择GameCanvas和J2ME应用程序画布。这就意味着如果我们想要一个定制
  34. *的效果,就必须在GameCanvas上重新设计我们所有的widget。Android还不仅仅是这些,视图类型
  35. *也可以混合使用。Android还带了一个widget库,这个类库包括了滚动条,文本实体,进度条以及其
  36. *他很多控件。这些标准的widget可以被重载或被按着我们的习惯定制。
  37. *
  38. */
  39. publicclassSnakeViewextendsTileView{
  40. privatestaticfinalStringTAG="SnakeView";
  41. /**
  42. *Currentmodeofapplication:READYtorun,RUNNING,oryouhavealready
  43. *lost.staticfinalintsareusedinsteadofanenumforperformance
  44. *reasons.
  45. */
  46. privateintmMode=READY;
  47. publicstaticfinalintPAUSE=0;
  48. publicstaticfinalintREADY=1;
  49. publicstaticfinalintRUNNING=2;
  50. publicstaticfinalintLOSE=3;
  51. /**
  52. *设置方向
  53. *Currentdirectionthesnakeisheaded.
  54. */
  55. privateintmDirection=NORTH;
  56. privateintmNextDirection=NORTH;
  57. privatestaticfinalintNORTH=1;
  58. privatestaticfinalintSOUTH=2;
  59. privatestaticfinalintEAST=3;
  60. privatestaticfinalintWEST=4;
  61. /**
  62. *LabelsforthedrawablesthatwillbeloadedintotheTileViewclass
  63. */
  64. privatestaticfinalintRED_STAR=1;
  65. privatestaticfinalintYELLOW_STAR=2;
  66. privatestaticfinalintGREEN_STAR=3;
  67. /**
  68. *mScore:usedtotrackthenumberofapplescapturedmMoveDelay:numberof
  69. *millisecondsbetweensnakemovements.Thiswilldecreaseasapplesare
  70. *captured.
  71. */
  72. privatelongmScore=0;
  73. privatelongmMoveDelay=600;
  74. /**
  75. *mLastMove:trackstheabsolutetimewhenthesnakelastmoved,andisused
  76. *todetermineifamoveshouldbemadebasedonmMoveDelay.
  77. */
  78. privatelongmLastMove;
  79. /**
  80. *mStatusText:textshowstotheuserinsomerunstates
  81. */
  82. privateTextViewmStatusText;
  83. /**
  84. *用于存储贪吃蛇中,苹果和蛇的点阵的坐标的信息的集合
  85. *mSnakeTrail:alistofCoordinatesthatmakeupthesnake'sbody
  86. *mAppleList:thesecretlocationofthejuicyapplesthesnakecraves.
  87. */
  88. privateArrayList<Coordinate>mSnakeTrail=newArrayList<Coordinate>();
  89. privateArrayList<Coordinate>mAppleList=newArrayList<Coordinate>();
  90. /**
  91. *为创建苹果坐标使用随机对象
  92. *Everyoneneedsalittlerandomnessintheirlife
  93. */
  94. privatestaticfinalRandomRNG=newRandom();
  95. /**
  96. *刷新界面处理器
  97. *Createasimplehandlerthatwecanusetocauseanimationtohappen.We
  98. *setourselvesasatargetandwecanusethesleep()
  99. *functiontocauseanupdate/invalidatetooccuratalaterdate.
  100. */
  101. privateRefreshHandlermRedrawHandler=newRefreshHandler();
  102. /**
  103. *实现刷新的功能:
  104. *在J2ME中,刷新都是在canvas中通过调用线程结合repaint()来刷新,他们使线程不断去循环,
  105. *去调用canvas,笔者在android入门时也曾经想用J2ME的模式用在android中,结果报异常了,
  106. *为什么呢?很多人认为Dalvik虚拟机是一个Java虚拟机,因为Android的编程语言恰恰就是Java语言。
  107. *但是这种说法并不准确,因为Dalvik虚拟机并不是按照Java虚拟机的规范来实现的,两者并不兼容;
  108. *同时还要两个明显的不同:Java虚拟机运行的是Java字节码,而Dalvik虚拟机运行的则是其专有的
  109. *文件格式DEX(DalvikExecutable)。所以在以前JAVA里面能使用的模式,可能在android
  110. *里面用不起来。在自带的例子里面他是通过消息的机制来刷新的。而在android的消定义比较广泛,
  111. *比如,手机的暂停,启动,来电话、短信,键盘按下,弹起都是一个消息。总的来说,事件就是消息;
  112. *只要继承Handler类就可以对消息进行控制,或者处理,根据具体情况进行具体处理:
  113. *
  114. *@authorAdministrator
  115. *@date2010-5-24
  116. *@version1.0
  117. *@sinceJDK6.0
  118. */
  119. classRefreshHandlerextendsHandler{
  120. /**
  121. *响应消息
  122. */
  123. @Override
  124. publicvoidhandleMessage(Messagemsg){
  125. SnakeView.this.update();
  126. SnakeView.this.invalidate();
  127. }
  128. /**
  129. *向外提供人工的调用消息的接口
  130. *@paramdelayMillis
  131. */
  132. publicvoidsleep(longdelayMillis){
  133. //注销消息
  134. this.removeMessages(0);
  135. //添加消息
  136. sendMessageDelayed(obtainMessage(0),delayMillis);
  137. }
  138. };
  139. /**
  140. *ConstructsaSnakeViewbasedoninflationfromXML
  141. *
  142. *@paramcontext
  143. *@paramattrs
  144. */
  145. publicSnakeView(Contextcontext,AttributeSetattrs){
  146. super(context,attrs);
  147. initSnakeView();
  148. }
  149. publicSnakeView(Contextcontext,AttributeSetattrs,intdefStyle){
  150. super(context,attrs,defStyle);
  151. initSnakeView();
  152. }
  153. /**
  154. *初始化界面的
  155. */
  156. privatevoidinitSnakeView(){
  157. setFocusable(true);
  158. Resourcesr=this.getContext().getResources();
  159. resetTiles(4);
  160. loadTile(RED_STAR,r.getDrawable(R.drawable.redstar));
  161. loadTile(YELLOW_STAR,r.getDrawable(R.drawable.yellowstar));
  162. loadTile(GREEN_STAR,r.getDrawable(R.drawable.greenstar));
  163. }
  164. /**
  165. *初始化新的游戏
  166. */
  167. privatevoidinitNewGame(){
  168. mSnakeTrail.clear();
  169. mAppleList.clear();
  170. //Fornowwe'rejustgoingtoloadupashortdefaulteastboundsnake
  171. //that'sjustturnednorth
  172. //设置初始化蛇的位置
  173. mSnakeTrail.add(newCoordinate(7,7));
  174. mSnakeTrail.add(newCoordinate(6,7));
  175. mSnakeTrail.add(newCoordinate(5,7));
  176. mSnakeTrail.add(newCoordinate(4,7));
  177. mSnakeTrail.add(newCoordinate(3,7));
  178. mSnakeTrail.add(newCoordinate(2,7));
  179. mNextDirection=NORTH;
  180. //Twoapplestostartwith
  181. //设置苹果的位置
  182. addRandomApple();
  183. addRandomApple();
  184. //
  185. mMoveDelay=600;
  186. //设置积分的
  187. mScore=0;
  188. }
  189. /**
  190. *GivenaArrayListofcoordinates,weneedtoflattenthemintoanarrayof
  191. *intsbeforewecanstuffthemintoamapforflatteningandstorage.
  192. *
  193. *@paramcvec:aArrayListofCoordinateobjects
  194. *@return:asimplearraycontainingthex/yvaluesofthecoordinates
  195. *as[x1,y1,x2,y2,x3,y3...]
  196. */
  197. privateint[]coordArrayListToArray(ArrayList<Coordinate>cvec){
  198. intcount=cvec.size();
  199. int[]rawArray=newint[count*2];
  200. for(intindex=0;index<count;index++){
  201. Coordinatec=cvec.get(index);
  202. rawArray[2*index]=c.x;
  203. rawArray[2*index+1]=c.y;
  204. }
  205. returnrawArray;
  206. }
  207. /**
  208. *Savegamestatesothattheuserdoesnotloseanything
  209. *ifthegameprocessiskilledwhileweareinthe
  210. *background.
  211. *
  212. *@returnaBundlewiththisview'sstate
  213. */
  214. publicBundlesaveState(){
  215. Bundlemap=newBundle();
  216. map.putIntArray("mAppleList",coordArrayListToArray(mAppleList));
  217. map.putInt("mDirection",Integer.valueOf(mDirection));
  218. map.putInt("mNextDirection",Integer.valueOf(mNextDirection));
  219. map.putLong("mMoveDelay",Long.valueOf(mMoveDelay));
  220. map.putLong("mScore",Long.valueOf(mScore));
  221. map.putIntArray("mSnakeTrail",coordArrayListToArray(mSnakeTrail));
  222. returnmap;
  223. }
  224. /**
  225. *Givenaflattenedarrayofordinatepairs,wereconstitutethemintoa
  226. *ArrayListofCoordinateobjects
  227. *
  228. *@paramrawArray:[x1,y1,x2,y2,...]
  229. *@returnaArrayListofCoordinates
  230. */
  231. privateArrayList<Coordinate>coordArrayToArrayList(int[]rawArray){
  232. ArrayList<Coordinate>coordArrayList=newArrayList<Coordinate>();
  233. intcoordCount=rawArray.length;
  234. for(intindex=0;index<coordCount;index+=2){
  235. Coordinatec=newCoordinate(rawArray[index],rawArray[index+1]);
  236. coordArrayList.add(c);
  237. }
  238. returncoordArrayList;
  239. }
  240. /**
  241. *Restoregamestateifourprocessisbeingrelaunched
  242. *
  243. *@paramicicleaBundlecontainingthegamestate
  244. */
  245. publicvoidrestoreState(Bundleicicle){
  246. setMode(PAUSE);
  247. //从资源中获取ArrayList
  248. mAppleList=coordArrayToArrayList(icicle.getIntArray("mAppleList"));
  249. mDirection=icicle.getInt("mDirection");
  250. mNextDirection=icicle.getInt("mNextDirection");
  251. mMoveDelay=icicle.getLong("mMoveDelay");
  252. mScore=icicle.getLong("mScore");
  253. mSnakeTrail=coordArrayToArrayList(icicle.getIntArray("mSnakeTrail"));
  254. }
  255. /**
  256. *重点的控制代码
  257. *
  258. *实现键盘事件:键盘主要起操作作用,在任何的手机游戏中键盘都是起重要的用,要本游戏中,
  259. *他就是起控制蛇的行走方向:现在我们分析他的代码:
  260. *就是通过判断那个键按下,然后再给要走的方向(mDirection)赋值。
  261. *
  262. *handleskeyeventsinthegame.Updatethedirectionoursnakeistraveling
  263. *basedontheDPAD.Ignoreeventsthatwouldcausethesnaketoimmediately
  264. *turnbackonitself.
  265. *
  266. *(non-Javadoc)
  267. *
  268. *@seeandroid.view.View#onKeyDown(int,android.os.KeyEvent)
  269. */
  270. @Override
  271. publicbooleanonKeyDown(intkeyCode,KeyEventmsg){
  272. if(keyCode==KeyEvent.KEYCODE_DPAD_UP){
  273. if(mMode==READY|mMode==LOSE){
  274. /*
  275. *Atthebeginningofthegame,ortheendofapreviousone,
  276. *weshouldstartanewgame.
  277. */
  278. initNewGame();
  279. setMode(RUNNING);
  280. update();
  281. return(true);
  282. }
  283. if(mMode==PAUSE){
  284. /*
  285. *Ifthegameismerelypaused,weshouldjustcontinuewhere
  286. *weleftoff.
  287. */
  288. setMode(RUNNING);
  289. update();
  290. return(true);
  291. }
  292. if(mDirection!=SOUTH){
  293. mNextDirection=NORTH;
  294. }
  295. return(true);
  296. }
  297. if(keyCode==KeyEvent.KEYCODE_DPAD_DOWN){
  298. if(mDirection!=NORTH){
  299. mNextDirection=SOUTH;
  300. }
  301. return(true);
  302. }
  303. if(keyCode==KeyEvent.KEYCODE_DPAD_LEFT){
  304. if(mDirection!=EAST){
  305. mNextDirection=WEST;
  306. }
  307. return(true);
  308. }
  309. if(keyCode==KeyEvent.KEYCODE_DPAD_RIGHT){
  310. if(mDirection!=WEST){
  311. mNextDirection=EAST;
  312. }
  313. return(true);
  314. }
  315. returnsuper.onKeyDown(keyCode,msg);
  316. }
  317. /**
  318. *SetstheTextViewthatwillbeusedtogiveinformation(suchas"Game
  319. *Over"totheuser.
  320. *
  321. *@paramnewView
  322. */
  323. publicvoidsetTextView(TextViewnewView){
  324. mStatusText=newView;
  325. }
  326. /**
  327. *Updatesthecurrentmodeoftheapplication(RUNNINGorPAUSEDorthelike)
  328. *aswellassetsthevisibilityoftextviewfornotification
  329. *
  330. *@paramnewMode
  331. */
  332. publicvoidsetMode(intnewMode){
  333. intoldMode=mMode;
  334. mMode=newMode;
  335. if(newMode==RUNNING&oldMode!=RUNNING){
  336. mStatusText.setVisibility(View.INVISIBLE);
  337. update();
  338. return;
  339. }
  340. Resourcesres=getContext().getResources();
  341. CharSequencestr="";
  342. if(newMode==PAUSE){
  343. str=res.getText(R.string.mode_pause);
  344. }
  345. if(newMode==READY){
  346. str=res.getText(R.string.mode_ready);
  347. }
  348. if(newMode==LOSE){
  349. str=res.getString(R.string.mode_lose_prefix)+mScore
  350. +res.getString(R.string.mode_lose_suffix);
  351. }
  352. mStatusText.setText(str);
  353. mStatusText.setVisibility(View.VISIBLE);
  354. }
  355. /**
  356. *
  357. *生成苹果位置的代码:
  358. *苹果的位置就是更简单了,他是随机生成的,而且必须在现在蛇的位置相对远距离。
  359. *
  360. *Selectsarandomlocationwithinthegardenthatisnotcurrentlycovered
  361. *bythesnake.Currently_could_gointoaninfiniteloopifthesnake
  362. *currentlyfillsthegarden,butwe'llleavediscoveryofthisprizetoa
  363. *trulyexcellentsnake-player.
  364. *
  365. */
  366. privatevoidaddRandomApple(){
  367. CoordinatenewCoord=null;
  368. booleanfound=false;
  369. while(!found){
  370. //随机生成新的X,Y位置
  371. //Chooseanewlocationforourapple
  372. intnewX=1+RNG.nextInt(mXTileCount-2);
  373. intnewY=1+RNG.nextInt(mYTileCount-2);
  374. newCoord=newCoordinate(newX,newY);
  375. //Makesureit'snotalreadyunderthesnake
  376. booleancollision=false;
  377. intsnakelength=mSnakeTrail.size();
  378. for(intindex=0;index<snakelength;index++){
  379. //检查一下存放的位置是否合理
  380. if(mSnakeTrail.get(index).equals(newCoord)){
  381. collision=true;
  382. }
  383. }
  384. //ifwe'rehereandthere'sbeennocollision,thenwehave
  385. //agoodlocationforanapple.Otherwise,we'llcircleback
  386. //andtryagain
  387. found=!collision;
  388. }
  389. if(newCoord==null){
  390. Log.e(TAG,"SomehowendedupwithanullnewCoord!");
  391. }
  392. //添加苹果的列表中的
  393. mAppleList.add(newCoord);
  394. }
  395. /**
  396. *Handlesthebasicupdateloop,checkingtoseeifweareintherunning
  397. *state,determiningifamoveshouldbemade,updatingthesnake'slocation.
  398. */
  399. publicvoidupdate(){
  400. if(mMode==RUNNING){
  401. longnow=System.currentTimeMillis();
  402. if(now-mLastMove>mMoveDelay){
  403. clearTiles();
  404. updateWalls();
  405. updateSnake();
  406. updateApples();
  407. mLastMove=now;
  408. }
  409. mRedrawHandler.sleep(mMoveDelay);
  410. }
  411. }
  412. /**
  413. *调用以上的方法以循环的方式位置数组赋值以及图片的索引。
  414. *
  415. *Drawssomewalls.
  416. *
  417. */
  418. privatevoidupdateWalls(){
  419. for(intx=0;x<mXTileCount;x++){
  420. setTile(GREEN_STAR,x,0);//设置顶部的界限的位置
  421. setTile(GREEN_STAR,x,mYTileCount-1);//设置底部界限的位置
  422. }
  423. for(inty=1;y<mYTileCount-1;y++){
  424. setTile(GREEN_STAR,0,y);//设置顶部的界限的位置
  425. setTile(GREEN_STAR,mXTileCount-1,y);//设置底部界限的位置
  426. }
  427. }
  428. /**
  429. *Drawssomeapples.
  430. *
  431. */
  432. privatevoidupdateApples(){
  433. for(Coordinatec:mAppleList){
  434. setTile(YELLOW_STAR,c.x,c.y);
  435. }
  436. }
  437. /**
  438. *设置当前蛇的方向位置:
  439. *从以上的键盘代码我们可以看得出,程序中是通过触发来改变坐标(+1,-1)的方式来改蛇头的方向,
  440. *可见坐标在游戏编程中的作用,这个也是根据手机的屏幕是点阵的方式来显示,所以坐标就是一个
  441. *定位器。在这里大家可能还有一个疑问。就是就这个蛇什么能够以“7”字形来移动行走,其实我们
  442. *稍微仔细观察一下就知道了,在这里面,他们也是通过坐标的传递来实现的,只要把头部的坐标点
  443. *依次赋给下一个点,后面的每一个点都走过了头部所走过的点,而蛇的头部就是负责去获取坐标,整
  444. *个蛇的行走起来就很自然和连贯。坐标的方向变换又是通过判断那个方向按键的按下来改变的,这
  445. *样一来,键盘的作用就发挥出来了。蛇吃苹果又是怎样去实现?上面我所说到的坐标就起了作用。在蛇
  446. *所经过的每一个坐标,他们都要在苹果所在的(ArrayList<Coordinate>mAppleList=new
  447. *ArrayList<Coordinate>())坐标集里面集依次判断,若是坐标相同,那个这个苹果就被蛇吃了。
  448. *
  449. *Figureoutwhichwaythesnakeisgoing,seeifhe'srunintoanything(the
  450. *walls,himself,oranapple).Ifhe'snotgoingtodie,wethenaddtothe
  451. *frontandsubtractfromtherearinordertosimulatemotion.Ifwewantto
  452. *growhim,wedon'tsubtractfromtherear.
  453. *
  454. */
  455. privatevoidupdateSnake(){
  456. booleangrowSnake=false;
  457. //grabthesnakebythehead
  458. //获取蛇的头部
  459. Coordinatehead=mSnakeTrail.get(0);
  460. //创建一个新的蛇的头部应该的位置
  461. CoordinatenewHead=newCoordinate(1,1);
  462. //根据当前的为方向设置坐标的信息
  463. mDirection=mNextDirection;
  464. switch(mDirection){
  465. caseEAST:{
  466. newHead=newCoordinate(head.x+1,head.y);
  467. break;
  468. }
  469. caseWEST:{
  470. newHead=newCoordinate(head.x-1,head.y);
  471. break;
  472. }
  473. caseNORTH:{
  474. newHead=newCoordinate(head.x,head.y-1);
  475. break;
  476. }
  477. caseSOUTH:{
  478. newHead=newCoordinate(head.x,head.y+1);
  479. break;
  480. }
  481. }
  482. //Collisiondetection
  483. //Fornowwehavea1-squarewallaroundtheentirearena
  484. if((newHead.x<1)||(newHead.y<1)||(newHead.x>mXTileCount-2)
  485. ||(newHead.y>mYTileCount-2)){
  486. setMode(LOSE);
  487. return;
  488. }
  489. //Lookforcollisionswithitself
  490. intsnakelength=mSnakeTrail.size();
  491. for(intsnakeindex=0;snakeindex<snakelength;snakeindex++){
  492. Coordinatec=mSnakeTrail.get(snakeindex);
  493. if(c.equals(newHead)){
  494. setMode(LOSE);
  495. return;
  496. }
  497. }
  498. //Lookforapples
  499. //查找苹果设置苹果新的位置的信息
  500. intapplecount=mAppleList.size();
  501. for(intappleindex=0;appleindex<applecount;appleindex++){
  502. Coordinatec=mAppleList.get(appleindex);
  503. if(c.equals(newHead)){
  504. mAppleList.remove(c);
  505. addRandomApple();
  506. mScore++;
  507. //设置的移动的速度
  508. mMoveDelay*=0.9;
  509. growSnake=true;
  510. }
  511. }
  512. //将蛇头的位置信息放在第一个的对象中方取值
  513. //pushanewheadontotheArrayListandpulloffthetail
  514. mSnakeTrail.add(0,newHead);
  515. //exceptifwewantthesnaketogrow
  516. if(!growSnake){
  517. mSnakeTrail.remove(mSnakeTrail.size()-1);
  518. }
  519. intindex=0;
  520. for(Coordinatec:mSnakeTrail){
  521. if(index==0){
  522. setTile(YELLOW_STAR,c.x,c.y);
  523. }else{
  524. setTile(RED_STAR,c.x,c.y);
  525. }
  526. index++;
  527. }
  528. }
  529. /**
  530. *用于存储每一个位点的x,y坐标信息
  531. *Simpleclasscontainingtwointegervaluesandacomparisonfunction.
  532. *There'sprobablysomethingIshoulduseinstead,butthiswasquickand
  533. *easytobuild.
  534. *
  535. */
  536. privateclassCoordinate{
  537. publicintx;
  538. publicinty;
  539. publicCoordinate(intnewX,intnewY){
  540. x=newX;
  541. y=newY;
  542. }
  543. publicbooleanequals(Coordinateother){
  544. if(x==other.x&&y==other.y){
  545. returntrue;
  546. }
  547. returnfalse;
  548. }
  549. @Override
  550. publicStringtoString(){
  551. return"Coordinate:["+x+","+y+"]";
  552. }
  553. }
  554. }

更多相关文章

  1. Android中设置分割线
  2. Android(安卓)欢迎界面设置
  3. AndroidManifest.xml - activity 详细说明
  4. android根据字体大小设置控件高度
  5. Android(安卓)系统功能设置菜单 LinearLayout与relativeLayout的
  6. Android-Google自己的下拉刷新组件SwipeRefreshLayout
  7. 安卓开发09:常用控件-TextView文本展示
  8. Android(安卓)属性系统: Android(安卓)Property System
  9. Android(安卓)处理屏幕解锁和设置锁屏密码

随机推荐

  1. Android关于桌面快捷方式工具类!
  2. android显示gif图片
  3. Surface Flinger boot flow in Android s
  4. android获得手机cpu型号
  5. Android(安卓)Questions (问题集锦)
  6. android sqlite lock
  7. android折叠展开列表动态修改显示测试
  8. Android实现手机定位的案例代码
  9. 简析API属性——API 23 view.View
  10. Android P 限制级API调用弹窗关闭