0

我希望标题没有误导。我正在尝试实现onRetainNonConfigurationInstance()加载AsyncTask图像并收到此错误"Java.lang.RuntimeException:Unable to retain Activity"。这是我的代码onRetainNonConfigurationInstance()

public Object onRetainNonConfigurationInstance(){
  //final ListView listview = list;

  final int count = list.getChildCount();
    final LoadedImage[] mylist = new LoadedImage[count];

    for(int i = 0; i < count; i++){
        final ImageView v = (ImageView)list.getChildAt(i); // getting error here
        mylist[i] = new LoadedImage(((BitmapDrawable) v.getDrawable()).getBitmap());
    }
    return mylist;
}

这是Logcat

05-18 08:43:15.385: E/AndroidRuntime(28130): java.lang.RuntimeException: Unable to retain activity {com.MyApps.ImageGen/com.MyApps.ImageGen.Wallpapers}: java.lang.ClassCastException: android.widget.LinearLayout
05-18 08:43:15.385: E/AndroidRuntime(28130):    at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:2989)
05-18 08:43:15.385: E/AndroidRuntime(28130):    at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:3100)
05-18 08:43:15.385: E/AndroidRuntime(28130):    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3216)
05-18 08:43:15.385: E/AndroidRuntime(28130):    at android.app.ActivityThread.access$1600(ActivityThread.java:132)

这是我的布局ListView

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

<ListView
    android:id="@android:id/list"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:cacheColorHint="#00000000"
    android:listSelector="@android:color/transparent" >
</ListView>     
</LinearLayout>

这是我设置的方法ListView

private void setupViews() { 
        list = (ListView)findViewById(android.R.id.list);
        list.setDivider(null);
        list.setDividerHeight(0);
        imageAdapter = new ImageAdapter(getApplicationContext());
        list.setAdapter(imageAdapter);
        list.setOnItemClickListener(this);
}

我的异步任务和项目适配器:

class LoadImagesFromSDCard extends AsyncTask<Object, LoadedImage, Object> {


    @Override
    protected Object doInBackground(Object... params) {

        Bitmap bitmap = null;
        Bitmap newbitmap = null;
        Uri uri = null;

        String [] img = {MediaStore.Images.Media._ID};

        String state = Environment.getExternalStorageState();

        if(Environment.MEDIA_MOUNTED.equals(state)){    

        cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, img, null, null, null);

        } else {
        // cursor = getContentResolver().query(MediaStore.Images.Media.INTERNAL_CONTENT_URI, img, null, null, null);

         inInternalStorage = true;
        }

        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID);
        int size = cursor.getCount();

        if(size == 0){
            //Toast.makeText(getApplicationContext(), "There are no Images on the sdcard", Toast.LENGTH_SHORT).show();
            //System.out.println("size equals zero");

            Wallpaper.this.runOnUiThread(new Runnable() {
                public void run() {
                    Toast.makeText(getApplicationContext(), "There are no Images on the sdcard", Toast.LENGTH_SHORT).show();
                }
            });

            return params;
        }else {

        }

        for(int i = 0; i < size; i++){
            cursor.moveToPosition(i);
            int ImageId = cursor.getInt(column_index);

            if(inInternalStorage == true){
             uri = Uri.withAppendedPath(MediaStore.Images.Media.INTERNAL_CONTENT_URI, "" + ImageId);
         }else {
             uri = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "" + ImageId);
         }


         try {
             BitmapFactory.Options options = new BitmapFactory.Options();
             options.inJustDecodeBounds = true;

             BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);

             int imageHeight = options.outHeight;
             int imageWidth = options.outWidth;
             String imageType = options.outMimeType;

             Log.i(TAG, "imageheight = " + imageHeight);
             Log.i(TAG, "imagewidth = " + imageWidth);
             Log.i(TAG, "imageType = " + imageType);

             //options.inSampleSize=4;

             options.inSampleSize = calculateInSampleSize(options, imageWidth, imageHeight);

            options.inJustDecodeBounds = false;
             //bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
             bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);

             if(bitmap != null){
                 newbitmap = Bitmap.createScaledBitmap(bitmap, 180, 180, true);
                 bitmap.recycle();
             }
             if(newbitmap != null){
                 publishProgress(new LoadedImage(newbitmap));

             }
         }catch(IOException e){

         }
         //cursor.close();
        }
        cursor.close();
        return null;    
    }

    @Override
    public void onProgressUpdate(LoadedImage... value){
        addImage(value);
    }

       @Override
        protected void onPostExecute(Object result) {
            setProgressBarIndeterminateVisibility(false);
        }
}

private static class LoadedImage {
    Bitmap mBitmap;

    LoadedImage(Bitmap bitmap) {
        mBitmap = bitmap;
    }

    public Bitmap getBitmap() {
        return mBitmap;
    }
}

/*Image Adapter to populate grid view of images*/

public class ImageAdapter extends BaseAdapter {
    private Context mContext;
    private ArrayList<LoadedImage> photos = new ArrayList<LoadedImage>();


    public ImageAdapter(Context context){
        this.mContext = context;
    }

    public void addPhotos(LoadedImage photo){
        photos.add(photo);
    }

    @Override
    public int getCount() {
        return photos.size();
    }


