あるアクティビティから別のアクティビティにビットマップオブジェクトを渡すにはどうすればよいですか


145

私のアクティビティでは、Bitmapオブジェクトを作成してから、別のを起動する必要があります。サブアクティビティ(起動されるもの)からActivityこのBitmapオブジェクトを渡すにはどうすればよいですか?

回答:


297

Bitmapimplements Parcelableなので、いつでも次の目的で渡すことができます。

Intent intent = new Intent(this, NewActivity.class);
intent.putExtra("BitmapImage", bitmap);

もう一方の端でそれを取得します:

Intent intent = getIntent(); 
Bitmap bitmap = (Bitmap) intent.getParcelableExtra("BitmapImage");

84
ビットマップがファイルまたはリソースとして存在する場合、ビットマップ自体ではなくビットマップのURIまたはを渡す方が常に適切ResourceIDです。ビットマップ全体を渡すには、大量のメモリが必要です。URLを渡すために必要なメモリは非常に少なく、各アクティビティは必要に応じてビットマップをロードおよびスケーリングできます。
スレイトン

3
私のために動作しませんが、これは実行します。stackoverflow.com/questions/11010386/...
Houssem

1
@slayton URI / ResourceIDとして画像を渡すにはどうすればよいですか?例?ありがとう!
WantIt

そのようなエクストラにビットマップを配置することはベストプラクティスではありません。ビットマップオブジェクトのサイズが大きい場合、「java.lang.SecurityException:Unable to find app for caller android.app.ApplicationThreadProxy ......」が発生します。推奨される方法は、@ slaytonが言うように、ビットマップを外部ストレージに保存し、URIのみを渡す必要があります。
AITAALI_ABDERRAHMANE 2015

1
渡すことができるビットマップの最大サイズは何ですか?
AtifSayings 2018年

24

実際、ビットマップをParcelableとして渡すと、「JAVA BINDER FAILURE」エラーが発生します。ビットマップをバイト配列として渡し、次のアクティビティで表示するためにビットマップを作成してみてください。

私はここで私のソリューションを共有しました:
バンドルを使用してAndroidアクティビティ間で画像(ビットマップ)をどのように渡しますか?


16

Parceable(1mb)のサイズ制限のため、ビットマップをparceableとしてバンドルしてアクティビティ間で渡すことはお勧めできません。ビットマップを内部ストレージのファイルに保存し、保存したビットマップをいくつかのアクティビティで取得できます。ここにいくつかのサンプルコードがあります。

内部ストレージのファイルmyImageにビットマップを保存するには:

public String createImageFromBitmap(Bitmap bitmap) {
    String fileName = "myImage";//no .png or .jpg needed
    try {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
        FileOutputStream fo = openFileOutput(fileName, Context.MODE_PRIVATE);
        fo.write(bytes.toByteArray());
        // remember close file output
        fo.close();
    } catch (Exception e) {
        e.printStackTrace();
        fileName = null;
    }
    return fileName;
}

次のアクティビティでは、次のコードを使用して、このファイルmyImageをビットマップにデコードできます。

//here context can be anything like getActivity() for fragment, this or MainActivity.this
Bitmap bitmap = BitmapFactory.decodeStream(context.openFileInput("myImage"));

nullのチェックとビットマップのスケーリングの多くは省略されています。


これはコンパイルされません-メソッドを解決できませんopenFileOutput
Hawklike、

4

画像が大きすぎてストレージに保存およびロードできない場合は、ビットマップへのグローバル静的参照(受信アクティビティ内)を使用することを検討する必要があります。これは、「isChangingConfigurations」の場合にのみ、onDestoryでnullにリセットされます。 trueを返します。


3

インテントにはサイズ制限があるため。パブリック静的オブジェクトを使用して、サービスからブロードキャストにビットマップを渡します....

public class ImageBox {
    public static Queue<Bitmap> mQ = new LinkedBlockingQueue<Bitmap>(); 
}

私のサービスを渡す

