gpt4 book ai didi

android - Google Play 控制台报告应用程序崩溃,我无法重现

转载 作者:行者123 更新时间:2023-11-28 20:49:31 26 4
gpt4 key购买 nike

Android Vitals 报告中的 Google Play 控制台为我提供了此信息

java.lang.RuntimeException: 
at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2955)
at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:3030)
at android.app.ActivityThread.-wrap11 (Unknown Source)
at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1696)
at android.os.Handler.dispatchMessage (Handler.java:105)
at android.os.Looper.loop (Looper.java:164)
at android.app.ActivityThread.main (ActivityThread.java:6938)
at java.lang.reflect.Method.invoke (Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run (Zygote.java:327)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1374)
Caused by: java.lang.NullPointerException:
at com.golendukhin.whitenoise.GridAdapter.getCount (GridAdapter.java:52)
at android.widget.GridView.setAdapter (GridView.java:243)
at com.golendukhin.whitenoise.FoldersGridActivity.onCreate (FoldersGridActivity.java:60)
at android.app.Activity.performCreate (Activity.java:7183)
at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1220)
at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2908)

据我所知,这是因为网格适配器的 getCount 方法返回空值。因此,网格适配器不起作用。因此,不会创建整个 Activity 。只有三星设备有这样的问题。

首先,我尝试创建具有相同 Android 版本、RAM 和 ARM 的相同模拟设备。模拟器工作得非常好。没有错误。

然后我添加了一些测试以确保 getCount 有效并创建了 Activity 。

@RunWith(AndroidJUnit4.class)
public class GridViewTest {

@Rule
public ActivityTestRule<FoldersGridActivity> foldersGridActivityTestRule = new ActivityTestRule<>(FoldersGridActivity.class);

@Test
public void ensureGridAdapterIsNotNull() {
FoldersGridActivity foldersGridActivity = foldersGridActivityTestRule.getActivity();
View view = foldersGridActivity.findViewById(R.id.grid_view);
GridView gridView = (GridView) view;
GridAdapter gridAdapter = (GridAdapter) gridView.getAdapter();
assertThat(gridAdapter, notNullValue());
}

@Test
public void ensureArrayAdapterInGridActivityIsNotEmpty() {
FoldersGridActivity foldersGridActivity = foldersGridActivityTestRule.getActivity();
View view = foldersGridActivity.findViewById(R.id.grid_view);
GridView gridView = (GridView) view;
GridAdapter gridAdapter = (GridAdapter) gridView.getAdapter();
assertTrue(gridAdapter.getCount() > 0 );
}

@Test
public void gridViewIsVisibleAndClickable() {
onData(anything()).inAdapterView(withId(R.id.grid_view)).atPosition(0).perform(click());
onView(withId(R.id.toolbar_title_text_view)).check(matches(withText("rain")));
}
}

所有模拟设备再次成功通过测试。然后我添加了 FireBase TestLab 并在装有 Android 8 的 Galaxy S9 真实设备上启动了我的测试。所有测试都通过了。

适配器代码。是的,我已经覆盖了 getCount() 方法,即使它没有意义。

public class GridAdapter extends ArrayAdapter<TracksFolder> {
@BindView(R.id.folder_text_view) TextView textView;
@BindView(R.id.grid_item_image_view) ImageView imageView;

private ArrayList<TracksFolder> tracksFolders;
private Context context;

GridAdapter(Context context, int resource, ArrayList<TracksFolder> tracksFolders) {
super(context, resource, tracksFolders);
this.tracksFolders = tracksFolders;
this.context = context;
}

/**
* @return grid item, customized via TracksFolder class instance
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.grid_item, parent, false);
}
ButterKnife.bind(this, convertView);

String folderName = tracksFolders.get(position).getFolderName();
int imageResource = tracksFolders.get(position).getImageResource();
textView.setText(folderName);
imageView.setImageResource(imageResource);

return convertView;
}

/**
* Added to possibly avoid NPE on multiple devices
* Could not reproduce this error
* @return size of tracksFolders
*/
@Override
public int getCount() {
return tracksFolders.size();
}
}