    @Override
    public Object getItem(int position) {
        return position;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ImageView image;
        ViewHolder holder;

        if(convertView == null){
            LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            //convertView = inflater.inflate(R.layout.image_list,null);
            convertView = inflater.inflate(R.layout.media_view, null);
            holder = new ViewHolder();

            holder.image = (ImageView)convertView.findViewById(R.id.media_image_id);

            //holder.item_name = (TextView)convertView.findViewById(R.id.media_image_id);

            convertView.setTag(holder); 
        } else{
            holder = (ViewHolder)convertView.getTag();
        }   
        //holder.image.setLayoutParams(new GridView.LayoutParams(100, 100));

         //String item_name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME));

            holder.image.setImageBitmap(photos.get(position).getBitmap());    

            //holder.item_name.setText(item_name);

        return convertView;
    }
}

static class ViewHolder {
   ImageView image;
   TextView item_name;
}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    Cursor cursor = null;
    int image_column_index = 0;
    String[] proj = {MediaStore.Images.Media.DATA};

    String state = Environment.getExternalStorageState();

  if(Environment.MEDIA_MOUNTED.equals(state)){


    cursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,proj,null, null,null);
  }else{
      cursor = managedQuery(MediaStore.Images.Media.INTERNAL_CONTENT_URI,proj,null, null,null);

  }
    cursor.moveToPosition(position);
    image_column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);


    String info = cursor.getString(image_column_index);
    Intent imageviewer  = new Intent(getApplicationContext(), ViewImage.class);
           imageviewer.putExtra("pic_name", info);
           startActivity(imageviewer);

     cursor.close();
}

public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 2;

if (height > reqHeight || width > reqWidth) {
    if (width > height) {
        inSampleSize = Math.round((float)height / (float)reqHeight);
    } else {
        inSampleSize = Math.round((float)width / (float)reqWidth);
    }
}

/*final int REQUIRED_SIZE = 180;

int scale = 1;
if(reqWidth > REQUIRED_SIZE || reqHeight > REQUIRED_SIZE){
    scale = (int)Math.pow(2, (int)Math.round(Math.log(REQUIRED_SIZE/(double)Math.max(reqHeight, reqWidth)) / Math.log(0.5)));
}*/

return inSampleSize;

}

异步任务中的其他方法:

private void loadImages() {
 final Object data = getLastNonConfigurationInstance();
 if(data == null){
     new LoadImagesFromSDCard().execute();
 }else {
     final LoadedImage[] photos = (LoadedImage[])data;
     if(photos.length == 0){

        new LoadImagesFromSDCard().execute();
     }
     for(LoadedImage photo:photos){
         addImage(photo);
    }
 }

}

private void addImage(LoadedImage... value) {

    for(LoadedImage photo: value){
        imageAdapter.addPhotos(photo);  
        imageAdapter.notifyDataSetChanged();
    }

}

我假设我应该先获取根元素,然后再ListViewlogcat错误中获取,但我不知道如何,我似乎无法从文档中找到合适的方法。

PS:我使用的是一个Activity而不是一个ListActivity.

4

1 回答 1

1

异常告诉您您尝试进行无效转换。我的猜测是,您的行布局并不ImageView像您假设的那样简单,而是您的行布局可能有一个包装(和其他视图?!)onRetainNonConfigurationInstance()的父级。当您调用该方法时,您会获得尝试将其转换为. 相反,您应该这样做:LinearlayoutImageViewgetChildAtLinearlayoutImageView

//...
for(int i = 0; i < count; i++){
        LinearLayout parent = (LinearLayout)list.getChildAt(i);
        final ImageView v = (ImageView) parent.findViewById(R.id.the_id_of_the_imageview_from_theRow_layout);
        mylist[i] = new LoadedImage(((BitmapDrawable) v.getDrawable()).getBitmap());
}

注意:该getChildAt方法仅返回可见行的行视图,因此如果您尝试访问View当前不可见的行NullPointerException的从解析所有行Views)。

根据评论编辑

如果我理解你的问题,你看到的行为是正常的。你没有说你最终是如何获得位图的,onRetainNonConfigurationInstance但我的猜测是你只是保存了ListView用户当前可见的行中的图像。当需要使用您提供的图像来恢复适配器时,getLastNonConfigurationInstance()最终只会获得以前可见的图像。如果再次旋转手机,情况会变得更糟,因为很可能横向显示的图像比纵向显示的要少。

我不知道这是否可行,但您可以尝试修改LoadedImage类以存储id来自MediaStore.Images.Media. 当需要保存配置时,停止LoadImagesFromSDCard任务并 从(在适配器中)取消所有图像(删除Bitmap到哪些LoadedImage点),LoadedImages ArrayList除了当前对用户可见的图像。通过 . 从您的适配器 发送照片ArrayListonRetainNonConfigurationInstance

当需要恢复适配器时,将新适配器的照片 ArrayList设置为您返回的照片,并将其放在ListView可见图像的位置(以便用户看到发送的图像)。在getView您的适配器的方法中,当您在关联类中有一个值时,您将放置一个默认图像(如loading... )。开始一个新任务来获取图像并再次解析它们。当您从那里获得时,您将检查适配器中是否存在带有 this的 a 以及它是否有一个集合。如果它不存在(或它没有关联),则加载图像并将其放入适配器中,如果不存在,则图像已存在并移至下一个。nullBitmapLoadedImageLoadImagesFromSDCardidMediaStore.Images.MediaLoadedImageidBitmapBitmap

我不知道上面的解决方案是否有效或是否有效。我建议您修改代码并按需加载图像,而不是在一项大任务中全部加载。

于 2012-05-18T09:11:31.067 回答