Android 开发问题总结 四

26 篇文章 0 订阅
3 篇文章 0 订阅

Android 开发问题总结 四

1、Android 悬挂式通知栏的实现

Android 悬挂式通知是Android 在5.0以后才有的。在5.0以前通过设置setTicker 来实现

。在5.0 以上、8.0以上通过设置setFullScreenIntent。在8.0以上需要设置
NotificationChannel 的优先级为NotificationManager.IMPORTANCE_HIGH
即可。但是在使用过程中可能会出现很多特殊情况。
比如:悬挂通知栏无法弹窗、会直接进入目标Activity、或者其他情况。
下边是适配过的悬挂式通知栏实例代码:

 //获取PendingIntent
        android.app.NotificationManager notificationManager = (android.app.NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        Intent intent = new Intent();
        PendingIntent mainPendingIntent = PendingIntent.getBroadcast(context, Integer.valueOf(alramId), intent, FLAG_UPDATE_CURRENT);
        RemoteViews views = new RemoteViews(Application.getInstance().getPackageName(),R.layout.notify_drop);
      
        NotificationCompat.Builder builder = new NotificationCompat.Builder(TimeApplication.getInstance());
        builder.setLargeIcon(BitmapFactory.decodeResource(TimeApplication.getInstance().getResources(),R.mipmap.ic_launcher))
                .setSmallIcon(R.mipmap.ic_launcher)//不能缺少的一个属性
                .setContentIntent(mainPendingIntent)
                .setCustomContentView(views)
                .setAutoCancel(true)
                .setLights(0, 0, 0)
                .setWhen(System.currentTimeMillis());//设置通知时间
                builder.setDefaults(Notification.DEFAULT_ALL);

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel channel;
            if(eventDataEntity.soundposition == 0){
                channel = new NotificationChannel(String.valueOf(CHANNEL_ID), "提醒通知", NotificationManager.IMPORTANCE_HIGH);
                channel.setShowBadge(true); //是否在久按桌面图标时显示此渠道的通知
                channel.getAudioAttributes();
                notificationManager.createNotificationChannel(channel);
                builder.setChannelId(String.valueOf(CHANNEL_ID));
                builder.setCustomContentView(views);
            }else{
                channel = new NotificationChannel(String.valueOf(CHANNEL_CUSTOM_ID), "自定义铃声提醒通知", NotificationManager.IMPORTANCE_HIGH );
                channel.setShowBadge(true); //是否在久按桌面图标时显示此渠道的通知
                channel.getAudioAttributes();
                channel.setSound(null,null);
                notificationManager.createNotificationChannel(channel);
                builder.setChannelId(String.valueOf(CHANNEL_CUSTOM_ID));
                builder.setCustomContentView(views);
            }
        } else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
            if(isNeedSetFullScreen()){
                CustomLog.e("提醒事件 === 2");
                builder.setFullScreenIntent(mainPendingIntent,true);
            }
//            builder.setVisibility(Notification.VISIBILITY_PUBLIC);

//            builder.setTicker("悬浮通知");
//                builder.setDefaults(Notification.DEFAULT_ALL);
//                builder.setPriority(Notification.PRIORITY_MAX);
        }

        notificationManager.notify(Integer.parseInt(alramId), builder.build());








/**
     * 是否需要设置setFullScreenIntent
     * @return
     */
    public static boolean isNeedSetFullScreen(){
        CustomLog.e("当前手机品牌 =" + Build.MANUFACTURER);
        boolean isNeed;
        switch (Build.MANUFACTURER) {
            case MANUFACTURER_HUAWEI://华为
            case MANUFACTURER_Huawei:
                isNeed = false;
                break;
            case MANUFACTURER_MEIZU://魅族
                isNeed = false;
                break;
            case MANUFACTURER_XIAOMI://小米
                isNeed = false;
                break;
            case MANUFACTURER_SONY://索尼
                isNeed = false;
                break;
            case MANUFACTURER_OPPO://oppo
                isNeed = false;
                break;
            case MANUFACTURER_LG://lg
                isNeed = false;
                break;
            case MANUFACTURER_LETV://乐视
                isNeed = false;
                break;
            case MANUFACTURER_VIVO:
                isNeed = true;
                break;
            case MANUFACTURER_SAMSUNG:
                isNeed = false;
                break;

            case MANUFACTURER_ZTE:
                isNeed = false;
                break;
            case MANUFACTURER_YULONG:

                isNeed = false;
                break;

            case MANUFACTURER_LENOVO:
                isNeed = false;
                break;
            default:
                isNeed =true;
                break;
        }

        return isNeed;
    }

