《APP研发录》笔记

最近两天在项目不忙的时候读了《APP研发录》,虽然是看的PDF版,但还是受益匪浅,由于时间关系,还没有对其中的问题进行demo验证,

仅对一些重要内容做了笔记,现将笔记贴出来与大家共同学习,如果有问题,大家可以留言或私信。在今后的额阅读中,再对笔记的内容进行补充说明。

面试考察的几方面:

1.Activity的生命周期

2.Activity的4种启动方式及使用场合

3.做过的项目,Activity是否有基类,如果有,封装了哪些公用的逻辑

4.事件的各种使用方式及优缺点

5.与HTML5页面的相互调用

6、UI线程的阻塞与解决方案(Runnable和Handler)

7. 采用什么姿势调用MobileAPI并解析返回的数据

8。怎样做列表的分页和刷新

9.登录的实现,包括从哪来,到哪去的页面跳转机制,记住密码的逻辑设计。

10.性能调优,包括Layout调优,Activity中如何使用Const常量,时间换空间策略,

ViewHolder、图集的优化策略、数据缓存的图片缓存,等等。

11.全局变量过多怎么办

12.写过UT没

13.是否做过自动打包,Ant、Maven或Gradle任意一种都可以。

14.如何检查内存泄露、如何优化内存、多线程、自动打包、框架设计、版本管理等。

Android应用开发所需要的技能点:

1.Activity相关,涉及LaunchMode、onSaveInstanceState、生命周期等。

2.Fragment相关,《Creating Dynamic UI with Android Fragments》

3.序列化技术。Parcelable和Serializable。前者基于Service,后者基于Bundle

4.ImageLoader的原理和使用。

5.fastJson或Gson的使用。

6.多线程相关。包括Handler、Looper、ExecutorService

7.Adapter和ListView。

8.用户Cookie设计。登录机制。

9.网络请求封装。

10.Android与H5交互。

11.代码混淆。

12.Android打包机制。

13.线上Crash分析并修复。

14.内存泄露,内存优化,内存泄露场景,MAT工具。

15.调试工具。DDMS等

16。Monkey机制

17.单元测试,Junit。

18.Git的高级功能。包括Stage、R额八色、Revert、Stash、Cherry Pick和Sub Module等。svn。

19.插件化变成。DexClassLoader。

20.设计模式。工厂、生成器、适配器、代理、策略模式等。

第四章 编码规范

1.activity中定义新生命周期在onCreate中创建三个方法

initVariables initViews loadData

2.activity中不要嵌套内部类

3.实体不要在不同模块中共享,可以在同一模块的不同页面中共享

4.为节省内存,尽量使用ArrayList<自定义实体>,而不是HashMap

5.图片的处理统一使用第三方组件加载

6.简单的配置信息,设置页面的各种开关,存储到SharedPreferences中。复杂的对象,比如User类,

城市基础数据,需要存在本地文件中。

7.尽量使用ApplicationContext替代Context,否则会引起内存泄露,但也不是任何地方都可以替代。

8.数据类型转换一定要进行校验。

第五章 Crash异常收集与统计 第六章 Crash异常分析

CrashHandler类 继承自UncaughtExceptionHandler,

/**

* UncaughtException处理类,当程序发生Uncaught异常的时候,由该类来接管程序,并记录发送错误报告。

* 需要在Application中注册,为了要再程序启动器就监控整个程序。

*/

