Android,Adapter 的 getView 中的 NullPointerException
Android, NullPointerException in an Adapter's getView
我目前正在学习 Android,这是我的第一个练习应用程序之一。
该应用是 'Daily Selfie' 应用。它应该在屏幕上显示项目列表。每个项目都应该有一个图像的缩略图和文件名。单击一个项目应全屏打开图像。操作栏中有一个相机图标。单击此按钮应打开设备上的现有相机 activity。拍照时,应保存该照片,然后显示在我的应用程序的列表中。
我有上述所有工作。但是我对这种情况有一个问题:我通过我的应用程序打开相机activity,然后将设备横向旋转,然后拍照,然后接受照片。当它尝试使用项目列表再次加载我的应用程序时,我收到 NullPointerException。
我已经为适配器设置了断点并弄清楚了:适配器中的项目列表在那里,假设大小为 10。前 9 个元素已填充且正常,但最后一个元素为空。如果我在相机打开时不旋转设备,我就没有这个问题。
有什么解决办法吗?
这是我认为与问题相关的代码(我省略了一些东西,比如设置闹钟和上下文菜单,我认为它们在这里无关紧要?)。
在MainActivity.java中:
private File mCurrentPhoto;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAdapter = new SelfieListAdapter(getApplicationContext());
setListAdapter(mAdapter);
readImages();
getListView().setBackgroundColor(getResources().getColor(R.color.white));
setupAlarm();
registerForContextMenu(getListView());
}
private void readImages(){
File dir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
for(File f : dir.listFiles()){
mAdapter.add(f);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem menuItem){
if(menuItem.getItemId() == R.id.camera_item){
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if(intent.resolveActivity(getPackageManager()) != null){
getOutputMediaFile(); //Sets mCurrentPhoto to a new file with a unique name
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mCurrentPhoto));
startActivityForResult(intent, CAMERA_REQUEST_CODE);
}
}
return true;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
if(requestCode == CAMERA_REQUEST_CODE && resultCode == RESULT_OK){
mAdapter.add(mCurrentPhoto);
}
}
private void getOutputMediaFile(){
if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
return;
}
File mediaStorageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
if (!mediaStorageDir.exists()){
if (!mediaStorageDir.mkdirs()){
Log.d("DailySelfie", "Failed to create directory");
return;
}
}
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
mCurrentPhoto = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
}
这是适配器中的相关代码:
private static final int THUMBNAIL_WIDTH = 160;
private static final int THUMBNAIL_HEIGHT = 120;
List<File> mItems = new ArrayList<>();
Context context;
public SelfieListAdapter(Context context){
this.context = context;
}
public void add(File file){
mItems.add(file);
notifyDataSetChanged();
}
@Override
public View getView(int pos, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if(convertView == null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.selfie, parent, false);
viewHolder = new ViewHolder();
viewHolder.thumbnail = (ImageView) convertView.findViewById(R.id.thumbnail);
viewHolder.filename = (TextView) convertView.findViewById(R.id.image_filename);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
File selfie = mItems.get(pos);
Bitmap fullImage = BitmapFactory.decodeFile(selfie.getAbsolutePath());
viewHolder.thumbnail.setImageBitmap(
Bitmap.createScaledBitmap(fullImage, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, true));
viewHolder.filename.setText(selfie.getName().split("\.")[0]);
return convertView;
}
static class ViewHolder{
ImageView thumbnail;
TextView filename;
}
我得到的 NullPointerException 是在这一行,因为自拍是空的:
Bitmap fullImage = BitmapFactory.decodeFile(selfie.getAbsolutePath());
但仅针对列表中的最后一个元素。谢谢...感谢任何帮助。
顺便说一下,我在这里有什么明显的不良做法吗?
感谢您的帮助。
编辑:好吧,我想我已经弄清楚为什么会这样,但我不知道如何解决它。
当设备倾斜时,我的 activity 是否被破坏然后重新创建?即使它不是当前的 activity?因此 mCurrentPhoto 为 null,所以我要在 onActivityResult?
中向适配器添加 null
我不知道如何解决这个问题。一个 null 意图仍然传递到 onActivityResult 中,所以那里没有我可以使用的东西。
当您旋转 CameraActivity 并返回到您的 MainActivity 时,MainActivity 现在也处于新的方向。每当屏幕方向改变时,activity 就会被销毁并重新创建,这就是 mCurrentPhoto 为 null 的原因。
解决方案 -
1- 为您的 mCurrentPhoto 制作 属性 方法,如下所示
private File getCurrentPhotoFile(){
return mCurrentPhoto == null ? mCurrentPhoto = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg") : mCurrentPhoto;
}
然后在你的 onActivityResult() 中使用这个
mAdapter.add(getCurrentPhotoFile());
或
2 - 使用 onSaveInstanceState() 回调方法保存 mCurrentPhoto 并在 onCreate() 或 onRestoreInstanceState() 上从包中获取 mCurrentPhoto 值。
我目前正在学习 Android,这是我的第一个练习应用程序之一。
该应用是 'Daily Selfie' 应用。它应该在屏幕上显示项目列表。每个项目都应该有一个图像的缩略图和文件名。单击一个项目应全屏打开图像。操作栏中有一个相机图标。单击此按钮应打开设备上的现有相机 activity。拍照时,应保存该照片,然后显示在我的应用程序的列表中。
我有上述所有工作。但是我对这种情况有一个问题:我通过我的应用程序打开相机activity,然后将设备横向旋转,然后拍照,然后接受照片。当它尝试使用项目列表再次加载我的应用程序时,我收到 NullPointerException。
我已经为适配器设置了断点并弄清楚了:适配器中的项目列表在那里,假设大小为 10。前 9 个元素已填充且正常,但最后一个元素为空。如果我在相机打开时不旋转设备,我就没有这个问题。
有什么解决办法吗?
这是我认为与问题相关的代码(我省略了一些东西,比如设置闹钟和上下文菜单,我认为它们在这里无关紧要?)。
在MainActivity.java中:
private File mCurrentPhoto;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAdapter = new SelfieListAdapter(getApplicationContext());
setListAdapter(mAdapter);
readImages();
getListView().setBackgroundColor(getResources().getColor(R.color.white));
setupAlarm();
registerForContextMenu(getListView());
}
private void readImages(){
File dir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
for(File f : dir.listFiles()){
mAdapter.add(f);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem menuItem){
if(menuItem.getItemId() == R.id.camera_item){
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if(intent.resolveActivity(getPackageManager()) != null){
getOutputMediaFile(); //Sets mCurrentPhoto to a new file with a unique name
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mCurrentPhoto));
startActivityForResult(intent, CAMERA_REQUEST_CODE);
}
}
return true;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
if(requestCode == CAMERA_REQUEST_CODE && resultCode == RESULT_OK){
mAdapter.add(mCurrentPhoto);
}
}
private void getOutputMediaFile(){
if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
return;
}
File mediaStorageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
if (!mediaStorageDir.exists()){
if (!mediaStorageDir.mkdirs()){
Log.d("DailySelfie", "Failed to create directory");
return;
}
}
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
mCurrentPhoto = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
}
这是适配器中的相关代码:
private static final int THUMBNAIL_WIDTH = 160;
private static final int THUMBNAIL_HEIGHT = 120;
List<File> mItems = new ArrayList<>();
Context context;
public SelfieListAdapter(Context context){
this.context = context;
}
public void add(File file){
mItems.add(file);
notifyDataSetChanged();
}
@Override
public View getView(int pos, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if(convertView == null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.selfie, parent, false);
viewHolder = new ViewHolder();
viewHolder.thumbnail = (ImageView) convertView.findViewById(R.id.thumbnail);
viewHolder.filename = (TextView) convertView.findViewById(R.id.image_filename);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
File selfie = mItems.get(pos);
Bitmap fullImage = BitmapFactory.decodeFile(selfie.getAbsolutePath());
viewHolder.thumbnail.setImageBitmap(
Bitmap.createScaledBitmap(fullImage, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, true));
viewHolder.filename.setText(selfie.getName().split("\.")[0]);
return convertView;
}
static class ViewHolder{
ImageView thumbnail;
TextView filename;
}
我得到的 NullPointerException 是在这一行,因为自拍是空的:
Bitmap fullImage = BitmapFactory.decodeFile(selfie.getAbsolutePath());
但仅针对列表中的最后一个元素。谢谢...感谢任何帮助。
顺便说一下,我在这里有什么明显的不良做法吗?
感谢您的帮助。
编辑:好吧,我想我已经弄清楚为什么会这样,但我不知道如何解决它。 当设备倾斜时,我的 activity 是否被破坏然后重新创建?即使它不是当前的 activity?因此 mCurrentPhoto 为 null,所以我要在 onActivityResult?
中向适配器添加 null我不知道如何解决这个问题。一个 null 意图仍然传递到 onActivityResult 中,所以那里没有我可以使用的东西。
当您旋转 CameraActivity 并返回到您的 MainActivity 时,MainActivity 现在也处于新的方向。每当屏幕方向改变时,activity 就会被销毁并重新创建,这就是 mCurrentPhoto 为 null 的原因。
解决方案 -
1- 为您的 mCurrentPhoto 制作 属性 方法,如下所示
private File getCurrentPhotoFile(){
return mCurrentPhoto == null ? mCurrentPhoto = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg") : mCurrentPhoto;
}
然后在你的 onActivityResult() 中使用这个
mAdapter.add(getCurrentPhotoFile());
或 2 - 使用 onSaveInstanceState() 回调方法保存 mCurrentPhoto 并在 onCreate() 或 onRestoreInstanceState() 上从包中获取 mCurrentPhoto 值。