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();
    }

}

ListViewエラーから取得する前に最初にルート要素を取得する必要があると想定してlogcatいますが、方法がわかりません。ドキュメントから適切なメソッドを見つけることができないようです。

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を保存するようにクラスを変更してみてください。構成を保存するときが来たら、タスクを 停止し、現在ユーザーに表示されているものを除いて、(アダプター内の) からすべての画像を無効にします (ポイントを削除します)。経由でアダプタから 写真を送信します。idMediaStore.Images.MediaLoadImagesFromSDCardBitmapLoadedImageLoadedImages ArrayList ArrayListonRetainNonConfigurationInstance

アダプターを復元するときは、新しいアダプターの写真 を元に戻したものに設定し、可視画像の位置に配置します (ユーザーが送信された画像を見るようにします)。関連するクラスに の値がある場合、アダプターのメソッドにデフォルトのイメージ ( loading...など) を配置します。新しいタスクを開始して画像を取得し、再度解析します。fromを取得すると、これを含む がアダプターに存在するかどうか、およびセットがあるかどうかを確認します。存在しない場合 (または関連付けられていない場合) は、イメージをロードしてアダプタに配置します。イメージがまだ存在しない場合は、次のイメージに移動します。ArrayListListViewgetViewnullBitmapLoadedImageLoadImagesFromSDCardidMediaStore.Images.MediaLoadedImageidBitmapBitmap

上記の解決策が機能するかどうか、または効率的かどうかはわかりません。大きなタスクですべてをロードするのではなく、コードを変更してオンデマンドで画像をロードすることをお勧めします。

于 2012-05-18T09:11:31.067 に答える