Îȶ¨ÐÔÓëÄÚ´æÓÅ»¯
Ëæ×ÅAndroid¼¼ÊõµÄ·¢Õ¹¸÷ÖÖ¿ªÔ´¿â²ã³ö²»Ç¿ª·¢Ò»¸öAndroidÓ¦ÓÃÒѾ±äµÃÈÝÒ×Á˺ܶࡣȻ¶ø¿ª·¢Ò»¸öÉÌÒµÓ¦Óò¢²»Êǵ¥´¿ÊÇʵÏÖÒµÎñÐèÇóÄÇô¼òµ¥£¬¿ª·¢Íê³ÉÖ»ÊÇ»ù´¡£¬ºóÐø»¹ÐèÒª¾¹ýQAͬѧµÄÑϸñ²âÊÔ¡£È»¶ø¶ÔÓÚСÐÍ´´Òµ¹«Ë¾À´Ëµ£¬ÎÒÃDz¢Ã»ÓÐBATµÈ´ó³§ÀïµÄ²âÊÔÆ½Ì¨¡¢·½°¸Ñо¿Ô±£¬ÎÒÃÇQA×ÊÔ´±È½ÏÓÐÏÞ£¬Èç¹û½«Ò»Çз¢ÏÖÎÊÌâµÄÖØµ£¶¼½»¸ø²âÊÔ²¿ÃÅ£¬²»µ«ºÄ·ÑµÄ²âÊÔÖÜÆÚ³¤£¬¶øÇÒÓÐһЩÎÊÌ⽫ÄÑÒÔ·¢ÏÖ¡£ÀýÈçij¸öcrashÖ»»áÔÚij¸ö³¡¾°Ï¸´ÏÖ£¬Ä³¸öÄÚ´æÐ¹Â©Ö»ÓÐÔÚÓû§Ö´ÐÐÁËij¸ö²Ù×÷²Å»á³öÏÖ£¬¶øQAͬѧÔÚ²âÊÔʱ²¢²»Ò»¶¨Äܹ»Ö´Ðе½ÄÇÌõcrashµÄ²âÊÔ·¾¶¡£¶ÔÓÚÄÚ´æÐ¹Â©À´Ëµ£¬¼´Ê¹²âÊÔµ½ÁËÄÇÌõ·¾¶£¬µ«¿ÉÄÜËûÃDz¢²»ÊÇÔÚ²âÊÔÄÚ´æÎÊÌ⣬Òò´Ë¼´Ê¹³öÏÖÁËÄÚ´æÐ¹Â©Ò²ÄÑÒÔ·¢ÏÖ¡£È»¶øÓÉÓÚÄÚ´æÐ¹Â©µ¼ÖµÄOOM¡¢¿ÕÖ¸ÕëÕýÊǵ¼ÖÂÓ¦ÓñÀÀ£µÄÁ½´óÔÒò£¬Òò´Ë¾¡ÔçµÄ·¢ÏÖ²¢ÇÒ½â¾öµôÕâÀàÎÊÌâ¶ÔÓÚÓ¦ÓÃÖÊÁ¿À´ËµÖÁ¹ØÖØÒª¡£
Ò²ÐíÓÐͬѧ»á˵ͨ¹ýLeakCanary¿ÉÒԺܷ½±ãµÄΪÎÒÃǼì²âÄÚ´æÐ¹Â©£¬µ«ÊÇÎÊÌâÊÇÎÒÃDz¢²»Äܱ£Ö¤ÎÒµÄÑз¢¡¢QAͬѧÔÚÿ¸ö°æ±¾¶¼»áͨ¹ýLeakCanaey¼ì²â¸÷¸öÒ³ÃæµÄÄÚ´æÎÊÌ⣬ÒòΪÈ˲»ÊÇ»úÆ÷£¬Äã²»Äܱ£Ö¤Ã¿Ò»´Î¶¼»á½øÐÐÊÖ¶¯»Ø¹é¡£¶øÈç¹ûÔÚ¿ª·¢ÖÐÖ±½ÓÒýÈëLeakCanary»áÍÏÂýÄãµÄ¿ª·¢ËÙ¶È¡£Òò´Ë£¬ÕÒµ½Ò»Öֵͳɱ¾¡¢¸ßÊÕÒæµÄ×Ô¶¯»¯²âÊÔ·½°¸À´±£Ö¤Ó¦ÓõÄÎȶ¨ÐÔ¶ÔÓÚ´´ÒµÐ¡ÍŶÓÀ´Ëµ»¹ÊǷdz£ÓмÛÖµµÄ¡£
ÕâÆªÎÄÕÂÎÒ¾ÍÀ´·ÖÏíÒ»ÏÂÎÒÃÇÊÇÈçºÎ±£Ö¤Ó¦ÓõÄÎȶ¨ÐÔ¡¢±ÜÃâÄÚ´æÐ¹Â©µÄ¡£Ê×ÏÈÎÒÁÐһϼ¸¸öÒªµã:
- Jenkins ³ÖÐø¼¯³É
- µ¥Ôª²âÊÔ
- Monkey ѹÁ¦²âÊÔ ÒÔ¼° logÊÕ¼¯
- ¶¨ÖÆ LeakCanary ʵÏÖÅäºÏMonkey²âÊÔµÄÄÚ´æ¼ì²â
Ò»¡¢Jenkins ³ÖÐø¼¯³Éƽ̨
ÔÚÃô½Ý·½·¨ÖУ¬³ÖÐø¼¯³ÉÊÇÆä»ùʯ£¬³ÖÐø¼¯³ÉµÄºËÐÄÊÇ×Ô¶¯»¯²âÊÔ¡£JenkinsÊÇÒ»¸ö¿ÉÀ©Õ¹µÄ³ÖÐø¼¯³Éƽ̨£¬ËüÌṩÁ˷ḻµÄ²å¼þÄܹ»Èÿª·¢ÈËÔ±Íê³É¸÷ÖÖÈÎÎñ¡£ËüÖ÷Òª×÷ÓÃÓÐÈçÏÂÁ½¸ö·½Ãæ:
- ³ÖÐø¡¢×Ô¶¯µØ¹¹½¨»òÕß²âÊÔÈí¼þÏîÄ¿;
- ¶¨Ê±µØÖ´ÐÐÈÎÎñ¡£
¶ÔÓÚAndroidÏîÄ¿À´Ëµ£¬Äã¿ÉÒÔÀí½âΪËü¿ÉÒÔ¶¨ÆÚµÄÀÈ¡´úÂ룬Ȼºó´ò°üÄãµÄÓ¦Ó㬲¢ÇÒÖ´ÐÐÒ»Ð©ÌØ¶¨µÄÈÎÎñ£¬ÀýÈç´ò°üÖ®ºóÔËÐе¥Ôª²âÊÔ¡¢Ñ¹Á¦²âÊÔ¡¢UI×Ô¶¯»¯²âÊÔ¡¢ÉÏ´«µ½fir.im Éϵȡ£JenkinsµÄÖ´ÐÐÁ÷³Ì´óÖÂÈçͼ 1-1 Ëùʾ :