所以,我有几个问题:首先,此崩溃报告是否意味着每次 Sumsung 所有者启动应用程序时都会发生此崩溃?由于一些三星设备坚持统计,我假设没有。其次,我应该怎么做才能以某种方式重现此错误并最终修复错误。

我知道问题太宽泛了,但我真的很感激任何帮助,因为我绝对不知道下一步该做什么。

入门级。使用适配器

import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.GridView;

import com.google.firebase.crash.FirebaseCrash;

import java.util.ArrayList;
import butterknife.BindArray;
import butterknife.BindView;
import butterknife.ButterKnife;

import static com.golendukhin.whitenoise.SharedPreferencesUtils.writeToSharedPreferences;

public class FoldersGridActivity extends AppCompatActivity {
@BindView(R.id.grid_view) GridView gridView;
@BindArray(R.array.labels) String[] foldersName;
@BindView(R.id.toolbar_like_button) Button toolbarLikeButton;
@BindView(R.id.toolbar_back_button) Button toolbarBackButton;

private ArrayList<TracksFolder> tracksFolders;

/**
* Binds all UI views
* Defines variables to feed adapter and listeners
* Initializes grid adapter, sets number of columns via phone in portrait or landscape orientation
* Sets onclick listener for every grid item
* Sets onclick for toolbar "like" button
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.folders_grid_view);
ButterKnife.bind(this);

if (getIntent().getExtras() != null) { //activity is triggered via on back pressed
Bundle bundle = getIntent().getExtras();
tracksFolders = (ArrayList<TracksFolder>) bundle.getSerializable("tracksFolders");
} else if (savedInstanceState != null) { //this happens after screen is rotated
tracksFolders = (ArrayList<TracksFolder>) savedInstanceState.getSerializable("tracksFolders");
} else { //this happens if app is launched by user
tracksFolders = getTracksFolders();
initService();
}

toolbarBackButton.setVisibility(View.GONE);

GridAdapter gridAdapter;
gridAdapter = new GridAdapter(this, R.id.grid_view, tracksFolders);
gridView.setNumColumns(getResources().getInteger(R.integer.columns_number));
gridView.setAdapter(gridAdapter);
FirebaseCrash.log("Activity created");

gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Bundle bundle = new Bundle();
bundle.putSerializable("tracksFolders", tracksFolders);
bundle.putInt("folderPosition", position);
Intent intent = new Intent(FoldersGridActivity.this, TracksListActivity.class);
intent.putExtras(bundle);
startActivity(intent);
}
});

toolbarLikeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Bundle bundle = new Bundle();
bundle.putSerializable("tracksFolders", tracksFolders);
bundle.putInt("activityFrom", Constants.FROM_FOLDERS_GRID_ACTIVITY);
Intent intent = new Intent(FoldersGridActivity.this, LikedTracksListActivity.class);
intent.putExtras(bundle);
startActivity(intent);
}
});
}

/**
* Saves tracksFolders array list to rebuild activity after rotation
*/
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putSerializable("tracksFolders", tracksFolders);
writeToSharedPreferences(this, tracksFolders);
super.onSaveInstanceState(outState);
}

@Override
public void onBackPressed() {
super.onBackPressed();
moveTaskToBack(true);
}

/**
* After app is launched need to initialize audio player service
*/
private void initService() {
Intent intent = new Intent(FoldersGridActivity.this, AudioPlayerService.class);
startService(intent);
}

/**
* If tracksFolders is not stored in shared preferences, it is initialized from resources.
* @return arrayList of folders with arrayList of tracks belonging to every folder
*/
private ArrayList<TracksFolder> getTracksFolders() {
Resources resources = getResources();
TypedArray pictures = resources.obtainTypedArray(R.array.pictures);

ArrayList<TracksFolder> tracksFolders = new ArrayList<>();
for (int i = 0; i < foldersName.length; i++) {
String folderName = foldersName[i];
int imageResource = pictures.getResourceId(i, -1);
ArrayList<Track> tracks = getArrayListOfTracks(resources, i, imageResource);
tracksFolders.add(new TracksFolder(folderName, imageResource, tracks));
}
pictures.recycle();
return tracksFolders;
}