private void downloadFile(final String url){
        mExecutorService.submit(new Runnable() {
            @Override
            public void run() {
                Bitmap b = BitmapFromURL.getBitmapFromURL(url);
                synchronized (this){
                    TaskCount--;
                }
                Intent i = new Intent(ACTION_ON_GET_IMAGE);
                ImageBox.mQ.offer(b);
                sendBroadcast(i);
                if(TaskCount<=0)stopSelf();
            }
        });
    }

私のBroadcastReceiver

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            LOG.d(TAG, "BroadcastReceiver get broadcast");

            String action = intent.getAction();
            if (DownLoadImageService.ACTION_ON_GET_IMAGE.equals(action)) {
                Bitmap b = ImageBox.mQ.poll();
                if(b==null)return;
                if(mListener!=null)mListener.OnGetImage(b);
            }
        }
    };

2

圧縮して送信 Bitmap

受け入れられた回答Bitmapが大きすぎるとクラッシュします。それは1MBの制限だと思います。Bitmap以下のような別のファイル形式に圧縮されなければならないJPGによって表されるByteArray、それは安全を介して渡すことができますIntent

実装

関数はURLから作成された後に圧縮が連鎖されるため、Kotlinコルーチンを使用して別のスレッドに含まれます。作成は避けるために別のスレッドが必要です(ANR)対応アプリケーションではありませんが、エラーを。BitmapBitmapStringBitmap

使用される概念

  • コトリンコルーチン ノート
  • 読み込んで、コンテンツ、エラー(LCE)パターンが下に使用されています。興味があれば、このトークとビデオでそれについてもっと学ぶことができます。
  • LiveDataはデータを返すために使用されます。私はこれらのノートでお気に入りのLiveDataリソースをまとめました。
  • ステップ3toBitmap()あるKotlin拡張機能ライブラリは、アプリケーションの依存関係に追加することを要求します。

コード

1. 作成後BitmapJPG ByteArrayに圧縮します。

Repository.kt

suspend fun bitmapToByteArray(url: String) = withContext(Dispatchers.IO) {
    MutableLiveData<Lce<ContentResult.ContentBitmap>>().apply {
        postValue(Lce.Loading())
        postValue(Lce.Content(ContentResult.ContentBitmap(
            ByteArrayOutputStream().apply {
                try {                     
                    BitmapFactory.decodeStream(URL(url).openConnection().apply {
                        doInput = true
                        connect()
                    }.getInputStream())
                } catch (e: IOException) {
                   postValue(Lce.Error(ContentResult.ContentBitmap(ByteArray(0), "bitmapToByteArray error or null - ${e.localizedMessage}")))
                   null
                }?.compress(CompressFormat.JPEG, BITMAP_COMPRESSION_QUALITY, this)
           }.toByteArray(), "")))
        }
    }

ViewModel.kt

//Calls bitmapToByteArray from the Repository
private fun bitmapToByteArray(url: String) = liveData {
    emitSource(switchMap(repository.bitmapToByteArray(url)) { lce ->
        when (lce) {
            is Lce.Loading -> liveData {}
            is Lce.Content -> liveData {
                emit(Event(ContentResult.ContentBitmap(lce.packet.image, lce.packet.errorMessage)))
            }
            is Lce.Error -> liveData {
                Crashlytics.log(Log.WARN, LOG_TAG,
                        "bitmapToByteArray error or null - ${lce.packet.errorMessage}")
            }
        }
    })
}

2.をByteArray介して画像を渡しますIntent

このサンプルでは、フラグメントからサービスに渡されます。2つのアクティビティ間で共有する場合も同様です。

Fragment.kt

ContextCompat.startForegroundService(
    context!!,
    Intent(context, AudioService::class.java).apply {
        action = CONTENT_SELECTED_ACTION
        putExtra(CONTENT_SELECTED_BITMAP_KEY, contentPlayer.image)
    })

3.に変換ByteArrayBitmapます。

Utils.kt

fun ByteArray.byteArrayToBitmap(context: Context) =
    run {
        BitmapFactory.decodeByteArray(this, BITMAP_OFFSET, size).run {
            if (this != null) this
            // In case the Bitmap loaded was empty or there is an error I have a default Bitmap to return.
            else AppCompatResources.getDrawable(context, ic_coinverse_48dp)?.toBitmap()
        }
    }