ͼ 1-1
ͨ¹ý¶¨Ê±´¥·¢Jenkins¹¹½¨ÈÎÎñ£¬ËüÄܹ»×Ô¶¯´ÓgithubÀÈ¡´úÂë¡¢´ò°üapk¡¢ÔËÐÐÎÒÃǵIJâÊÔÈÎÎñ£¬×îºóÎÒÃÇ¿ÉÒÔ½«½á¹ûͨ¹ýÓʼþ·¢Ë͸øÏà¹ØÈËÔ±¡£ÀýÈçÎÒÃǵÄJenkinsÿ¸ôÁ½¸öСʱ¾Í»áÖ´ÐÐÒ»´Îµ¥Ôª²âÊÔ£¨Èç¹û´úÂëÓи͝£©£¬È»ºó½«½á¹û·¢Ë͸øÏà¹ØÈËÔ±¡£¼ÙÈçÓÐһλͬʽøÐÐÁË´úÂëÖØ¹¹£¬µ«ÊÇÒýÈëÁË´íÎó£¬ÄÇôµ¥Ôª²âÊÔ½«»á¿ìËٵķ¢ÏÖÎÊÌ⣬²¢ÇÒ×îºóͨ¹ýÓʼþ½«±¨¸æ·¢Ë͸øÏà¹ØÈËÔ±¡£Ïà¹ØÈËԱͨ¹ý±¨¸æ·¢ÏÖ´íÎóÖ®ºó¾Í»á¾¡¿ìÐÞ¸´bug, ¶ø²»ÐèÒªµÈµ½²âÊԽ׶ξ¹ý¸÷ÖÖ²âÊÔ·¾¶Ö®ºó²ÅÄÜ·¢ÏÖÎÊÌâ¡£Èç¹ûÕâ¸öÎÊÌâÔÚQA²âÊÔ½×¶ÎûÓб»¸²¸Çµ½£¬ÄÇô¾Í»áµ¼ÖÂÓÐÎÊÌâapk½»¸¶¸øÓû§¡£
¹ØÓÚÈçºÎ´î½¨Jenkinsƽ̨ÎҾͲ»×ö¹ý¶à½éÉÜ£¬Õâ·½ÃæµÄ×ÊÔ´±È½Ï¶à£¬´ó¼Ò¿ÉÒԲο¼ÏÂÃæÁ½ÆªÎÄÕ¡£
UbuntuÏ´Android¿ª·¢»·¾³
´î½¨Jenkins³ÖÐø²âÊÔÆ½Ì¨
¶þ¡¢µ¥Ôª²âÊÔ
˵µ½×Ô¶¯»¯²âÊÔ£¬³É±¾×îµÍµÄÓ¦¸ÃÊǵ¥Ôª²âÊÔ¡£µ¥Ôª²âÊԳɱ¾×îµÍ£¬µ«ÊÇÊÕÒæÈ´·Ç³£¸ß¡£ÒòΪËüÊÇ×î»ù´¡µÄ²âÊÔ£¬ÕýËùν¡°¾Å²ą֮̃£¬ÆðÓÚÀÝÍÁ£»Ç§ÀïÖ®ÐУ¬Ê¼ÓÚ×ãÏ¡±£¬Ö»Óлù´¡ÀιÌÁ˲ÅÄܱ£Ö¤¸ü¸ß²ã´ÎµÄÕýÈ·ÐÔ¡£µ«ÊÇÓÉÓÚ¹úÄÚ¿ª·¢ÈËÔ±¶ÔÓÚµ¥Ôª²âÊÔÈÏʶ²»¶à£¬ËùÒÔÄܹ»Ð´µ¥Ôª²âÊԵĿª·¢ÈËÔ±²¢²»ÊǺܶ࣬ҲÕýÒòΪÈç´ËÔÚ2015ÄêÎÒ²ÅÔÚ¡¶Android¿ª·¢½ø½×:´ÓС¹¤µ½×¨¼Ò¡·µÄµÚ¾ÅÕÂÏêϸ½²ÊöÁ˵¥Ôª²âÊÔ£¬Ò²ÊÇÏ£Íû½«ÕâЩ֪ʶ¾¡ÔçµÄÍÆ¼ö¸øÔçÆÚ½Ó´¥Android¿ª·¢µÄͬѧ£¬Òò´Ë±¾ÎIJ»»áÔٴνéÉÜÈçºÎдµ¥Ôª²âÊÔ¡£ÑÔ¹éÕý´«£¬ÕâЩ²âÊÔ²ßÂÔÆäʵºÜÔç¾ÍÓÐ×ܽá¹ý£¬×îÖøÃûµÄ¾ÍÊÇMartin FowlerµÄ²âÊÔ½ð×ÖËþ£¬Èçͼ 2-1Ëùʾ¡£
Martin FowlerÊÇÊÀ½çÖøÃûµÄÃæÏò¶ÔÏó·ÖÎöÉè¼Æ¡¢UML¡¢Ä£Ê½µÈ·½ÃæµÄר¼Ò£¬Ãô½Ý¿ª·¢·½·¨µÄ´´Ê¼ÈËÖ®Ò»£¬ÏÖΪThoughtWorks¹«Ë¾µÄÊ×ϯ¿ÆÑ§¼Ò£¬³ö°æ¹ý¡¶Öع¹:¸ÄÉÆ¼ÈÓдúÂëµÄÉè¼Æ¡·¡¢¡¶ÆóÒµÓ¦Óüܹ¹Ä£Ê½¡·µÈÃûÖø¡£