public class CrashHandler implements UncaughtExceptionHandler{

public static final String TAG = "CrashHandler";

public static final String APP_CACHE_PATH =

Environment.getExternalStorageDirectory()/getPath()+"/YoungHeart/crash";

/**

* 当UncaughtException发生时会转入函数来处理

*/

@Override

public void uncaughtException(Thread thread,Throwable ex){

if(!handleException(ex) && mDefaultHandler !=null){

//如果用户没有处理则让系统默认的异常处理器来处理

mDefaultHandler. uncaughtException(thread,ex);

}else{

try{

Thread.sleep(3000);

}catch(){

}

//退出程序

android.os.Process.killProcess(android.os.Process.myPid);

System.exit(1);

}

}

handlerException 方法主要做三件事情,1发错误日志到服务器2给用户友好提示3记录到sd卡

1.对Crash进行归纳,每类Crash发生的次数、涉及的机型、涉及的Android系统版本

2.对Crash产生的原因分析

a。Android碎片化

b. MobileAPI返回了脏数据。

c。混淆时没有Keep要使用的类或方法,找不到类或方法了。

3.每天跑Monkey的包存到测试机上即可。有专人去排查Monkey包的问题。

4.Java语法相关的异常

1)空指针

a。方法需要对传入的参数判空后再使用。

b。调用外部接口,确保返回值中不为空,需要确保执行该接口不会抛出其他异常导致程序退出。

c。APP中过多使用全局变量。

2)角标越界OutOfBoundsException

a。程序不严谨

b。在遍历一个数组/集合时,需要预判数组/集合是否为空,长度是否大于0.

c。在使用数组/集合中的元素时,要预判数组/集合长度是否有这么长。

d。subString(start,end)要判断字符串的长度

e。listview的长度判断

3)试图调用空对象方法

Attempt to invoke virtual method on a null object reference

对象没有实例化,或者将实例化的语句写在了if-else语句中

在activityA中调用activityB中的方法,在B中建立了一个static变量,当这个static变量被回收。就会出现这个问题。

推送,跳过首页直接进入二级或三级,需要使用首页某个对象时,对象为空

4)类型转换异常

设置转换失败的默认值,防止得到空值。

5)数字转换错误 NumberFormatException

字符型转换为数字失败时,

String abc = “123xxx45”; int result = Integer.parseInt(abc);

如果转换失败,要设置默认值。

6)声明数组时长度为-1 NegativeArraySizeException

String[] arg1 = new String[args.length - 1];

当args数组中没有元素时,就会出现问题。

7)遍历集合同事删除其中元素 ConcurrentModificationException

多个线程同时删除同一个集合中的元素。

8)比较器使用不当 Comparison method violates its general contrat!

9)除数为0 ArithmeticException:divide by zero

多发生在第三方控件,如GifView

10)随便用asList

11)有类找不到

ClassNotFoundException 和 NoClassDefFoundError

5.Activity相关异常

1)找不到activity

2)不能实例化Activity RuntimeException

没有在AndroidManifest清单中注册该activity

创建activity后修改了包名或类名但配置清单没有修改

系统处于异常状态

3)找不到Service RuntimeException

4)不能启动BroadcastReceiver

使用Activity以外的content来startActivity。比如BroadcastReceiver,必须用

Intent.FLAG_ACTIVITY_NEW_TASK

5)startActivityForResult不能回传

6)Fragment Fragment not attached to Activity

Fragment在还没有Attach到Activity时,调用了诸如getResource() 的方法

解决方案需要在获取资源前用isAdded方法进行判断

isAdded方法是Android系统提供的,只有在Fragment被添加到所属的Activity中才会返回true。

7.序列化相关异常

实体对象不支持序列化

序列化时未指定ClassLoader

反序列化时找不到类,被ProGuard混淆导致的崩溃

反序列化时找不到类,传入畸形数据

反序列化时出错,Could not read……

8.列表相关异常

adapter数据源变化没有通知listview

listview滚动时点击刷新按钮崩溃(滚动时将刷新设为不可用)

absListview 的obtainView返回空指针

adapter数据源变化但没有调用notifyDataSetChanged

9.窗体相关异常

窗口句柄泄露

View not attached to window manager

窗体在不恰当的时候获取焦点

token null is not for an application

添加窗体失败

AlertDialog.resolveDialogTheme

The specified child already has a parent

子线程不能修改UI