2、Android 8.0以上使用手机相册、相机以后图片保存、裁剪是会出现android.support.v4.content.FileProvider的使用权限问题

在使用裁剪的时候必须添加以下代码:

      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
            //添加这一句表示对目标应用临时授权该Uri所代表的文件
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            //通过FileProvider创建一个content类型的Uri
//            uri = FileProvider.getUriForFile(this, "包名.fileProvider", file);
        }

3、Litpal 2.0数据库使用过程中id主键自动从 0开始。但是其他sqlite 数据库默认从1 开始。

修改litpal默认主键id 的初始化值,需要覆写

   @Override
    public void assignBaseObjId(int baseObjId) {
    //修改初始值为 1 ,修改时一定要注意这样使用会不会对你现有的逻辑发生影响。
        super.assignBaseObjId(1);
    }

4、关于TextView 支持html标签的问题

目前支持的html标签很基础,p 、h 、font 等等。
span标签在6.0以上的手机系统已经开始支持,6.0以下不起作用。如果是字体颜色等的调整可以使用font。

5、Glide 图片加载库在使用asBitmap 的时候。偶现同一个ImageView会显示其他页面加载的bitmap图片。

原因:因为Glide 库底层对bitmap 有复用的处理。而且是指向同一块内存地址。所有在加载其他bimap图片的时候。只是改变了内容,地址没有变化。这个时候其他ImageView或者控件在使用的时候,就会变成该地址所对应的最新的bitmap 图片。
修改:
使用时只要重新创建Bitmap 对象。而不是直接使用Glide 返回的bitmap。

6、合并不同仓库的代码。并同步提交:

git init

git remote add trans_old https://××××××××××.git   (旧的git仓库代码地址)

git remote add trans_new https://×××××××××.git  (新的git仓库代码地址)

git fetch trans_old

git fetch trans_new

git checkout -b trans_new/branchName

git merge trans_old/branchName

git push trans_new trans_new/branchName

7、Android SDK版本名和API level对照表

SDK版本名API Level
Android 9.0 (Pie)28
Android 8.1 (Oreo)27
Android 8.0 (Oreo)26
Android 7.1.1 (Nougat)25
Android 7.0 (Nougat)24
Android 6.0 (Marshmallow)23
Android 5.1 (Lollipop)22
Android 5.0 (Lollipop)21
Android 4.4W (KitKat Wear)20
Android 4.4 (KitKat)19
Android 4.3 (Jelly Bean)18
Android 4.2 (Jelly Bean)17
Android 4.1 (Jelly Bean)16
Android 4.0.3 (IceCreamSandwich)15
Android 4.0 (IceCreamSandwich)14
Android 3.2 (Honeycomb)13
Android 3.1 (Honeycomb)12
Android 3.0 (Honeycomb)11
Android 2.3.3 (Gingerbread)10
Android 2.3 (Gingerbread)9
Android 2.2 (Froyo)8
Android 2.1 (Eclair)7
Android 2.0.1 (Eclair)6
Android 2.0 (Eclair)5
Android 1.6 (Dout)4
Android 1.5 (Cupcake)3
Android 1.1 (Base)2
Android 1.0 (Base)1

8、Glide接入后出现 ERROR: Failed to resolve: disklrucache。

解决版本,修改build.gradle文件。
替换为