ͼ 2-1 Öн«×Ô¶¯²âÊÔ·ÖΪÁËÈý¸ö²ã´Î£¬´Óϵ½ÉÏÒÀ´ÎΪµ¥Ôª²âÊÔ¡¢ÒµÎñÂß¼²âÊÔ¡¢UI²âÊÔ£¬Ô½ÍùÉϲâÊԳɱ¾Ô½¸ß¡¢²âÊÔµÄЧÂÊÔ½µÍ£¬Ò²¾ÍÊÇ˵µ¥Ôª²âÊÔÊÇÕû¸ö²âÊÔ½ð×ÖËþÖÐͶÈë×îÉÙ¡¢ÊÕÒæ×î¸ß¡¢²âÊÔЧÂÊ×î¸ßµÄ²âÊÔÀàÐÍ¡£
¾Ù¸ö¾ßÌåµÄÀý×Ó£¬¼ÙÈçÎÒÃǵÄÓ¦ÓÃÖÐÓÐÊý¾Ý¿â»º´æ¹¦ÄÜ£¬ÄÇôÎÒÃÇÈçºÎ¿ìËÙÑéÖ¤Êý¾Ý¿â´æ´¢Ä£¿éÊÇ·ñÕýÈ·£¿Í¨³£µÄÁ÷³ÌÎÒÃÇÊÇÔËÐÐÓ¦Óõõ½UIÉϵÄÊý¾Ý£¬È»ºó¼Ç¼µ±Ç°µÄÊý¾Ý£¬Êý¾Ý´æ´¢Ö®ºó£¬È»ºóÔÙÖØÐ½øÈëÓ¦Óã¬ÔÙÓë֮ǰ¼Ç¼µÄÊý¾Ý×ö¶Ô±È£¬·´¸´Ö´ÐÐÕâ¸ö¹ý³ÌÀ´À´È·±£Êý¾ÝµÄÕýÈ·ÐÔ¡£Ã¿´Î·¢²¼Ð°汾֮ǰ²âÊÔÈËÔ±¶¼µÃÖ´ÐÐÉÏÊö²âÊÔÁ÷³Ì£¬¿ÝÔïÎÞζ²»Ëµ£¬»¹ÈÝÒ׳ö´í¡¢ÀË·Ñʱ¼ä£¬¶øÈç¹ûÎÒÃÇÓе¥Ôª²âÊÔ£¬ÄÇôÎÒÃÇÖ»ÐèÒªÔËÐÐÒ»´Îµ¥Ôª²âÊÔ£¬Èç¹û²âÊÔͨ¹ýÎÒÃǾÍÈÏΪÊý¾Ý¿â»º´æÄ£¿é»ù±¾Ã»ÓÐÎÊÌ⣬ÔÙ¼òµ¥ÅäºÏÎÒÃǵÄÈ˹¤²âÊԾͿÉÒÔͨ¹ý²âÊÔ£¬ÕâÑùÒ»À´Ð§ÂʾÍÌá¸ßÁ˺ܶࡣ
ÕâÈý¸ö²ã´ÎµÄ×Ô¶¯»¯²âÊԵķÖÅä±ÈÀý´Óϵ½ÉÏͨ³£Îª 70% ¡¢20%¡¢10%£¬¿É¼ûµ¥Ôª²âÊÔÔÚÕû¸ö×Ô¶¯»¯²âÊÔÖÐÕ¼¾ÝÁ˷dz£´óµÄ±ÈÀý¡£Í¨¹ýµ¥Ôª²âÊÔ£¬ÎÒÃÇÄܹ»»ñµÃÈçÏÂÊÕÒæ:
- ±ãÓÚºóÆÚÖØ¹¹¡£Óõ¥Ôª²âÊÔ¾¡Á¿¸²¸Ç³ÌÐòÖеÄÿһÏÄܵÄÕýÈ·ÐÔ£¬ÕâÑù¾ÍËãÊÇ¿ª·¢ºóÆÚ£¬Ò²¿ÉÒÔÓб£ÕϵØÔö¼Ó¹¦ÄÜ»òÕ߸ü¸Ä³ÌÐò½á¹¹£¬¶ø²»Óõ£ÐÄÕâ¸ö¹ý³ÌÖÐ»áÆÆ»µÔÀ´µÄ¹¦ÄÜ£¬ÒòΪµ¥Ôª²âÊÔΪ´úÂëµÄÖØ¹¹ÌṩÁ˱£ÕÏ¡£Ö»ÒªÖع¹´úÂëÖ®ºóµ¥Ôª²âÊÔÈ«²¿ÔËÐÐͨ¹ý£¬ÄÇô£¬Ôںܴó³Ì¶ÈÉϱíʾÕâ´ÎÖØ¹¹Ã»ÓÐÒýÈëеÄBug£¬µ±È»ÕâÊǽ¨Á¢ÔÚÍêÕû¡¢ÓÐЧµÄµ¥Ôª²âÊÔ¸²¸ÇÂʵĻù´¡ÉÏ;
- ÓÅ»¯Éè¼Æ¡£±àдµ¥Ôª²âÊÔ½«Ê¹Óû§´Óµ÷ÓÃÕߵĽǶȹ۲졢˼¿¼£¬ÌرðÊÇʹÓòâÊÔÇý¶¯¿ª·¢µÄ¿ª·¢·½Ê½£¬ÆÈʹÉè¼ÆÕ߰ѳÌÐòÉè¼Æ³ÉÒ×ÓÚµ÷ÓúͿɲâÊÔ£¬²¢ÇÒ½â³ýÈí¼þÖеÄñîºÏ¡£
- ¾ßÓлعéÐÔ¡£×Ô¶¯»¯µÄµ¥Ôª²âÊÔ±ÜÃâÁË´úÂë³öÏֻع飬±àдÍê³ÉÖ®ºó£¬¿ÉÒÔËæÊ±ËæµØµØ¿ìËÙÔËÐвâÊÔ¡£¶ø²»Êǽ«´úÂ벿Êðµ½É豸ÉÏ£¬È»ºóÔÙÊÖ¶¯µØ¸²¸Ç¸÷ÖÖÖ´Ðз¾¶£¬ÕâÑùµÄÐÐΪЧÂʵÍÏ¡¢ÀË·Ñʱ¼ä¡£
- Ìá¸ßÄã¶Ô´úÂëµÄÐÅÐÄ¡£Í¨¹ýµ¥Ôª²âÊÔ£¬Ï൱ÓÚÎÒÃÇ´ÓÁíÒ»¸ö½Ç¶ÈÉóÊÓÁËÎÒÃǵĴúÂ룬²¢ÇÒÑéÖ¤ÁËËüÃǵÄÕýÈ·ÐÔ£¬ÕâÑùÒ»À´Ê¹µÃÎÒÃǶÔÓÚ´úÂë¸üÓÐÐÅÐÄ£¬¶ø²»ÊÇÔÚÉÏÏßÖ®ºó»¹µ£ÐÄ»ù´¡´úÂë»á³öÏÖÎÊÌâ¡£
µ±ÎÒÃÇÓе¥Ôª²âÊÔÖ®ºó£¬ÎÒÃǾͿÉÒÔÔÚJenkinsÉÏÖ´ÐÐGradleÈÎÎñ(ÐèÒª°²×°Gradle²å¼þ)£¬ÒÔ´ËÀ´Ö´ÐÐÎÒÃǵĵ¥Ôª²âÊÔ¡£Ê×ÏÈÐèÒªÌí¼Ó¹¹½¨²½Ö裬ȻºóÑ¡Ôñ¡±Invoke Gradle Scripts¡±, È»ºóÔÚGradleÈÎÎñÏÂÈçͼ 2-2 ËùʾµÄÈÎÎñ:

