Android 开发问题

Posted 元气小嘉

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 开发问题相关的知识,希望对你有一定的参考价值。

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

android开发问题



提示:以下是本篇文章正文内容,下面案例可供参考

1.Fragment 内findViewByid空指针问题

Attempt to invoke virtual method 'android.view.View android.view.View.findViewById(int)' on a null object reference

解决方法:

 public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) 
        // Inflate the layout for this fragment
        View v=inflater.inflate(R.layout.fragment_main, container, false);

        smartRefreshLayout= v.findViewById(R.id.smart_refreshLayout);

        grid_div=v.findViewById(R.id.grid_divs);

        tv_add_dev =v.findViewById(R.id.tv_add_dev);
        layout_2_set_location =v.findViewById(R.id.layout_2_set_location);
 
        return v;

    

2.getApplication 空指针问题

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method ‘android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()’ on a null object reference

解决办法:定义可以在OnCreat外,但FindViewByid要在Oncreat内。

3.NullPointerException异常:

FragmentManager.beginTransaction()
Fragment fragment =this.getsupportFragmentManager();

4.Can’t toast on a thread that has not called Looper.prepare()问题

问题描述:

 java.lang.NullPointerException: Can't toast on a thread that has not called Looper.prepare()

如果在一个线程中没有调用Looper.prepare(),就不能在该线程中创建Toast。这个问题是因为在子线程中弹出Toast导致的。

解决办法:先调用Looper.prepare();再调用Toast.makeText().show();最后再调用Looper.loop();

Looper.prepare();
Toast.makeText(Modify_pho_or_passActivity.this,"修改成功!",Toast.LENGTH_LONG).show();
Looper.loop();

5.okhttp3 response内的数据无法在外部使用

问题描述:在okhttp中我们成功的访问后台,然后从onResponse中获得了返回的json数据),这个返回的数据只能在onResponse方法内调用,放到方法外这个数据就无法使用,追根揭底就是okhttp是异步请求,你没办法将异步请求的结果放到主线程中使用。

自己使用的RecycleView,在onResponse外使用,无数据进adapter;在onResponse内使用,提示

Only the original thread that created a view hierarchy can touch its views.

异常的意思是说只有创建这个view的线程才能操作这个 view,普通会认为是将view创建在非UI线程中才会出现这个错误。


解决办法:在onResponse内创建了runOnUiThread,写入recycleView的配置,将其在主线程中操作。


@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException 
               final String responseData = response.body().string();
               //解析json
               devices = JsonManager.parseJsonArray(responseData, DeviceEntity.class);
              // Log.e("devices",devices.get(0).getDevicename());
               runOnUiThread(new Runnable() 
                   @Override
                   public void run() 
                       if(devices!=null)
                       
                           rv_devices_list.setLayoutManager(new LinearLayoutManager(DeviceManagerActivity.this));
                           devListAdapter =new DevListAdapter(devices);
                           rv_devices_list.setAdapter(devListAdapter);
                           // rv_devices_list.setVisibility(View.VISIBLE);
                       
                   
               );
           
       );

6.TabLayout 加载适配器后TabItem不显示问题

问题描述:
在XMl文件中静态加载TabItem,tabLayout.setupWithViewPager(viewPager)之前可以显示,之后就不能显示。

原因及解决办法:
https://blog.csdn.net/sundy_tu/article/details/52682246

最好从PageAdapter内动态添加TabItem。

 @Nullable
    @Override
    public CharSequence getPageTitle(int position) 
        title.clear();
        title.add("查询数据");
        title.add("统计数据");
        return title.get(position);
    

7.Adapter内设置字体颜色无效

参考链接
有效:
holder.tv_1.setTextColor(Color.parseColor(“#FF0000”));
无效:
holder.tv_1.setTextColor(R.color.red);

Android 开发问题总结 四

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。

以上是关于Android 开发问题的主要内容,如果未能解决你的问题,请参考以下文章

Android 11 (API 30) ContentProvider开发及碰到的问题 (Unknown URL content)

android开发难学吗? Android开发学习方法

Android开发问题怎么解决?

如何更好地开发一个Android应用

如何更好地开发一个Android应用

android开发遇到问题之一