HRMP项目总结

1.在AndroidManifest文件中设置service的exported属性的作用


android:exported
这个属性用于指示该服务是否能够被其他应用程序组件调用或跟它交互。如果设置为true,则能够被调用或交互,否则不能。设置为false时,只有同一个应用程序的组件或带有相同用户ID的应用程序才能启动或绑定该服务。
它的默认值依赖与该服务所包含的过滤器。没有过滤器则意味着该服务只能通过指定明确的类名来调用,这样就是说该服务只能在应用程序的内部使用(因为其他外部使用者不会知道该服务的类名),因此这种情况下,这个属性的默认值是false。另一方面,如果至少包含了一个过滤器,则意味着该服务可以给外部的其他应用提供服务,因此默认值是true。这个属性不是限制把服务暴露给其他应用程序的唯一方法。还可以使用权限来限制能够跟该服务交互的外部实体。


2.在AndroidManifest文件中设置aplication的allowBackup属性的作用




android:allowBackup
①allowBackup安全风险描述
Android API Level 8及其以上Android系统提供了为应用程序数据的备份和恢复功能,此功能的开关决定于该应用程序中AndroidManifest.xml文件中的allowBackup属性值[1] ,其属性值默认是True。当allowBackup标志为true时,用户即可通过adb backup和adb restore来进行对应用数据的备份和恢复,这可能会带来一定的安全风险。
Android属性allowBackup安全风险源于adb backup容许任何一个能够打开USB 调试开关的人从Android手机中复制应用数据到外设,一旦应用数据被备份之后,所有应用数据都可被用户读取;adb restore容许用户指定一个恢复的数据来源(即备份的应用数据)来恢复应用程序数据的创建。因此,当一个应用数据被备份之后,用户即可在其他Android手机或模拟器上安装同一个应用,以及通过恢复该备份的应用数据到该设备上,在该设备上打开该应用即可恢复到被备份的应用程序的状态。
尤其是通讯录应用,一旦应用程序支持备份和恢复功能,攻击者即可通过adb backup和adb restore进行恢复新安装的同一个应用来查看聊天记录等信息;对于支付金融类应用,攻击者可通过此来进行恶意支付、盗取存款等;因此为了安全起见,开发者务必将allowBackup标志值设置为false来关闭应用程序的备份和恢复功能,以免造成信息泄露和财产损失。
②allowBackup安全影响范围
Android API Level 8以及以上系统
③allowBackup安全风险详情
1) allowBackup风险位置:
AndroidMannifest.xml文件android:allowBackup属性;
2) allowBackup风险触发前提条件:
未将AndroidMannifest.xml文件中的android:allowBackup属性值设为false;
3) allowBackup风险原理:
当allowBackup标志值为true时,即可通过adb backup和adb restore来备份和恢复应用程序数据;



3.Button.setBackgroundColor(可绘制背景) 引发 NoSuchMethodError

在API小于16的手机上测试,如果代码中出现了Button.setBackgroundColor 调用那么会出现“没有方法”的异常,原因是手机的SDK等级偏低。此时我们可以用setBackgroundDrawable方法去设置button的背景颜色(虽然最新SDK已不推荐此方法)



4.MVP模式内存泄漏情况