ͼ 2-2
ÅäÖúÃÖ®ºóÎÒÃǾͽ«AndroidÉ豸£¨»òÕßʹÓÃÄ£ÄâÆ÷²å¼þ£©Á¬½Óµ½jenkinsÖ÷»úÉÏ£¬È»ºó´¥·¢JenkinsÈÎÎñÆô¶¯µ¥Ôª²âÊÔµÄÈÎÎñ£¬Jenkins¾Í»áÖ´ÐÐÎÒÃÇÅäÖõÄGradle½Å±¾ assembleDebug connectedDebugAndroidTest --continue ÈÎÎñ£¬Õâ¸öÈÎÎñ»á´ò°üÒ»¸ödebug°æµÄapk°ü£¬È»ºó°²×°±»²âÏîÄ¿¡¢²âÊÔÏîÄ¿£¬×îºóÖ´Ðй¤³ÌÖеĵ¥Ôª²âÊÔ¡£Èç¹ûÎÒÃÇÅäÖÃÁËÓʼþ²å¼þ£¬ÄÇôÎÒÃÇÒ²¿ÉÒÔ½«²âÊÔ±¨¸æ£¨²âÊÔ±¨¸æ´æ·ÅÔÚ build/reports/androidTests/ connected/flavors/²âÊ﵀ flavor/index.html£©Í¨¹ýÓʼþ·¢Ë͸øÏà¹ØÈËÔ±¡£Èç±í 2-1 Ëùʾ:
Óʼþ֪ͨ

±í 2-1£¨1£©
²âÊԳɹ¦

±í 2-1£¨2£©
²âÊÔʧ°Ü

±í 2-1£¨3£©
¼ÙÈç²âÊÔʧ°Ü£¬ÄÇôÎÒÃÇͨ¹ý²âÊÔ±¨¸æ¾ÍÖªµÀÊÇÄĸö²âÊÔÔËÐÐʧ°Ü£¬ÒÔ¼°ÎªÊ²Ã´Ê§°Ü£¬È»ºóÏà¹ØÈËÔ±¾Í¿ÉÒÔ¿ìËÙµÄÐÞ¸´bug£¬½«»ù´¡bug¶óɱÔÚÒ¡ÀºÖ®ÖС£
»¹Êǻص½Ç°ÎÄÌáµ½µÄ£¬Ð´µ¥Ôª²âÊÔÐèÒªÒ»¶¨µÄ֪ʶ£¬Ôõô±àдµ¥Ôª²âÊÔ²»ÊÇÄѵ㣬ÄѵãÊÇÔõôÈÃÄãµÄ´úÂë¿ÉÒÔ²âÊÔ£¬ÕâÐ©Éæ¼°µ½½âñî¡¢ÒÀÀµ×¢ÈëµÈ֪ʶ£¬ËäȻ˵ºÜdzÏÔ£¬µ«ÊǺܶ๤³Ìʦ²¢Ã»ÓÐÕæÕýÁì»áµ½ÕâЩ£¬Òò´ËÄܹ»Ð´µ¥Ôª²âÊԵŤ³ÌʦÊÇÉÙÖ®ÓÖÉÙ¡£Ò²ÕýÊÇÒòΪÕâÑù£¬ÔÚС¹«Ë¾Ö´Ðе¥Ôª²âÊԲŻáÏÔµÃÀ§ÄÑ¡£
Èý¡¢MonkeyѹÁ¦²âÊÔÓëÄÚ´æÐ¹Â©¼ì²â
½«»ù´¡µÄbug¶óɱÓÚµ¥Ôª²âÊÔºóÎÒÃÇ»¹ÒªÃæÁٸ߲ã´ÎµÄ²âÊÔÎÊÌ⣬ÀýÈçÔÚÄ³Ð©Ò³ÃæµÄijЩÇé¿öÏÂÓ¦ÓûᷢÉú±ÀÀ££¬µ«ÊDzâÊÔµÄʱºòÎÒÃÇûÓвâÊÔµ½¸Ã³¡¾°£¬Òò´Ë¾ÍÉÏÏßÖ®ºó·¢ÏÖij¸öÒ³Ãæ±ÀÀ£Ö±ÏßÉÏÉý¡£ÓÉÓÚ²âÊÔ×ÊÔ´¡¢²âÊÔʱ¼äÓÐÏÞ£¬ÕâÖÖÇé¿öÄÑÒÔ±ÜÃ⣬ΪÁ˾¡Á¿±ÜÃâÕâÖÖÇé¿öÎÒÃÇ¿ÉÒÔͨ¹ýMonkey½øÐÐѹÁ¦²âÊÔ¡£
MonkeyÊÇÒ»¿îѹÁ¦²âÊÔ¹¤¾ß£¬ËüÄܹ»¸ù¾ÝÓû§Ö¸¶¨µÄʼþ±ÈÀýÏòÖ¸¶¨µÄÓ¦Ó÷¢ËÍʼþ£¬±ÈÈç´¥Ãþʼþ¡¢µã»÷ʼþ¡¢ÆÁÄ»ÐýתµÈ£¬Í¨¹ýMonkey²âÊÔÄܹ»ÈÃÓ¦Óô¦ÔÚÒ»¸öδ֪µÄ²âÊÔ»·¾³Ï£¨Í¨Ë׵㽲¾ÍÊÇÓйæÂɵÄÔÚÓ¦ÓÃÄÚÂҵ㣩£¬Õâ¸öʱºòÎÒÃÇÍùÍùÄܹ»·¢ÏÖQAͬѧûÓвâ³öÀ´µÄbug£¬´ÓÁíÒ»¸ö²ãÃæ±£Ö¤Ó¦ÓõÄÖÊÁ¿¡£
ÔÚÖ´ÐÐMonkeyµÄ¹ý³ÌÖУ¬Èç¹ûÓ¦ÓòúÉúÁ˱ÀÀ£¡¢ANRµÈ£¬Ëü¶¼»áÊä³öÈÕÖ¾£¬²âÊÔ½áÊøÖ®ºóÈç¹û²âÊÔʧ°ÜÎÒÃÇÖ»ÐèÒª²é¿´´íÎóÈÕÖ¾¾Í¿ÉÒÔ·¢ÏÖÎÊÌâËùÔÚ¡£Í¨¹ýÕâÖÖ×Ô¶¯»¯µÄ²âÊÔ¡¢ÈÕÖ¾ÊÕ¼¯£¬ÎÒÃǾÍÄܹ»±ß¿ª·¢¡¢±ß²âÊÔ£¬¾¡ÔçµÄ·¢ÏÖ¡¢ÐÞ¸´bug¡£
ÒªÔÚJenkinsÖÐʵÏÖѹÁ¦×Ô¶¯»¯²âÊÔ£¬ÎÒÃÇÐèÒªÈçϼ¸²½:
- ͨ¹ýgradleÃüÁîÉú³Éapk£¬²¢ÇÒ°²×°
- Ö´ÐÐ monkey ½Å±¾½øÐвâÊÔ
- »ñÈ¡²¢ÇÒ·¢ËͲâÊÔ±¨¸æ
Éú³ÉapkÎÒÃÇ¿ÉÒÔͨ¹ýÌí¼Ógradle ½Å±¾ÃüÁîʵÏÖ£¬·½Ê½Óëͼ2-2ÖÐÒ»Ñù£¬Ö»ÐèÒªÎÒÃǽ«SwitchesµÄÖµÐÞ¸ÄΪ¡±assembleDebug¡±¡£È»ºóÔÚJenkinsÖÐÎÒÃÇ¿ÉÒÔΪһ¸öÏîÄ¿Ìí¼Ó¹¹½¨ÈÎÎñ£¬ÈÎÎñÀàÐÍΪ ¡°Execute Shell¡±, Èçͼ 3-1 Ëùʾ:

