【问题标题】:Gson Not mapping data in Production Mode APK AndroidGson 没有在生产模式下映射数据 APK Android
【发布时间】:2017-02-16 18:48:31
【问题描述】:

我正在使用 Gson 将数据映射到 ArrayList。在设备上或在调试模式下运行应用程序时工作正常,但在生产模式 APK 中没有映射数据。 这是代码

Const.courses = new ArrayList<>();
    Log.v("Courses",object.toString());
    Type type = new TypeToken<ArrayList<Course>>() {
    }.getType();

    if(object != null && object.has("data") ){

        try {
            if(object.get("data") != null && object.getJSONArray("data").length()>0) {
                Const.courses.clear();
                Const.courses = new GsonBuilder().create().fromJson(object.getJSONArray("data").toString(), type);

                Log.d("Course from Array",Const.courses.get(0).getTitle());

  adapter = new CourseAdapter(getApplicationContext(), R.layout.course_row_layout, Const.courses);
                listView.setDivider(new ColorDrawable(ContextCompat.getColor(getApplicationContext(), android.R.color.transparent)));
                listView.setAdapter(adapter);
            }else{
                tvSelectCourse.setVisibility(View.GONE);
                tvNoCourse.setVisibility(View.VISIBLE);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}

这里是 Logcat。任何帮助将不胜感激。

    02-16 23:30:57.836 1234-1234/? V/Courses: {"contentEncoding":null,"contentType":null,"data":[{"id":1,"title":"course Updated"},{"id":12,"title":"Arabic"},{"id":13,"title":"usman"},{"id":14,"title":"really "},{"id":15,"title":"urdu"},{"id":17,"title":"abc"},{"id":21,"title":"course"},{"id":22,"title":"Ali don"},{"id":24,"title":"umair"},{"id":25,"title":"math"},{"id":27,"title":"world"},{"id":28,"title":"wether"},{"id":33,"title":"computer Science "},{"id":34,"title":"cs"},{"id":37,"title":"maths"},{"id":38,"title":"hello"},{"id":39,"title":"course Updated"},{"id":42,"title":"for testing purpose"}],"jsonRequestBehavior":0,"maxJsonLength":null,"recursionLimit":null}
02-16 23:30:57.852 1234-1234/? D/AndroidRuntime: Shutting down VM
02-16 23:30:57.859 1234-1234/? E/AndroidRuntime: FATAL EXCEPTION: main
                                                 Process: com.umer.doratiteacher, PID: 1234
                                                 java.lang.NullPointerException: println needs a message
                                                     at android.util.Log.println_native(Native Method)
                                                     at android.util.Log.d(Log.java:139)
                                                     at com.umer.doratiteacher.MainActivity$3.a(Unknown Source)
                                                     at com.umer.doratiteacher.d.a$3.a(Unknown Source)
                                                     at com.umer.doratiteacher.d.a$3.a(Unknown Source)
                                                     at com.a.a.a.i.a(Unknown Source)
                                                     at com.a.a.e$a.run(Unknown Source)
                                                     at android.os.Handler.handleCallback(Handler.java:739)
                                                     at android.os.Handler.dispatchMessage(Handler.java:95)
                                                     at android.os.Looper.loop(Looper.java:234)
                                                     at android.app.ActivityThread.main(ActivityThread.java:5526)
                                                     at java.lang.reflect.Method.invoke(Native Method)
                                                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

【问题讨论】:

  • 你使用过 pro_guard 吗?它会改变你的班级名称。您必须在 pro_guard 文件中定义一些设置。
  • 这就是你要的 .. buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }
  • 我需要哪些 pro_guard 设置?

标签: android json gson


【解决方案1】:

如前所述,问题来自 Proguard(当 minifyEnabledtrue 时)。 Proguard 去掉了 GSON 解析所需的Type

基于此链接,https://github.com/google/gson/blob/master/examples/android-proguard-example/proguard.cfg,我只需添加 3 行即可让我的代码工作

# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature

# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }

# Application classes that will be serialized/deserialized over Gson
-keep class com.example.YourPackage.** { *; }

最后一行是代码所在包的名称。如果您将所有代码放在一个主包中(所有 java 文件在一个目录中)或仅在一个文件中进行 GSON 解析,则替换为 last为此行(我已经测试了上述但没有测试以下)

-keep class com.example.YourPackage.YourClass.** { *; }

【讨论】:

    【解决方案2】:

    @Gary 已正确识别出 Proguard 是这里的问题。他给出的解决方案确实有效。实现这一点的另一种方法是添加

    @Keep 
    

    androidx.annotation.Keep 到 yourClass 的注释。

    【讨论】:

      【解决方案3】:

      这是 build.gradle 中的代码

      buildTypes {
              release {
                  minifyEnabled true
                  proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
                  signingConfig signingConfigs.release
                  lintOptions {
                      disable 'MissingTranslation'
                  }
              }
      ...
      

      您必须在 proguard_rules.pro 中定义哪些类不应更改其名称

      这是我的:

      -optimizationpasses 5
      -dontusemixedcaseclassnames
      -dontskipnonpubliclibraryclasses
      -dontpreverify
      -verbose
      
      -dontwarn org.joda.time.**
      -keep class org.joda.time.** {
      *;
      }
      
      -keep class com.xxx.xxx.** {
      public *;
      }
      
      -keep class android.support.**{*;}
      -keep class org.jsoup.**{*;}
      -keep class com.google.**{*;}
      

      使用 -keep 保留你的类名或方法名, 这是文件中的详细链接

      # For more details, see
      #   http://developer.android.com/guide/developing/tools/proguard.html
      

      【讨论】:

      • @UmerFarooq 你可以将minifyEnabled 设置为false,那么所有的东西都不会被专业守卫改变..
      • 这对我不起作用..知道这里发生了什么
      • @UmerFarooq 你有没有尝试将minifyEnabled 设置为false,我认为这会起作用
      【解决方案4】:

      您应该注释您的类属性,以便 Gson 知道要查找的内容:

          public class RData {
      
          @SerializedName("code")
          public String code;
          @SerializedName("info")
          public String info; 
      }
      

      【讨论】:

      • 问题与 GSON 映射无关。它已经在开发中工作。这是因为 minifyEnabled True。
      【解决方案5】:

      乍一看堆栈跟踪,您似乎正在将null 传递给您的日志调用:

      Log.d("Course from Array",Const.courses.get(0).getTitle());

      一个快速的解决方法是在将 getTitle() 方法传递给 log 方法之前检查以确保它不是 null。所以,像Log.d("Course from Array", TextUtils.isEmpty(Const.courses.get(0).getTitle()) ? "" : Const.courses.get(0).getTitle());

      【讨论】:

      • 不。它不为空。您可以在 logcat 中查看课程。第一个出现了。此外,它在调试模式下运行良好..
      • 只是从您提供的堆栈跟踪中说出来。那么这可能是一个支持/缩小的问题。
      • 什么问题??你能详细说明你想说什么吗??
      • Pro-guard/minifyEnabled 会混淆代码,因此它可能会删除调试版本中存在的生产版本中所需的类。此外,查看看起来可能的堆栈跟踪。尝试为 prod 构建切换 minifiedEnabled = false ,看看它是否解决了问题。如果是这样,你需要配置你的 pro-guard 规则,以确保你没有剥离重要的类。
      【解决方案6】:

      经过一整天的努力,我最终来到了这里,上面标记为有效的回复为我指明了正确的方向。 我已经提到了所有这些 proguard 规则,并且一切正常,直到...我更新了 gradle 和 Android Studio!
      现在 Android Studio 默认使用 R8 和 proguard 规则。所以我在 R8 寻找答案,瞧!这是link

      我在上面的规则中添加了以下内容:

      -keepclassmembers,allowobfuscation class * {
       @com.google.gson.annotations.SerializedName <fields>;
      }
      

      终于为我工作了。希望这对其他人有帮助

      【讨论】:

        猜你喜欢
        • 2017-07-05
        • 2019-11-11
        • 1970-01-01
        • 2010-11-20
        • 2012-11-23
        • 2014-10-21
        • 1970-01-01
        • 2010-09-17
        • 1970-01-01
        相关资源
        最近更新 更多