第一种情况:在单例模式中的泄漏
例子一:
    public static UserBiz userBiz = null;
    private IThreadListener threadListener;
    private UserBiz() {
    }
    public static UserBiz getInstance(){
        if (userBiz==null){
            userBiz = new UserBiz();
        }
        return userBiz;
    }
    public void doLogin(String username,String psd){
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                    if (threadListener!=null) {
                        threadListener.success();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
    public void setThreadListener(IThreadListener listener){
        this.threadListener = listener;
    }
这里UserBiz是一个单例模式实现类,doLogin方法中模拟登录成功直接调用接口的success方法,setThreadListener是之前在Presenter类中传过来的,这时候我们运行项目,在LeakCabary中查看LoginActivity内存泄漏了。在Presenter构造方法中传进来一个实现了ILoginView的一个Activity实例,而在Presenter构造中又调用setThreadListener的方法,因此单例UserBiz对象的threadListener实例变量引用了Presenter的一个ThreadListener对象,而Presenter又引用了LoginActivity,当LoginActivity销毁时,UserBiz的threadListener对象不会销毁,它依然变相的引用这LoginActivity,所以内存泄漏了。我们可以将代码改成如下:
    public static UserBiz userBiz = null;
    private UserBiz() {
    }
    public static UserBiz getInstance(){
        if (userBiz==null){
            userBiz = new UserBiz();
        }
        return userBiz;
    }
    @Override
    public void doLogin(String username, String psd,final IThreadListener threadListener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                    threadListener.success();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
IThreadListener的对象作为doLogin的参数传进来,而不是把它当做UserBiz的实例对象。这样当LoginActivity销毁时UserBiz的实例对象不会引用外界的实例。

5.Error:Execution failed for task ':app:transformClassesWithDexForDebug'异常

如果在项目中多添加了一个方法或者添加额外加入了lib,启动的时候报错:
Error:Execution failed for task ':app:transformClassesWithDexForDebug'.
> com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException: java.util.concurrent.ExecutionException: com.android.dex.DexException: Multiple dex files define Lokhttp3/Address
如果项目中有自定义的Application,那么重写attachBaseContext方法,
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }


6.Error:Execution failed for task ':app:buildInfoDebugLoader'.异常

项目中出现了如下异常
> Exception while doing past iteration backup : Source D:\WorkSpace\as\hrmp\app\build\intermediates\builds\debug\105665528047786\classes.dex and destination 
D:\WorkSpace\as\hrmp\app\build\intermediates\builds\debug\105665528047786\classes.dex must be different

解决方案:Build--> Rebuild Project 


7.Context使用的注意事项

1.一定要传对值尤其是碰到页面跳转,显示dialog等,里面的Context一定是Activity的,传错会有可能造成白屏等现象。
2.遇到static修饰的变量要注意,是否有oom的危险,这里用到Context最好用application的,因为它的context是全局变量,生命周期很长,并且也可以拿到系统资源和各种属性。

8.ViewGroup的descendantFocusability属性

该属性是当一个为view获取焦点时,定义viewGroup和其子控件两者之间的关系。
属性的值有三种:
        beforeDescendants:viewgroup会优先其子类控件而获取到焦点
        afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点
        blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点
当listview的item点击没有反应的时候可以考虑更改此值。

9.hardwareAccelerated属性

硬件加速

Android 3.0 (API level 11), 开始支持
所有的View 的canvas都会使用GPU,但是硬件的加速会占有一定的RAM。
在API >= 14上,默认是开启的,如果你的应用只是标准的View和Drawable,全局都打开硬件加速,是不会有任何问题的。
然而,硬件加速并不支持所有的2D画图的操作,这时开着它,可能会影响到你的自定义控件或者绘画,出现异常等行为,
所以android对于硬件加速提供了可选性
如果你的应用执行了自定义的绘画,可以通过在真机上测试开启硬件加速查找问题

look:http://blog.chenming.info/blog/2012/09/18/android-hardware-accel/

10.measure方法报IllegalArgumentException异常



调用该方法询问view最终多大。实际是由父容器提供建议宽和高的数值。
实际计算view的大小是在onMeasure(int,int)方法中,所以onMeasure方法必须在子类中重写才能改变view的大小,并且最终设置数值的时候调用setMeasuredDimension方法。在比较旧的SDK中,直接写measure方法会报IllegalArgumentException异常。

11.出现this requires android.permission.INTERACT_ACROSS_USERS_FULL语句的权限异常

做项目的时候发现了一个问题,在三星S3手机中登录之后出现了黑屏,欢迎界面和登录界面还有手势解锁界面没有问题,唯独进入主界面MainActivity出现了黑屏现象,这样排除了activity栈的问题,再测试,在S3模拟器中和其他品牌手机没有出现问题,因此断定这个是针对手机机型出现的bug。项目中报的异常如下:
Writing exception to parcel java.lang.SecurityException: Permission Denial: get/set setting for user asks to run as user -2 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL
                                                    at com.android.server.am.ActivityManagerService.handleIncomingUser(ActivityManagerService.java:13322)
                                                    at android.app.ActivityManager.handleIncomingUser(ActivityManager.java:2044)
                                                    at com.android.providers.settings.SettingsProvider.callFromPackage(SettingsProvider.java:615)
                                                    at android.content.ContentProvider$Transport.call(ContentProvider.java:279)
                                                    at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:273)
                                                    at android.os.Binder.execTransact(Binder.java:388)
                                                    at dalvik.system.NativeStart.run(Native Method)
网上搜了搜,再看异常中出现了SettingProvider等有关系统文件的字样,大概可以知道这个是S3手机不支持读取或者设置某些系统设置。最终在代码中查找是否有设置系统配置相关的属性
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //在setContentView之前添加,未添加的话home键监听无效,设置窗体属性
        this.getWindow().setFlags(0x80000000, 0x80000000);
        try {
            setContentView(R.layout.activity_2_main);
            ButterKnife.bind(this);   ... ... ... 
果然在上面语句中有 this.getWindow().setFlags(0x80000000.0x80000000),将它注释掉,于是就能在S3中运行了。


12. hrmp容易犯的错误

1.上线之前思考、查看代码中是否有写死的数据,由于正式环境测试不方便在测试环境中写死了数据。
2.利用RxAndroid的时候容易忘记蓝色字体的内容。
            MainApp.getApiService().uploadLocation(param)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Observer<BaseResp>() {
                        @Override
                        public void onSubscribe(@NonNull Disposable d) {


                        }


                        @Override
                        public void onNext(@NonNull BaseResp baseResp) {


                        }


                        @Override
                        public void onError(@NonNull Throwable e) {


                        }


                        @Override
                        public void onComplete() {


                        }
                    })
;


13.AndroidStudio 安装启动项目时 报错 Failure[DELETE_FAILED_INTERNAL_ERROR] 

最近做项目的时候用小米手机作为测试机,启动项目的时候报如下的错误:



启动其他项目都没有出现此问题,于是乎从build.gradle中用排除法一点点检查,最终定位到了一段代码
  defaultConfig {
    ...
    jackOptions {
      enabled true
    }
  }
这是为了AndroidStudio从2.1开始官方通过Jack支持Java8,从而使用Lambda等特性,加入的配置。
如果我们不加就会报错:
Error:Jack is required to support java 8 language features. Either enable Jack or remove sourceCompatibility JavaVersion.VERSION_1_8.
加了在小米手机中报如上异常,其他测试机正常。网上看到如果项目中用到了ButterKnife,Dagger等基于APT的注解框架,那么打开jackOptions就会无法使用这些注解框架。会提示如下错误:
Error:Could not find property ‘options’ on task ‘:app:compileDebugJavaWithJack’. 
最后只能用第三方的Java8兼容插件,retrolambda进行尝试:
第一步:在Project下面的主module的build.gradle中添加 apply plugin: 'me.tatarka.retrolambda'


第二步:在Project下的build.gradle中添加classpath 'me.tatarka:gradle-retrolambda:latest.release'



14.RecycleView设置item点击带有显示效果

在item的根布局中加入
             android:background="@drawable/selector_list_bg"
             android:clickable="true"
             android:focusable="true"
selector_list_bg.xml 
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/shape_list_bg_normal" 
          android:state_pressed="false"></item>
    <item android:drawable="@drawable/shape_list_bg_press" 
          android:state_pressed="true"></item>
    <item android:drawable="@drawable/shape_list_bg_normal" 
          android:state_focused="false"></item>
    <item android:drawable="@drawable/shape_list_bg_press" 
          android:state_focused="true"></item>
    <item android:drawable="@drawable/shape_list_bg_normal"></item>
</selector>


15.主项目libs引入的jar包和依赖第三方工程中build.gradle依赖的库冲突

起因是由于主项目中导入了ksoap2-android-assembly-3.6.2-jar-with-dependencies.jar,并且又依赖了友盟推送的工程包,如图



查看友盟工程(PushSDK)的build.gradle中添加了两个依赖



这里跟主项目导入的ksoap jar包中都用到了okio 类库,当打包的时候会报如下异常:
* What went wrong:
Execution failed for task ':app:transformClassesWithJarMergingFor_360Debug'.
> com.android.build.api.transform.TransformException: java.util.zip.ZipException: duplicate entry: okio/AsyncTimeout$1.class
表明项目中用到了多个okio类库文件。
将PushSDK中这两句依赖代码注释掉,项目可以编译,但是当安装后进入应用,会出现crash,抛出异常:
10-12 10:37:31.703 28011-28136/com.hrmp E/AndroidRuntime: FATAL EXCEPTION: Thread-42934
                                                          Process: com.hrmp, PID: 28011
                                                          java.lang.NoClassDefFoundError: com.umeng.message.protobuffer.PushRequest$Builder
                                                              at com.umeng.message.proguard.I.a(NetworkHelper.java:262)
                                                              at com.umeng.message.UTrack.addAlias(UTrack.java:678)
                                                              at com.umeng.message.UTrack$11.run(UTrack.java:608)
                                                              at java.lang.Thread.run(Thread.java:818)
此时思路就是,如何让项目中只用到一个okio类库,而又不能将wire-runtime类库删除。利用主项目是依赖第三方工程的,那么可以将本身libs下的jar包放到第三方工程libs下,这样就可以注释掉build.gradle中依赖的代码,还不影响主项目中引入ksoap jar包。修改如图:



jar包放到PushSDK libs下,再将compile 'com.squareup.okio:okio:1.6.0' 注释掉,运行项目,此时还会报duplicate entry: okio/AsyncTimeout$1.class异常,那么就是com.squareup.wire:wire-runtime:2.1.2类库的问题了。这时候我从友盟推送官网上看到PushSDK中还可以用本地依赖的形式替换掉从jcenter上下载的形式,即将下载下来的jar包放到libs下,将build.gradle中的compile 语句注释掉。
添加之后即:


build.gradle内容如下:



最后测试一下打包和运行都没有报异常了。

16.隐藏软键盘有时候会报空指针异常

最近做项目用到了退出界面前如果打开了软键盘就去隐藏它的功能,代码如下:
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
boolean isOpen=imm.isActive();
if (isOpen) {
	imm.hideSoftInputFromWindow(
		XXXActivity.this.getCurrentFocus().getWindowToken(),
		InputMethodManager.HIDE_NOT_ALWAYS);
}
进入到XXXActivity中,首先判断是否有网络,如果有网络那么显示有EditText等输入信息的layout,如果没有网络则显示include中的内容,而隐藏之前那个layout。当没有网络,显示include中的layout时,走上面的代码会报异常:
java.lang.NullPointerException: Attempt to invoke virtual 
method 'android.os.IBinder android.view.View.getWindowToken()' 
on a null object reference
getCurrentFocus()是获取当前activity中获得焦点的view 。判断就是这里getCurrentFocus为空。
更正代码如下:
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
boolean isOpen=imm.isActive();
if (isOpen) {
	imm.hideSoftInputFromWindow(
	view.getWindowToken(),
	InputMethodManager.HIDE_NOT_ALWAYS);
}
这里的view'就是Activity布局中的一个view。


17.解决项目中利用getResource.getColor过时的警告

我们在用项目的 setBackgroundColor方法时,会报警告:


这时我们可以用更兼容的方法,


利用Contextcompat.getColor(context,color); 方法替代

18.Android Studio 编译时提示 Error: Please select android sdk.


此时我们进入到Project Structure中,将Compile Sdk Version 选项按 config.gradle中的设置更改一下就好。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值