不能在子线程操作AlterDialog和Toast

10.资源相关异常

Resources$NotFoundException

StackOverflowError 视图嵌套太深,activity退出不完全,用system.exit(0)

UnsatisfiedLinkError so文件

11.系统碎片化相关异常

NoSuchMethodError 2.3版本的Bundle中getString()

RemoteViews (AppWidget和Notification)

SecurityException之一Intent中图片太大,超过1M不用Intent传递

SecurityException之二动态加载其他apk的activity

SecurityException之三 缺少权限 不同版本需要预判权限

view的getDrawingCache()返回null,背景图太大,超过屏幕大小

DeadObjectException 产生这样的错误以便重启设备

Android 2.1不支持SSL

ViewFlipper控件切换横竖屏时出现问题,解决方案重写onDetachedFromWindow(

12.SQLite相关异常

No transaction is active 逐条插入大量数据时发生的,解决办法一次性插入,通过事物成功进行提交 setTransactionSuccessful()

忘记关闭Cursor

数据库被锁定,当不同线程中创建多个数据库链接时发生

想要打开已经关闭的对象

文件加密了或无数据库

磁盘读写错误

13.不明觉厉的异常

内存溢出

TimeoutException GC回收异常,重写finalize方法不要超时操作

Json解析异常

LayoutInfiater.form().infiate()使用不当

Monkey点击过快导致的崩溃 取决于Monkey点击的间隔时间

图片缩放很多倍

第七章 ProGuard

ProGuard一共包括4个功能

压缩:侦测并移除代码中无用的类、字段、方法和特性

优化:对字节码进行优化,移除无用的指令

混淆:使用a、b、c、d这样简短而无意义的名称,对类、字段和方法进行重命名

预检:在Java平台上对处理后的代码进行预检

基本混淆

1.基本指令

# 代码混淆压缩比,在0-7之间,默认为5,一般不需要改

-optimizationpasses 5

# 混淆时不使用大小写混合,混淆后的类名为小写

-dontusemixedcaseclassnames

# 指定不去忽略非公共的库的类

-dontskipnonpubliclibraryclassmembers

# 不做预校验,preverify是proguard的4个步骤之一

# Android不需要preverify,去掉这一步可加快混淆速度

-dontpreverify

# 有了verbose这句话,混淆后就会生成映射文件

# 包含有类名->混淆后类名的映射关系

# 然后使用printmapping指定映射文件的名称

-verbose

-printmapping proguardMapping.txt

# 指定混淆时采用的算法,后面的参数是一个过滤器

# 这个过滤器是谷歌推荐的算法,一般不改变

-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

# 保护代码中的Annotation不被混淆

# 这在JSON实体映射时非常重要,比如fastJson

-keepattributes *Annotation*

# 避免混淆泛型

# 这在JSON实体映射中非常重要,比如fastJSON

-keepattributes Signature

//抛出异常时保留代码行号

-keepattributes SourceFile,LineNumberTable

-dontskipnonpubliclibraryclasses用于告诉ProGuard,不要跳过对非公开类的处理。默认情况下是跳过的,

因为程序中不会引用它们,有些情况下人们编写的代码与类库中的类在同一个包下,并且对包中内容加以引用,此时需要加入此条声明。

对于-dontusemixedcaseclassnames,Windows用户必须指定,因为Windows对文件名大小写不敏感,可能对导致class文件相互覆盖

2.需要保留的东西

# 保留所有的本地native方法不被混淆

-keepclasseswithmembernames class * {

    native ;

}

# 保留继承自Activity、Application这些类的子类

# 因为这些子类都有可能被外部调用

-keep public class * extends android.app.Activity

-keep public class * extends android.app.Application

-keep public class * extends android.app.Service

-keep public class * extends android.content.BroadcastReceiver

-keep public class * extends android.content.ContentProvider

-keep public class * extends android.app.backup.BackupAgentHelper

-keep public class * extends android.preference.Preference

-keep public class * extends android.view.View

-keep public class com.android.vending.licensing.ILicensingService

# 如果有引用android-support-v4.jar包,可以添加下面这行

-keep public class com.tuniu.app.ui.fragment.** {*;}

# 保留在Activity中的方法参数是view的方法

# 从而我们在layout里面编写onClick就不会被影响

-keepclassmembers class * extends android.app.Activity {

    public void *(android.view.View);

}

# 枚举类不能被混淆

-keepclassmembers enum * {

    public static **[] values();

    public static ** valueOf(java.lang.String);

}

# 保留自定义控件(继承自View)不会混淆

-keep public class * extends android.view.View{

    *** get*()

    void set*(***)

    public (android.content.Context);

    public (android.content.Context,android.util.AttributeSet);

    public (android.content.Context,android.util.AttributeSet,int);

}

# 保留Parcelable序列化的类不被混淆

-keep class * implements android.os.Parcelable {

    public static final android.os.Parcelable$Creator *;

}

# 保留Serializable序列化的类不被混淆

-keepclassmembers class * implements java.io.Serializable {

    static final long serialVersionUID;

    private static final java.io.ObjectStreamField[] serialPersistentFields;

    private void writeObject(java.io.ObjectOutputStream);

    private void readObject(java.io.ObjectInputStream);

    java.lang.Object writeReplace();

    java.lang.Object readResolve();

}

# 对于R(资源)下的所有类及其方法,都不能被混淆

-keep class **.R$* {

    *;

}

# 对于带有回调函数onXXEvent的,不能被混淆

-keepclassmembers class * {

    void *(**On*Event);

}

针对App的量身定制

1.保留实体类和成员不被混淆

对于实体,要保留它们的set和get方法,以及boolean型的get方法

-keep public class com.yourpackage.entity.** {

    public void set*(***);

    public *** get*();

    public *** is*();

}

2.内嵌类

内嵌类经常会被混淆,结果在调用的时候为空就崩溃了,在混淆时必须要进行保留,如保留MainActivity的所有内嵌类:

-keep class com.yourpackage.MainActivity$* {*;}

3.对WebView的处理

项目中用到了WebView的复杂操作,需添加:

-keepclassmembers class * extends android.webkit.webViewClient {

    public void *(android.webkit.WebView,java.lang.String,android.graphics.Bitmap);

    public boolean *(android.webkit.WebView,java.lang.String)

}

-keepclassmembers class * extends android.webkit.webViewClient {

    public void *(android.webkit.webView,java.lang.String)

}

4.对JavaScript的处理

如要保证js调用的原生方法不被混淆(JSInterface1是MainActivity的子类)

-keepclassmembers class com.yourpackage.MainActivity$JSInterface1 {

    ;

}

5.处理反射

对于Class.forName(“SomeClass”)这样的方法,在混淆过程中,就要保留这个类的名称不被混淆

针对第三方jar包的解决方案

1.针对android-support-v4.jar

-libraryjars libs/android-support-v4.jar

-dontwarn android.support.v4.**

-keep class android.support.v4.** {*;}

-keep interface android.support.v4.app.** {*;}

-keep public class * extends android.support.v4.**

-keep public class * extends android.app.Fragment

2.其他的第三方jar包的解决方案

将第三方jar包中有关于混淆的说明添加上去

第八章

使用Ant脚本打包:Ant IIS Antcontrib AndroidSDK JavaSDK SVN CCNET

是否支持自动打包 Daily Build

第九章 竞品分析

1.嗅探器 WireShark ,也有fiddler

2、发版前要进行兼容性测试,确保稳定性。app升级后,除了用户信息保留外,所有遗留数据删除。

3.h5用zip包存放本地,增量更新

4.使用WebView预加载H5,但耗流量。

5.本地使用png,网上下载使用jpg

你可能感兴趣的:(《APP研发录》笔记)