我试图让我的Android应用程序使用proguard。将minifyEnabled
设置为false,应用运行正常。当 true 时,我收到以下错误:
04-09 22:39:21.622 21657-21657/com.jcg.grocerylistconverter E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.jcg.grocerylistconverter, PID: 21657
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.jcg.grocerylistconverter/com.jcg.grocerylistconverter.RecipeActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.util.AbstractMap.toString()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2947)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3008)
at android.app.ActivityThread.-wrap14(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1650)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6688)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.util.AbstractMap.toString()' on a null object reference
at com.jcg.grocerylistconverter.p.onCreateView(Unknown Source)
at android.support.v4.app.Fragment.performCreateView(Unknown Source)
at android.support.v4.app.FragmentManagerImpl.moveToState(Unknown Source)
at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(Unknown Source)
at android.support.v4.app.FragmentManagerImpl.moveToState(Unknown Source)
at android.support.v4.app.BackStackRecord.executeOps(Unknown Source)
at android.support.v4.app.FragmentManagerImpl.executeOps(Unknown Source)
at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(Unknown Source)
at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(Unknown Source)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(Unknown Source)
at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(Unknown Source)
at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(Unknown Source)
at android.support.v4.app.FragmentController.dispatchActivityCreated(Unknown Source)
at android.support.v4.app.FragmentActivity.onStart(Unknown Source)
at android.support.v7.app.AppCompatActivity.onStart(Unknown Source)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1256)
at android.app.Activity.performStart(Activity.java:6929)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2910)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3008)
at android.app.ActivityThread.-wrap14(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1650)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6688)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
现在如果我查看我的RecipeActivity,就没有方法调用AT toString()
:
public class RecipeActivity extends AppCompatActivity {
private static final String TAG = "RecipeActivity";
private RecipeDatabase dbHelper;
private String mMenuRecipeTitle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recipe);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_RA);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowTitleEnabled(true);
String retreivedRecipe = getIntent().getStringExtra("recipeKey");
String retrievedGson = getIntent().getStringExtra("gsonRecipe");
dbHelper = RecipeDatabase.getInstance(this);
SQLiteDatabase db = dbHelper.getWritableDatabase();
String[] columns = new String[] {
"rowid AS " + RecipeContract.Columns._ID,
RecipeContract.Columns.RECIPE_NAME,
RecipeContract.Columns.RECIPE_CUPSTOGRAMS,
RecipeContract.Columns.RECIPE_SORTLIST,
RecipeContract.Columns.RECIPE_MEALTYPE
};
String whereclause = RecipeContract.Columns.RECIPE_NAME + "=?";
String[] whereargs = new String[] {retreivedRecipe};
Cursor cursor = db.query(RecipeContract.TABLE_NAME, columns, whereclause, whereargs,
null, null, null);
cursor.moveToFirst();
String listName = cursor.getString(cursor.getColumnIndex(RecipeContract.Columns.RECIPE_SORTLIST));
mMenuRecipeTitle = listName;
cursor.close();
RecipeActivityFragment fragment = new RecipeActivityFragment();
if (retreivedRecipe != null) {
Bundle bundle = new Bundle();
bundle.putString("retrievedRecipe", retreivedRecipe);
bundle.putString("retrievedGson", retrievedGson);
fragment.setArguments(bundle);
}
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragment_recipe_activity, fragment, TAG).commit();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_recipe_activity, menu);
MenuItem recipeListName = menu.findItem(R.id.menu_RecipeList);
recipeListName.setTitle(mMenuRecipeTitle);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
}
我会在我的build.gradle
文件和我的proguard-rules.pro
下面发布我的依赖项。
依赖关系:
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.android.support:design:26.1.0'
implementation 'com.android.support:support-v4:26.1.0'
implementation 'com.android.support:recyclerview-v7:26.1.0'
implementation 'com.google.code.gson:gson:2.8.2'
implementation 'com.fasterxml.jackson.core:jackson-core:2.7.3'
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.7.3'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.7.3'
implementation 'com.jaredrummler:material-spinner:1.2.4'
implementation 'com.google.android.gms:play-services-ads:12.0.1'
implementation 'com.android.support:multidex:1.0.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}
proguard-rules.pro
-keep class google.code.gson.** { *; }
-keep class com.fasterxml.databind.** { *; }
-keep class com.fasterxml.annotations.** { *; }
-keep class com.fasterxml.core.** { *; }
-keep class com.jaredrumler.material-spinner.** { *; }
-keepnames class com.fasterxml.jackson.** {*;}
-keepnames interface com.fasterxml.jackson.** {*;}
-dontwarn com.fasterxml.jackson.databind.**
-dontwarn com.fasterxml.jackson.annotations.**
-dontwarn com.fasterxml.jackson.core.**
-dontwarn com.jaredrumler.material-spinner.**
-assumenosideeffects class android.util.Log {
public static *** e(...);
public static *** w(...);
public static *** wtf(...);
public static *** d(...);
public static *** v(...);
public static *** i(...);
对于这里发生的事情感到非常困惑,我已经在这个问题上广泛搜索了类似的问题,但我找不到任何东西。我是否需要-dontwarn
拨打AbstractMap
电话?这似乎有点极端。
编辑:这是我的RecipeActivityFragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_recipe_activity, container, false);
mRecipeTitle = (TextView) view.findViewById(R.id.recipeactivityfragment_name);
mMealType = (TextView) view.findViewById(R.id.recipeactivityfragment_meal);
mIngredientTitle = (TextView) view.findViewById(R.id.rfa_ingredients);
mGramTitle = (TextView) view.findViewById(R.id.rfa_grams);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recipe_recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mRecyclerView.addItemDecoration(new VerticalSpaceItemDecoration(0));
Bundle arguments = getArguments();
final String recipeName = arguments.getString("retrievedRecipe");
Log.d(TAG, "onCreateView: recipeName = " + recipeName);
SQLiteDatabase db = dbHelper.getWritableDatabase();
String[] columns = new String[] {
"rowid AS " + RecipeContract.Columns._ID,
RecipeContract.Columns.RECIPE_NAME,
RecipeContract.Columns.RECIPE_CUPSTOGRAMS,
RecipeContract.Columns.RECIPE_SORTLIST,
RecipeContract.Columns.RECIPE_MEALTYPE
};
String whereclause = RecipeContract.Columns.RECIPE_NAME + "=?";
String[] whereargs = new String[] {recipeName};
Cursor cursor = db.query(RecipeContract.TABLE_NAME, columns, whereclause, whereargs,
null, null, null);
cursor.moveToFirst();
String recipeTitle = cursor.getString(cursor.getColumnIndex(RecipeContract.Columns.RECIPE_NAME));
String recipeCupsToGrams = cursor.getString(cursor.getColumnIndex(RecipeContract.Columns.RECIPE_CUPSTOGRAMS));
Log.d(TAG, "onCreateView: cupsToGrams = " + recipeCupsToGrams);
// other cups etc here
String recipeMealType = cursor.getString(cursor.getColumnIndex(RecipeContract.Columns.RECIPE_MEALTYPE));
String listName = cursor.getString(cursor.getColumnIndex(RecipeContract.Columns.RECIPE_SORTLIST));
mMenuRecipeTitle = listName;
cursor.close();
final String recipeGson = arguments.getString("retrievedGson");
Log.d(TAG, "onCreateView: recipeGson = " + recipeGson);
Recipe r;
r = mGson.fromJson(recipeGson, Recipe.class);
Log.d(TAG, "onCreateView: hashMapToString... = " + hashMapToJSONtoHashMap(r).toString());
mRecipeTitle.setText(recipeTitle);
mMealType.setText(recipeMealType);
JSONtoHashMap(recipeCupsToGrams);
mIngredientAdapter = new IngredientAdapter(JSONtoHashMap(recipeCupsToGrams));
mRecyclerView.setAdapter(mIngredientAdapter);
return view;
}
private HashMap<String, Float> hashMapToJSONtoHashMap(Recipe r) {
String json = mGson.toJson(r.getIngredientsGrams());
HashMap<String, Float> noWork = new HashMap<>();
HashMap<String, Float> cupsToGrams;
try {
cupsToGrams = new ObjectMapper().readValue(json, HashMap.class);
} catch (IOException e) {
e.printStackTrace();
return noWork;
}
return cupsToGrams;
}
我删除对该行的调用
Log.d(TAG, "onCreateView: hashMapToString... = " + hashMapToJSONtoHashMap(r).toString());
运行正常。为什么这与proguard关闭工作正常?