buildscript {
    repositories {
        jcenter{
            url 'https://jcenter.bintray.com/'
        }
        maven {
            url 'https://maven.google.com'

//            url 'http://maven.aliyun.com/nexus/content/repositories/releases/' //阿里云仓库地址
        }
//        maven {
//            url 'http://maven.aliyun.com/nexus/content/repositories/releases/' //阿里云仓库地址
//        }
//        maven {
//            url 'http://maven.aliyun.com/nexus/content/repositories/releases/' //阿里云仓库地址
//        }
        google()
        maven {
            url "http://10.241.11.54:18080/nexus/repository/maven-open-releases/"
        }
        maven {
            url "http://10.241.11.54:18080/nexus/repository/maven-open-snapshots/"
        }

    }

    dependencies {
        classpath 'com.android.tools.build:gradle:3.5.1'
        
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        flatDir {
            dirs 'libs'
        }

        maven {
            url 'https://maven.google.com'
//            url 'http://maven.aliyun.com/nexus/content/repositories/releases/' //阿里云仓库地址

//        }
            maven {
                url 'https://maven.google.com'
//            url 'http://maven.aliyun.com/nexus/content/repositories/releases/' //阿里云仓库地址
            }
            jcenter {
                url 'https://jcenter.bintray.com/'
            }
            maven { url 'http://developer.huawei.com/repo/' }

            maven { url 'https://jitpack.io' }
         
            google()
            maven {
                url "http://10.241.11.54:18080/nexus/repository/maven-open-releases/"
            }
            maven {
                url "http://10.241.11.54:18080/nexus/repository/maven-open-snapshots/"
            }

        }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

9、恢复删除分支提交的commit

  1. git log -g 查找提交的commit,并记录commit_id
  1. git branch “branch” commit_id
  1. 切换到“branch”分支,检查文件是否存在,即可。

10、通过Drawable来改变对应控件或者布局文件中的颜色:

例如需要 动态改变xml文件中的loading 效果的颜色。
实现方式有很多种,以下只是其中一种实现方式:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/icon_reader_progress_loading"
    android:fromDegrees="0.0"
    android:pivotX="50.0%"
    android:pivotY="50.0%"
    android:interpolator="@android:anim/anticipate_interpolator"
    android:duration="500"
    android:toDegrees="360.0" />

在ProgressBar中使用该xml文件,可以实现loading 加载动效。

<ProgressBar
                android:id="@+id/web_reader_progressBar_loading"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_gravity="center"
                android:indeterminate="true"
                android:layout_centerInParent="true"
                android:indeterminateDuration="1500"
                android:indeterminateDrawable="@drawable/web_progress_drawable_circle_wite" />

因为使用的是图片,而且图片是在xml文件中,那么通过正常方式是无法动态来改变loading的颜色。
但是通过Drawable 确可以实现,Drawable 是Android 中的一个类。
以下是改变颜色的方法:

   Drawable drawable = mProgressLoading.getIndeterminateDrawable();
           String color = “#333333;
           int color_loading = Color.parseColor(color);
           drawable.setColorFilter(color_loading, PorterDuff.Mode.SRC_ATOP);

11、Build was configured to prefer settings repositories over project repositories but repository ‘BintrayJCenter’ was added by build file ‘build.gradle’

Gradle 版本升级到7.0以上以后,需要去项目seeting.gradle 文件中进行设置,build.gradle设置不生效了

12、FTS全文搜索功能搜索速度慢的问题

Fts是用来做在大数据量的时候提供搜索效率、时间的一种实现,目前Android支持FTS3\4\5 三种版本。fts搜索是基于索引文本分词来进行查询的,但是如果索引的文本特别复杂,数据长度过大,特殊符号特别多,那么需要注意了,因为特殊符号是FTS中进行分词的分割符,这个会导致分词量增多,搜索时间指数级上涨。所有创建fts索引需要注意数据的复杂程度。(建议4000字符以下,超过的建议以文本方式使用)。

13、Android部分手机长时间后台或者频繁连接网络的情况,系统有特殊场景会把应用添加到限制联网的状态,需要手动在设置或者应用设置里边进行开启

如果使用过程中出现应用网络异常的情况,但是其他应用可以正常使用,那么就需要排查以下几点

  • 是否添加了网络访问权限
  • 是否是使用http,而且清单文件中没有设置允许明文传输,需要在清单文件进行设置
  • 需要检测是否是服务端ip、域名不可用
  • 需要检查是否应用被系统限制了联网(可用去联网控制进行查看)
  • 可用通过检测手机所有网卡的联网状态(可用通过代码实现)
  • 可用批量通过测试服务器端所有端口进行测试连通性

14、 通过hook IActivityManager 来捕获reportSizeConfigurations 异常带来的崩溃


public class HookIActivityManager {
    public static final String TAG = "HookActivityManager";

    public static HookIActivityManager hookIActivityManager = new HookIActivityManager();
    private void HookIActivityManager(){}

    public static HookIActivityManager getInstance(){
        return hookIActivityManager;
    }

    protected void init() {
        try {
            Field am = ActivityManager.class.getDeclaredField("IActivityManagerSingleton");
            am.setAccessible(true);
            Object iActivityManagerSingleton = am.get(null);

            Class singletonCls = iActivityManagerSingleton.getClass().getSuperclass();
            Field instance = singletonCls.getDeclaredField("mInstance");
            instance.setAccessible(true);
            Object iActivityManager = instance.get(iActivityManagerSingleton);


            Class iActivityManagerCls = Class.forName("android.app.IActivityManager");
            Class[] classes = {iActivityManagerCls};
            Object iActivityManageProxy = Proxy.newProxyInstance(
                    iActivityManagerCls.getClassLoader(),
                    classes,
                    new IActivityManagerProxy(iActivityManager));
            instance.set(iActivityManagerSingleton, iActivityManageProxy);
        } catch (Exception e) {
            Log.d("HookActivityManager", "" + e);
        }
    }


    private class IActivityManagerProxy implements InvocationHandler {
        private Object iActivityManager;
        public IActivityManagerProxy(Object iActivityManager) {
            this.iActivityManager = iActivityManager;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

            if ("reportSizeConfigurations".equals(method.getName())) {
                try {
                    Log.w(TAG, "reportSizeConfigurations invoke execute ");
                    return method.invoke(iActivityManager, args);
                } catch (Exception e) {

                    Log.w(TAG, "reportSizeConfigurations exception: " + e.getMessage());
                }
            }
            return method.invoke(iActivityManager, args);
        }
    }
}

15、unsupported class file major version 62 gradle

该问题是由于Gradle 与java版本不一致,导致Gradle编译失败,可以调整java版本或者调整gradle版本。

16、可能导致TransactionTooLargeException crash的几种情况

虽然可以看出是binder中传递了过大的数据,但是要定位具体是哪里传递了过大的数据并没有那么容易;

以下为可能出现的几种情况:

  • 1、activity或者fragment跳转时,传递的bundle携带了过大的数据,比如传递了bitmap或者size很大的ArrayList;可以使用toolargetool查看。
  • 2、Activity.onSaveInstanceState()保存了过大的数据
  • 3、FragmentStatePagerAdapter的saveState保存了过多的历史Fragment实例的状态数据,重写saveState

17、项目升级Android12 (31)以后,编译release版本报错"-keepclassmembers class * { *** @{}(android.view.View); }"

问题原因:

开启了混淆
项目中布局文件使用了android:onClick=“click 方法”
如果没有混淆需求可以直接关闭混淆;
否则需要删除所有布局文件中的onClick写法。

18、Android 暗黑模式适配中,出现了暗黑模式跟亮色同时存在的情况,导致页面显示异常

问题原因:

AppCompatDelegate.setDefaultNightMode(int mode)
该方法设置以后,如果应用或者系统中存在横竖屏切换的应用,那么横竖屏切换以后会导致该方法设置的状态不生效。从而出现错乱,需要在切到主页或者某些统一的位置进行重新设置。

19、Android源码网址

包含android源码下载、build、在线源码查找等.

https://source.android.com/

20、Java中使用HttpsURLConnection时需要特别注意的点

HttpsURLConnection提供了一个静态方法setDefaultSSLSockeFactory()。 可以提供一个自定义javax.net.ssl.TrustManager,用来做CA证书握手和验证等。但是,这将覆盖JVM中所有“ https” URL的默认值!

目前因该设置导致的问题:
1、FireBase crash 数据统计上报调用以后,在Firebase后台无法看到。
是因为代码中调用setDefaultSSLSocketFactory方法导致FireBase数据上报使用了错误的sslSocketFactory对象,导致验证没有通过。
可以使用单独对某个对象设置setSSLSocketFactory。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值