1

遅いかもしれませんが、助けることができます。最初のフラグメントまたはアクティビティでクラスを宣言します...たとえば

   @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        description des = new description();

        if (requestCode == PICK_IMAGE_REQUEST && data != null && data.getData() != null) {
            filePath = data.getData();
            try {
                bitmap = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(), filePath);
                imageView.setImageBitmap(bitmap);
                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
                constan.photoMap = bitmap;
            } catch (IOException e) {
                e.printStackTrace();
            }
       }
    }

public static class constan {
    public static Bitmap photoMap = null;
    public static String namePass = null;
}

次に、2番目のクラス/フラグメントでこれを行います。

Bitmap bm = postFragment.constan.photoMap;
final String itemName = postFragment.constan.namePass;

それが役に立てば幸い。


1

上記の解決策はすべて私にとっては機能しません。ビットマップを送信parceableByteArrayするとエラーが発生しますandroid.os.TransactionTooLargeException: data parcel size

解決

  1. ビットマップを内部ストレージに次のように保存しました:
public String saveBitmap(Bitmap bitmap) {
        String fileName = "ImageName";//no .png or .jpg needed
        try {
            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
            FileOutputStream fo = openFileOutput(fileName, Context.MODE_PRIVATE);
            fo.write(bytes.toByteArray());
            // remember close file output
            fo.close();
        } catch (Exception e) {
            e.printStackTrace();
            fileName = null;
        }
        return fileName;
    }
  1. putExtra(String)として送る
Intent intent = new Intent(ActivitySketcher.this,ActivityEditor.class);
intent.putExtra("KEY", saveBitmap(bmp));
startActivity(intent);
  1. そして他の活動でそれを受け取ります:
if(getIntent() != null){
  try {
           src = BitmapFactory.decodeStream(openFileInput("myImage"));
       } catch (FileNotFoundException e) {
            e.printStackTrace();
      }

 }


0

ビットマップ転送を作成できます。これを試して....

最初のクラスでは:

1)作成:

private static Bitmap bitmap_transfer;

2)ゲッターとセッターを作成する

public static Bitmap getBitmap_transfer() {
    return bitmap_transfer;
}

public static void setBitmap_transfer(Bitmap bitmap_transfer_param) {
    bitmap_transfer = bitmap_transfer_param;
}

3)画像を設定します。

ImageView image = (ImageView) view.findViewById(R.id.image);
image.buildDrawingCache();
setBitmap_transfer(image.getDrawingCache());

次に、2番目のクラスで:

ImageView image2 = (ImageView) view.findViewById(R.id.img2);
imagem2.setImageDrawable(new BitmapDrawable(getResources(), classe1.getBitmap_transfer()));

-2

私の場合、上記の方法ではうまくいきませんでした。ビットマップをインテントに配置するたびに、2番目のアクティビティが開始されませんでした。ビットマップをbyte []として渡したときにも同じことが起こりました。

私はこのリンクをたどると、それは魅力的で非常に速く機能しました:

package your.packagename

import android.graphics.Bitmap;

public class CommonResources { 
      public static Bitmap photoFinishBitmap = null;
}

私の最初の活動で:

Constants.photoFinishBitmap = photoFinishBitmap;
Intent intent = new Intent(mContext, ImageViewerActivity.class);
startActivity(intent);

そして、これが私の2番目のアクティビティのonCreate()です。

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Bitmap photo = Constants.photoFinishBitmap;
    if (photo != null) {
        mViewHolder.imageViewerImage.setImageDrawable(new BitmapDrawable(getResources(), photo));
    }
}

私はこれを試しましたが、うまくいきませんでした。リンクをたどったところ、のCommonResources.photoFinishBitmap代わりに使用する必要があったようですConstants.photoFinishBitmap
Nathan Hutton、

悪い習慣。プロセス全体の再作成中に、アクティビティクラスの静的フィールドで何が起こりますか(たとえば、実行時にアプリの権限が変更されたため)?答えはNPEです。
アレクサンダー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.