/**
* @param resources need to get typedArray to get array of audio files names
* @param folderPosition passed to Track constructor
* @param imageResource passed to Track constructor
* Liked tracks are obtained from shared preferences
* @return array list of tracks for every folder
*/
private ArrayList<Track> getArrayListOfTracks(Resources resources, int folderPosition, int imageResource) {
TypedArray audioTracksTypedArray = resources.obtainTypedArray(R.array.audio_tracks);
int audioTracksId = audioTracksTypedArray.getResourceId(folderPosition, 0);
String[] audio = resources.getStringArray(audioTracksId);
audioTracksTypedArray.recycle();

TypedArray trackNamesTypedArray = resources.obtainTypedArray(R.array.track_names);
int trackNamesId = trackNamesTypedArray.getResourceId(folderPosition, 0);
String[] trackNames = resources.getStringArray(trackNamesId);
trackNamesTypedArray.recycle();

SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());

ArrayList<Track> tracksInFolder = new ArrayList<>();
for (int i = 0; i < trackNames.length; i++) {
int audioResource = resources.getIdentifier(audio[i], "raw", this.getPackageName());
String trackName = trackNames[i].replace("_", " ");
boolean isLiked = sharedPreferences.getBoolean(String.valueOf(audioResource), false);
tracksInFolder.add(new Track(audioResource, trackName, imageResource, isLiked));
}
return tracksInFolder;
}
//todo убрать полосы в списках треков
}

更新类:

@NonNull
private ArrayList<TracksFolder> getTracksFoldersAndInitService(Bundle savedInstanceState) {
if (getIntent().getExtras() != null) { //activity is triggered via on back pressed
Bundle bundle = getIntent().getExtras();
tracksFolders = (ArrayList<TracksFolder>) bundle.getSerializable("tracksFolders");
} else if (savedInstanceState != null) { //this happens after screen is rotated
tracksFolders = (ArrayList<TracksFolder>) savedInstanceState.getSerializable("tracksFolders");
} else { //this happens if app is launched by user
tracksFolders = getTracksFoldersFromResources();
initService();
}
return tracksFolders;
}

@Nick Fortescue,@Ranjan,谢谢你们的建议,但 tracksFolders 永远不会为 NULL。我已经编辑了类(您可以在“更新的类:”下方看到它)并将 tracksFolders 实例化分离到另一个带有 @NonNull 注释的方法中。我已经用这些更改更新了应用程序,后来又用相同的日志获得了相同的 NPE。我知道这是在用户身上测试应用程序的最糟糕方式,但我别无选择。如果你是对的,日志会说在 getTracksFoldersAndInitService 方法中抛出了异常。但它没有。因此,问题出在适配器中。如果我错了,请纠正我。

最佳答案

GridAdapter.getCount() 中出现的 NullPointerException 并不意味着 getCount() 返回 null。这意味着它正在访问一个空值。由于您上传了代码(太棒了!),我们可以看到只有两个可能的问题:

  • trackFoldersnull,所以当您访问它时,您会得到一个 NPE
  • trackFolders 返回一个 null 整数,因此当它被转换为一个 int 时,您会得到一个 NPE

第二个选项是不可能的,因为 ArrayList 上的 .size() 也返回一个 int,所以它必须是第一个选项。

trackFolders 在构造函数中设置,它在您的 onCreate() 方法中从 bundle、从保存的状态或从 getTracksFolders() 设置。看起来 getTracksFolders() 无法返回 null,所以我猜测您的 Activity 是在将此设置为 null 的情况下启动的。我会在您的 onCreate() 方法中仔细检查这一点,如果发生这种情况,请采取适当的措施,也许用 new ArrayList() 替换它?

关于android - Google Play 控制台报告应用程序崩溃,我无法重现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53027956/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com