ͼ 3-1
Execute ShellÖеÄÄÚÈݾÍÊÇÎÒÃÇÒªÖ´ÐеĽű¾£¬×÷Ó÷ֱðΪ:
- unlock.sh - É豸½âËø£¬È»ºó²Å¿ÉÒÔÈÃMonkeyÔËÐÐÏÂÒ»²½µÄѹÁ¦²âÊÔ¡£
- Æô¶¯ÕæÕýµÄѹÁ¦²âÊÔ, ¼´Ö´ÐÐ start_monkey.sh ½Å±¾;
- ·ÖÎö²âÊÔÈÕÖ¾£¬Åж¨²âÊԵijɹ¦Óëʧ°Ü;
ÆäÖÐstart_monkey.sh×îÎªÖØÒª£¬ºËÐĽű¾ÈçÏÂËùʾ:
#! /bin/bash
project=ÄãµÄjenkinsÏîÄ¿Ãû³Æ
app_package=ÄãµÄÓ¦ÓðüÃû
# Ð¶ÔØ¾ÉÓ¦ÓÃ
adb uninstall $app_package
# ÖØÐ°²×°±»²âÊÔµÄapk
adb install -r $project/ÄãµÄappÄ£¿éÃû/build/outputs/apk/Éú³ÉµÄdebug.apk
# Ö´ÐÐmonkey½Å±¾£¬½«´íÎóÊä³öµ½monkey_error.txtÖÐ
adb shell monkey -p $app_package --ignore-crashes --ignore-timeouts --ignore-native-crashes --ignore-security-exceptions --pct-touch 40 --pct-motion 25 --pct-appswitch 10 --pct-rotation 5 -s 12358 -v -v -v --throttle 500 100000 2>$project/test_logs/monkey_error.txt 1>$project/test_logs/monkey_log.txt |
ÉÏÊö½Å±¾(ÐèÒª¸ù¾ÝÇé¿öÌæ»»µô²¿·ÖÄÚÈÝ)µÄº¬ÒåΪִÐÐ 100000´Î ʼþ£¬Ã¿´ÎʼþÏà¸ô 500ºÁÃ룬ºöÂÔ±ÀÀ£¡¢ºöÂÔANR£¬--pct-touch 40 --pct-motion 25 --pct-appswitch 10 --pct-rotation 5 ΪÉ趨¸÷ÖÖʼþµÄ°Ù·Ö±È£¬MonkeyµÄ¾ßÌå²ÎÊýÕâÀï²»ÔÙ׸Êö£¬´ó¼Ò¿ÉÒԲ鿴ÆäËûÎÄÕ¡£
ÔÚÖ´ÐÐÕâ100000´ÎʼþµÄ¹ý³ÌÖУ¬Èç¹û³öÏÖANR¡¢crash£¬ÄÇôÏà¹ØµÄÈÕÖ¾»áÊä³öµ½ $project/test_logs/monkey_error.txt ·¾¶ÖУ¬µ±²âÊÔ½áÊøÖ®ºóÎÒÃÇ¿ÉÒÔÅж¨monkey_error.txtÎļþµÄ´óС£¬Èç¹ûmonkey_error.txtÎļþÖÐÓÐÄÚÈÝÄÇÎÒÃÇÔòÈÏΪ±¾´Î²âÊÔʧ°Ü£¬È»ºóͨ¹ýÓʼþ½« monkey_error.txt ×÷Ϊ¸½¼þ·¢Ë͸øÏà¹ØÈËÔ±£¬Ïà¹ØÈËÔ±¾Í¿ÉÒÔͨ¹ý monkey_error.txt ÒÔ¼°²âÊÔÉ豸ÖÐµÄ /data/anr/traces.txt ÎļþÀ´¶¨Î»¡¢ÐÞ¸´ÎÊÌâ! ÖØÒªµÄÊÇÕâЩ²Ù×÷ÎÒÃǶ¼¿ÉÒÔÈÃJenkinsÔÚÒ¹¼ä×Ô¶¯µÄΪÎÒÃÇÀ´Íê³É£¬¶¨ÆÚÖ´ÐÐÈÎÎñ¡¢·ÖÎö±¨¸æÓëlog¡¢·¢ËÍÓʼþ£¬ÀýÈçÎÒÃǵÄJenkinsÈÎÎñ»áÔÚÿÌìÒ¹Àï 10µãÖ®ºóÖ´ÐÐѹÁ¦²âÊÔ£¬Ã¿´Î²âÊÔÅÜ8¸öСʱ£¬ÄÇôÔÚµÚ¶þÌìÔçÉÏÎÒÃǾͿÉÒԵõ½²âÊÔ±¨¸æ£¬Èç¹û·¢ÏÖÎÊÌâÎÒÃǾͿÉÒÔÔÚÔçÉϽ«ÎÊÌâ½â¾öµô£¬¶ø²»»áÍϵ½Ìá½»²âÊÔÖ®ºó!!!
Èç¹ûÄãµÄÓ¦ÓÃÄܹ»¾ÊÜ8¸öСʱѹÁ¦²âÊÔõåõïÖ®ºóûÓбÀÀ£¡¢Ã»ÓÐÄÚ´æÐ¹Â©¡¢Ã»ÓÐOOM£¬ÄÇôÔÚÒ»¶¨µÄ³Ì¶ÈÉÏÀ´ËµÄãµÄÓ¦ÓÃÒѾ¾ß±¸Ò»¶¨µÄÎȶ¨ÐÔ¡£È»ºóÎÊÌâÏÔȻûÓÐÄÇô¼òµ¥£¬ÔÚÖ´ÐÐѹÁ¦²âÊÔµÄÔçÆÚ£¬ÄãºÜ¿ÉÄÜÔÚÒ»¸öÁ¬ÐøµÄʱ¼ä¶ÎÄÚ¶¼ÃæÁÙ²âÊÔʧ°ÜµÄÎÊÌâ¡£±ÀÀ£ÎÊÌâ±È½ÏºÃ²éÕÒÔ¸Ò⣬ÄÇÈç¹ûÔÚѹÁ¦²âÊÔ¹ý³ÌÖÐÈç¹û³öÏÖÁËÄÚ´æÐ¹Â©ÎÒÃÇÔõô֪µÀÄØ£¿ÎÒÃÇÓÐûÓа취Äܹ»×Ô¶¯»¯µÄ·¢ÏÖÎÊÌ⣿
ÎÒÃǵĽâ¾ö·½°¸ÊÇͨ¹ý¶¨ÖÆ LeakCanary À´ÊµÏÖÔÚ×Ô¶¯»¯²âÊԵĹý³ÌÖÐ×Ô¶¯¼ì²âÄÚ´æÐ¹Â©£¬ÒòΪ LeakCanary ĬÈÏÊÇÔÚ·¢ÏÖÄÚ´æÐ¹Â©ÊÇÔÚ֪ͨÀ¸ÏÔʾ£¬ÕâÑù²»±ãÓÚʵÏÖ×Ô¶¯»¯¡£ÎÒÃÇͨ¹ýÐÞ¸Ä LeakCanary ·¢ÏÖÄÚ´æÐ¹Â©µÄ²ßÂÔÀ´ÊµÏÖÎÒÃǵÄÄ¿±ê£¬¼´·¢ÏÖÄÚ´æÐ¹Â©Ö®ºó½«Ïà¹ØÐÅϢдÈëµ½Ò»¸ö¾ßÌåµÄÎļþ£¬È»ºó²âÊÔÍê³ÉÖ®ºó·ÖÎöÕâ¸öÎļþ£¬Èç¹ûÕâ¸öÎļþÀïÃæÓÐÄÚÈÝ£¬ÄÇôÈÏΪ²úÉúÁËÄÚ´æÐ¹Â©£¬×îºó½«Õâ¸ölogÎļþͨ¹ýÓʼþ·¢Ë͸øÏà¹ØÈËÔ±¡£ÎÒÃǵÄÐÞ¸ÄÈçÏÂ:
public class LeakDumpService extends AbstractAnalysisResultService {
@Override
protected final void onHeapAnalyzed( HeapDump heapDump, AnalysisResult result) {
if ( !result.leakFound || result.excludedLeak ) {
return;
}
Log.e("", "### *** onHeapAnalyzed in onHeapAnalyzed , dump dir : " + heapDump.heapDumpFile. getParentFile(). getAbsolutePath());
String leakInfo = LeakCanary.leakInfo( this, heapDump, result, true);
CanaryLog.d(leakInfo);
// ½«ÄÚ´æÐ¹Â©ÈÕÖ¾
StorageUtils.saveResult( leakInfo);
}
} |
LeakCanary ¼ì²âµ½ÄÚ´æÐ¹Â©Ö®ºó¾Í»áÖ´ÐÐ LeakDumpService ÖÐµÄ onHeapAnalyzed º¯Êý£¬ÔÚÕâ¸öº¯ÊýÖÐÎÒÃǽ«Ð¹Â©µÄÐÅÏ¢±£´æµ½Ò»¸öÎļþÖУ¬Ã¿´ÎÔËÐвúÉúµÄlog»áµþ¼ÓдÈ뵽ͬһ¸öÎļþ£¬Òò´ËÈç¹ûÒ»´Î²âÊÔ²úÉúÁ˶à¸öй©ÎÒÃǾʹÓÒ»¸öÎļþÖеõ½¡£ÒªÊ¹ÓÃLeakDumpService×÷ΪLeakCanary·¢ÏÖй©ºóµÄ´¦Àí·þÎñÐèÒª½øÐÐÈçÏÂÅäÖÃ:
public final class LeakCanaryForTest {
private static String sAppPackageName = "";
private static RefWatcher sWatcher ;
public static void install( Application application) {
if (LeakCanary.isInAnalyzerProcess( application)) {
return;
}
sAppPackageName = application.getPackageName();
// ÉèÖö¨ÖÆµÄ LeakDumpService , ½« leak ÐÅÏ¢Êä³öµ½Ö¸¶¨µÄĿ¼
sWatcher = LeakCanary.refWatcher(application)
.listenerServiceClass( LeakDumpService.class)
.excludedRefs(AndroidExcludedRefs. createAppDefaults().build())
.buildAndInstall();
// disable DisplayLeakActivity
LeakCanaryInternals.setEnabled( application, DisplayLeakActivity.class, false);
}
/**
* ÊÖ¶¯¼à¿ØÒ»¸ö¶ÔÏó, ±ÈÈçÔÚ Fragment µÄ onDestroy º¯ÊýÖÐ µ÷Óà watch ¼à¿ØFragmentÊÇ·ñ±»»ØÊÕ.
* @param target
*/
public static void watch(Object target) {
if ( sWatcher != null ) {
sWatcher.watch(target);
}
}
} |
ͨ¹ýµ÷ÓÃLeakCanaryForTestµÄinstallº¯Êý£¬ÎÒÃǾͿÉÒÔ½«LeakDumpService×÷ΪLeakCanary·¢ÏÖй©ºóµÄ´¦Àí·þÎñ¡£ÕâÑùÒ»À´£¬ÎÒÃǾͿÉÒÔÔÚÖ´ÐÐѹÁ¦²âÊÔʱͨ¹ý LeakCanary ¼ì²âÄÚ´æÐ¹Â©£¬²¢ÇÒ½«ÄÚ´æÐ¹Â©Êä³öµ½Ò»¸öÈÕÖ¾ÎļþÖУ¬×îºóͨ¹ýÓʼþµÃµ½Õâ¸öÈÕÖ¾£¬È»ºó¸ù¾ÝÈÕÖ¾ÐÞ¸´ÄÚ´æÐ¹Â©ÎÊÌâ¡£ÒòΪѹÁ¦²âÊÔµÄʼþÊÇËæ»úÐԵģ¬Òò´ËËüÄܹ»·¢ÏÖһЩ±È½ÏÒþ±ÎµÄÎÊÌ⣬ÕâЩ²âÊÔ·¾¶¿ÉÄÜÎÒÃǵÄQAͬѧ²»»á²âÊÔµ½£¬Òò´ËMonkey ½áºÏ LeakCanary ÍùÍùÄܹ»µÃµ½ÒâÏë²»µ½µÄЧ¹û.
ÄÚ´æÐ¹Â©¼ì²âЧ¹ûÈçͼ 3-2 Ëùʾ:

ͼ3-2
2017-03-27_leak.txt¾ÍÊÇÄÚ´æÐ¹Â©µÄÈÕÖ¾Îļþ, ²¿·ÖÈÕÖ¾ÈçÏÂËùʾ:
In com.mynews:2.2.2:101.
* com.°üÃû·¾¶.NewsDetailActivity has leaked:
* GC ROOT static android. os.AsyncTask.SERIAL_EXECUTOR
* references android.os. AsyncTask$SerialExecutor.mTasks
* references java.util. ArrayDeque.elements
* references array java .lang.Object[].[0]
* references android.os. AsyncTask$SerialExecutor$1.val$r ( anonymous implementation of java.lang.Runnable)
* references android.widget. TextView$3.this$0 (anonymous implementation of java.lang.Runnable)
* references android.support. v7.widget.AppCompatEditText.mContext
* references android.support. v7.widget.TintContextWrapper.mBase
* references android.view. ContextThemeWrapper.mBase
* leaks com.°üÃû·¾¶.NewsDetailActivity instance |
Èç¹ûÄãÒ»´óÔçÀ´µ½¹«Ë¾¾ÍÊÕµ½ÁËÄÚ´æÐ¹Â©²âÊÔ½á¹ûµÄ±¨¸æ£¬ÄÇô¹§Ï²Ä㣬ÄãÓÖ¼´½«½â¾öÁËÒ»¸öÒþ±ÎµÄÄÚ´æÎÊÌâ! µ±È»£¬Ã»ÓÐÈËÔ¸ÒâÔÚÒ»´óÔç´ò¿ªÓʼþ¾Í¿´µ½ÕâÀàµÄ²âÊÔ±¨¸æ¡£µ«ÕâÓֺγ¢²»ÊÇÒ»¼þºÃÊ£¬Í¨¹ý×Ô¶¯»¯µÄÊֶξ¡ÔçµÄ·¢ÏÖÎÊÌ⣬½â¾öÎÊÌ⣬½µµÍÁ˳ɱ¾¡¢ÌáÉýÁËÓ¦ÓÃÖÊÁ¿¡£¾¹ýÒ»¶Îʱ¼äÖ®ºó£¬ÎÒÃÇÏàÐÅÓ¦ÓÃÄÚµÄÄÚ´æÐ¹Â©ÎÊÌâ»á»ù±¾Éϱ»ÏûÃðµô!
ËÄ¡¢¿ª·¢Óë²âÊÔ¸ôÀë
È»¶ø£¬ÎÒÃDz¢²»ÊÇÔÚ¿ª·¢µÄʱºò½« LeakCanary ÒýÈëµ½ÎÒÃǵŤ³ÌÖУ¬ÒòΪËü»áÍÏÂýÎÒÃǵıàÒëËÙ¶È£¬ÔÚ¿ª·¢²âÊÔ¹ý³ÌÖÐ LeakCanary µÄÄÚ´æ¼ì²âÒ²»áµ¼ÖÂÓ¦ÓÃÔËÐп¨¶Ù¡£±ÈÈçÎÒÃÇֻϣÍûÔÚÔËÐÐѹÁ¦²âÊÔʱÒýÈë LeakCanary ½øÐÐÄÚ´æ¼ì²â£¬ÄÇôÎÒÃÇ¿ÉÒÔн¨Ò»¸ö module £¨ÕâÀïÎÒÃÇÔÝÇÒ½Ð×ö leakfortest £©, ¸ÃÄ£¿éÒýÓÃÁË LeakCanary, È»ºó½« LeakCanaryForTest¡¢LeakDumpServiceµÈÀà·â×°µ½Õâ¸öÄ£¿éÖУ¬²¢ÇÒÔÚѹÁ¦²âÊÔµÄʱºòÒýÓÃËü¡£ÕâÑùÎÒÃǵÄÓ¦ÓÃÄ£¿ébuild.gradle¾ÍÐèÒª×öÀàËÆÈçϵÄÐÞ¸Ä:
android {
// ÆäËûÅäÖÃ
productFlavors {
// Ô°ü
prod {
}
// ÓÃÓÚѹÁ¦²âÊÔ
monkey {
}
}
}
dependencies {
// ÆäËûÅäÖÃ
// ÓÃÓÚÔÚ×Ô¶¯»¯²âÊÔÖÐÒýÈëleakcanary¼à¿ØÄÚ´æÐ¹Â¶.
monkeyCompile project(':leakfortest')
} |
È»ºóÎÒÃÇÎÒµÄÓ¦ÓôúÂëÖÐÌí¼ÓÈçϺ¯Êý£¬´úÂëÈçÏÂ:
public static void setupLeakCanary(Application application) {
if ( BuildConfig.FLAVOR.equals("monkey") ) {
try {
Class canaryClz = Class.forName(" com.simple.leakfortest.LeakCanaryForTest") ;
Method method = canaryClz. getDeclaredMethod("install", Application.class) ;
method.setAccessible( true);
method.invoke(null, application) ;
} catch (Exception e) {
Log.e("", "### leak canary error : " + e.getMessage()) ;
e.printStackTrace();
}
}
} |
È»ºóÎÒÃÇÔÚ Application ÀàÖе÷Óà setupLeakCanary º¯Êý£¬Ôڸú¯ÊýÖлáÅж¨Èç¹ûÕâ¸öÓ¦ÓÃÊÇmonkey flavor, ÄÇô¾Í»á¼¯³É leakfortest Ä£¿é£¬²¢ÇÒÔÚͨ¹ý·´Éäµ÷ÓÃÁËLeakCanaryForTestÀàµÄinstallº¯ÊýÀ´¼¯³ÉÎÒÃǶ¨ÖƹýµÄ LeakCanary, ´Ó¶ø´ïµ½½«ÄÚ´æÐ¹Â©µÄÈÕÖ¾Êä³öµ½Ìض¨ÎļþµÄЧ¹û. ΪÁËʵÏÖÕâ¸öЧ¹û£¬ÎÒÃÇÖ»ÐèÒª½«gradleÈÎÎñÖÐÉú³ÉapkµÄÃüÁî¸ÄΪ assembleMonkeyDebug, È»ºó½«Éú³ÉµÄapk°²×°µ½É豸ÖУ¬×îºóÖ´ÐвâÊÔ¼´¿É½øÐкóÐøµÄÁ÷³Ì¡£ÕâÑùÒ»À´£¬ÎÒÃǾͽ«¿ª·¢Óë×Ô¶¯»¯²âÊÔ¸ôÀ뿪À´ÁË!
ÆäËû²âÊÔ
ͨ¹ýÉÏÊöµÄ·½°¸£¬ÎÒÃǾÍÓÐÁËÒ»Ì×¼òµ¥¡¢Í¶ÈëµÍ¡¢ÊÕÒæ¸ßµÄ×Ô¶¯»¯²âÊÔ·½°¸£¬ËüÃÇÄܹ»¿ìËٵķ¢ÏÖ»ù´¡Ä£¿éµÄÎÊÌâ¡¢ÄÚ´æÐ¹Â©ÎÊÌ⣬Äܹ»±£Ö¤Ó¦ÓõÄÎȶ¨ÐÔ¡£µ«ÊÇÕâÖ»Äܱ£Ö¤Ó¦ÓÃÂß¼ÔÚµ¥¸öÉ豸µÄÎȶ¨ÐÔ£¬²»Í¬µÄÉ豸¿ÉÄÜ»á²úÉúһЩ¼æÈÝÐÔµÄÎÊÌâ¡£Òò´Ë£¬ÁíÒ»¸öÖØÒªµÄ²âÊÔ¾ÍÊǼæÈÝÐÔ²âÊÔ£¬È·±£ÎÒÃǵÄÓ¦ÓÃÔÚ¸÷ÖÖÉ豸ÉÏÄܹ»ÕýÈ·µÄÔËÐС£Èç¹ûÌõ¼þÐí¿É£¬ÎÒÃÇ¿ÉÒÔ½èÖúÊг¡ÉÏÔÆ²âÊÔÆ½Ì¨ÔËÐÐһЩmonkey²âÊÔÀ´ÑéÖ¤Ó¦ÓõļæÈÝÐÔ£¬´Ó¶ø±ÜÃâ¼æÈÝÐÔÒý·¢µÄÎÊÌâ¡£
Èç¹û˵ͨ¹ýjenkins¡¢monkey¡¢µ¥Ôª²âÊÔÄܹ»ÔÚÒ»¸öµãµÄ½Ç¶È±£Ö¤Ó¦ÓõÄÎȶ¨ÐÔ£¬ÄÇô¼æÈÝÐÔ²âÊÔ¾ÍÊÇ´ÓÒ»¸öÃæµÄ½Ç¶È±£Ö¤ÁËÓ¦ÓõļæÈÝÐÔ¡£Í¨¹ýÕâÁ½¸öά¶ÈµÄ²âÊÔ£¬ÎÒÃǵÄÓ¦Óÿ϶¨»áÔ½À´Ô½Îȶ¨£¬ÎÒÃÇÒ²ÄÜ´ÓÖÐÁìÎò¸ü¶àÈí¼þÉè¼Æ¡¢²âÊԵķ½·¨Óë˼Ïë¡£
È»¶ø£¬ÕâÒ»ÇÐÖ»ÊÇ¿ªÊ¼£¬Èç¹ûÍŶÓÓо«Á¦ºÍʱ¼ä£¬ÎÒÃÇ»¹¿ÉÒÔÔÚJenkinsÖÐÌí¼Ó¸ü¶àµÄ·½°¸½øÐвâÊÔ¡£ÀýÈç:
- ͨ¹ý TinyDancer ¡¢BlockCanaryµÈÐÔÄܼì²â¿ò¼ÜÀ´²éÕÒÐÔÄÜÎÊÌ⣻
- ÔÚ²âÊÔ¹ý³ÌÖж¨ÆÚµÄÊä³öÄÚ´æ¡¢CPUÕ¼Ó㬲âÊÔ½áÊøµÃµ½Ò»¸ö±¨±í£¬×îÖÕ¿ÉÒÔÓëÆäËû±¨¸æÒ»¿éÀ´·ÖÎöÎÊÌ⣻
- ͨ¹ý Espresso¡¢RobotiumʵÏÖUI×Ô¶¯»¯²âÊÔ¡£
ͨ¹ý²»¶ÏµÄÍêÉÆ×Ô¶¯»¯Æ½Ì¨£¬ÒÔ»úÆ÷Ìæ´ú²¿·ÖµÄÈ˹¤²âÊÔ£¬ÎÒÃǵÄÓ¦ÓÃÖÊÁ¿½«»áµÃµ½ºÜ´ó³Ì¶ÈµÄ±£ÕÏ¡£¼´Ê¹Ö»Óе¥Ôª²âÊÔ¡¢Ñ¹Á¦²âÊÔ¡¢LeakCanaryÄÚ´æ¼ì²â¡¢ÔÆÆ½Ì¨µÄ¼æÈÝÐÔ²âÊÔ£¬ÎÒÃǵÄÓ¦ÓÃÒ²Äܹ»¾ÊÜס´´Òµ¹«Ë¾¿ìËÙµü´ú´øÀ´µÄÖÊÁ¿¿¼Ñé¡£µ«²¢²»ÊÇÓиü¶àµÄ²âÊԾͻá¸üºÃ£¬ÓеÄʱºòÒ²»áÊÊµÃÆä·´£¬Òò´ËÔËÓÃÄÄЩ²âÊÔ·½°¸¡¢×öµ½Ê²Ã´³Ì¶È¶¼ÐèÒª¸ù¾Ý¸÷×ÔµÄÇé¿ö½øÐоö²ß¡£ÎÒÃǵÄÄ¿±êÊÇÌá¸ßÓ¦ÓõÄÖÊÁ¿£¬¶ø²»ÊÇÔö¼Ó²âÊÔµÄÊýÁ¿¡£
ºÃ°É£¬ÒÔÉϾÍÊÇÎÒÕâÕó×ÓµÄʵ¼ùÓë×ܽᣬҲϣÍû¸ü¶àµÄÈ˽«×Ô¼ºµÄʵ¼ù¡¢Ëù˼ËùµÃ·ÖÏí³öÀ´£¬ÈÃÎÒÃÇÔÚ¿ª·¢¹ý³ÌÖÐÉÙ×ßÍä·!
´úÂ벿·ÖʾÀýÇëÒÆ²½ github https:// github.com/hehonghui/ app-test-arch |