如何使用捆绑包在 Android 活动之间传递图像(位图)?

发布于 2024-10-05 19:41:00 字数 283 浏览 2 评论 0原文

假设我有一个活动从图库中选择图像,并将其作为位图检索,就像示例一样: 此处

现在,我想传递此 BitMap 以在 ImageView 中用于另一个活动。我知道捆绑包可以在活动之间传递,但是我如何将此位图存储到捆绑包中?

或者我应该采取另一种方法?

Suppose I have an activity to select an image from the gallery, and retrieve it as a BitMap, just like the example: here

Now, I want to pass this BitMap to be used in an ImageView for another activity. I am aware bundles can be passed between activities, but how would I store this BitMap into the bundle?

or is there another approach I should take?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

小姐丶请自重 2024-10-12 19:41:01

我强烈推荐一种不同的方法。

如果您真的想这样做,这是可能的,但它会消耗大量内存并且速度也很慢。如果您有旧手机和大位图,它可能不起作用。您可以将其作为额外的内容传递,例如 intent.putExtra("data", bitmap)。 Bitmap 实现了 Parcelable,因此您可以将其放在 extra 中。同样,捆绑包也有 putParcelable

如果您想在活动之间传递它,我会将其存储在文件中。这对您来说效率更高,工作量更少。您可以使用 MODE_PRIVATE 在数据文件夹中创建任何其他应用程序无法访问的私人文件。

I would highly recommend a different approach.

It's possible if you REALLY want to do it, but it costs a lot of memory and is also slow. It might not work if you have an older phone and a big bitmap. You could just pass it as an extra, for example intent.putExtra("data", bitmap). A Bitmap implements Parcelable, so you can put it in an extra. Likewise, a bundle has putParcelable.

If you want to pass it inbetween activities, I would store it in a file. That's more efficient, and less work for you. You can create private files in your data folder using MODE_PRIVATE that are not accessible to any other app.

瞄了个咪的 2024-10-12 19:41:01

如果您将其作为 Parcelable 传递,您一定会收到 JAVA BINDER FAILURE 错误。因此,解决方案是这样的:如果位图很小,例如缩略图,则将其作为字节数组传递并构建位图以在下一个活动中显示。例如:

在您的呼叫活动中......

Intent i = new Intent(this, NextActivity.class);
Bitmap b; // your bitmap
ByteArrayOutputStream bs = new ByteArrayOutputStream();
b.compress(Bitmap.CompressFormat.PNG, 50, bs);
i.putExtra("byteArray", bs.toByteArray());
startActivity(i);

以及在您的接收活动中

if(getIntent().hasExtra("byteArray")) {
    ImageView previewThumbnail = new ImageView(this);
    Bitmap b = BitmapFactory.decodeByteArray(
        getIntent().getByteArrayExtra("byteArray"),0,getIntent().getByteArrayExtra("byteArray").length);        
    previewThumbnail.setImageBitmap(b);
}

If you pass it as a Parcelable, you're bound to get a JAVA BINDER FAILURE error. So, the solution is this: If the bitmap is small, like, say, a thumbnail, pass it as a byte array and build the bitmap for display in the next activity. For instance:

in your calling activity...

Intent i = new Intent(this, NextActivity.class);
Bitmap b; // your bitmap
ByteArrayOutputStream bs = new ByteArrayOutputStream();
b.compress(Bitmap.CompressFormat.PNG, 50, bs);
i.putExtra("byteArray", bs.toByteArray());
startActivity(i);

...and in your receiving activity

if(getIntent().hasExtra("byteArray")) {
    ImageView previewThumbnail = new ImageView(this);
    Bitmap b = BitmapFactory.decodeByteArray(
        getIntent().getByteArrayExtra("byteArray"),0,getIntent().getByteArrayExtra("byteArray").length);        
    previewThumbnail.setImageBitmap(b);
}
寄意 2024-10-12 19:41:01

正如 @EboMike 的建议,我将位图保存在应用程序内部存储中名为 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 解码为位图:

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

注意 对 null 和缩放位图进行大量检查犯了。

As suggested by @EboMike I saved the bitmap in a file named myImage in the internal storage of my application not accessible my other apps. Here's the code of that part:

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

Then in the next activity you can decode this file myImage to a bitmap using following code:

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

Note A lot of checking for null and scaling bitmap's is ommited.

双手揣兜 2024-10-12 19:41:01

Activity

在Activities之间传递位图

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

以及在Activity类中

Bitmap bitmap = getIntent().getParcelableExtra("bitmap");

Fragment

在Fragment之间传递位图

SecondFragment fragment = new SecondFragment();
Bundle bundle = new Bundle();
bundle.putParcelable("bitmap", bitmap);
fragment.setArguments(bundle);

在SecondFragment内部接收

Bitmap bitmap = getArguments().getParcelable("bitmap");

传输大位图(压缩位图)

如果您的活页夹事务失败,则意味着您通过将大元素从一个活动传输到另一活动而超出了活页夹事务缓冲区。

因此,在这种情况下,您必须将位图压缩为字节数组,然后在另一个活动中解压缩,就像这样

在 FirstActivity

Intent intent = new Intent(this, SecondActivity.class);

ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPG, 100, stream);
byte[] bytes = stream.toByteArray(); 
intent.putExtra("bitmapbytes",bytes);

在 SecondActivity 中

byte[] bytes = getIntent().getByteArrayExtra("bitmapbytes");
Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);

Activity

To pass a bitmap between Activites

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

And in the Activity class

Bitmap bitmap = getIntent().getParcelableExtra("bitmap");

Fragment

To pass a bitmap between Fragments

SecondFragment fragment = new SecondFragment();
Bundle bundle = new Bundle();
bundle.putParcelable("bitmap", bitmap);
fragment.setArguments(bundle);

To receive inside the SecondFragment

Bitmap bitmap = getArguments().getParcelable("bitmap");

Transferring large bitmap (Compress bitmap)

If you are getting failed binder transaction, this means you are exceeding the binder transaction buffer by transferring large element from one activity to another activity.

So in that case you have to compress the bitmap as an byte's array and then uncompress it in another activity, like this

In the FirstActivity

Intent intent = new Intent(this, SecondActivity.class);

ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPG, 100, stream);
byte[] bytes = stream.toByteArray(); 
intent.putExtra("bitmapbytes",bytes);

And in the SecondActivity

byte[] bytes = getIntent().getByteArrayExtra("bitmapbytes");
Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
无戏配角 2024-10-12 19:41:01

位图是 Parcelable 因此您可以使用 [putExtra(String,Parcelable) 添加][2]方法,但不确定这是最佳实践,如果是大尺寸数据,最好存储在单个位置并从两个活动中使用。

[2]: http://developer.android .com/reference/android/content/Intent.html#putExtra(java.lang.String, android.os.Parcelable)

Bitmap is Parcelable so you can add using [putExtra(String,Parcelable)][2] method, But not sure it is a best practice, If it is large size data it is better to store in a single place and use from both activities.

[2]: http://developer.android.com/reference/android/content/Intent.html#putExtra(java.lang.String, android.os.Parcelable)

何以笙箫默 2024-10-12 19:41:01

在第一个.java中

Intent i = new Intent(this, second.class);
                    i.putExtra("uri",uri);
                    startActivity(i);

在第二个.java中

Bundle bd = getIntent().getExtras();
        Uri uri = bd.getParcelable("uri");
        Log.e("URI", uri.toString());
        try {
            Bitmap bitmap = Media.getBitmap(this.getContentResolver(), uri);
            imageView.setImageBitmap(bitmap);

        } 
        catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

in first.java

Intent i = new Intent(this, second.class);
                    i.putExtra("uri",uri);
                    startActivity(i);

in second.java

Bundle bd = getIntent().getExtras();
        Uri uri = bd.getParcelable("uri");
        Log.e("URI", uri.toString());
        try {
            Bitmap bitmap = Media.getBitmap(this.getContentResolver(), uri);
            imageView.setImageBitmap(bitmap);

        } 
        catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
呆头 2024-10-12 19:41:01

我必须稍微重新缩放位图,以不超过事务绑定器的 1mb 限制。您可以调整 400 屏幕或使其动态,这只是一个示例。
它工作正常,质量也很好。
它也比保存图像然后加载要快得多,但有大小限制。

public void loadNextActivity(){
    Intent confirmBMP = new Intent(this,ConfirmBMPActivity.class);

    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    Bitmap bmp = returnScaledBMP();
    bmp.compress(Bitmap.CompressFormat.JPEG, 100, stream);

    confirmBMP.putExtra("Bitmap",bmp);
    startActivity(confirmBMP);
    finish();

}
public Bitmap returnScaledBMP(){
    Bitmap bmp=null;
    bmp = tempBitmap;
    bmp = createScaledBitmapKeepingAspectRatio(bmp,400);
    return bmp;

使用以下代码恢复 nextActivity 中的 bmp 后:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_confirmBMP);
    Intent intent = getIntent();
    Bitmap bitmap = (Bitmap) intent.getParcelableExtra("Bitmap");

}

我希望我的回答对您有所帮助。
问候

I had to rescale the bitmap a bit to not exceed the 1mb limit of the transaction binder. You can adapt the 400 the your screen or make it dinamic it's just meant to be an example.
It works fine and the quality is nice.
Its also a lot faster then saving the image and loading it after but you have the size limitation.

public void loadNextActivity(){
    Intent confirmBMP = new Intent(this,ConfirmBMPActivity.class);

    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    Bitmap bmp = returnScaledBMP();
    bmp.compress(Bitmap.CompressFormat.JPEG, 100, stream);

    confirmBMP.putExtra("Bitmap",bmp);
    startActivity(confirmBMP);
    finish();

}
public Bitmap returnScaledBMP(){
    Bitmap bmp=null;
    bmp = tempBitmap;
    bmp = createScaledBitmapKeepingAspectRatio(bmp,400);
    return bmp;

}

After you recover the bmp in your nextActivity with the following code:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_confirmBMP);
    Intent intent = getIntent();
    Bitmap bitmap = (Bitmap) intent.getParcelableExtra("Bitmap");

}

I hope my answer was somehow helpfull.
Greetings

小镇女孩 2024-10-12 19:41:01

从您想要意图进入下一个活动的位置编写此代码。

    yourimageView.setDrawingCacheEnabled(true); 
    Drawable drawable = ((ImageView)view).getDrawable(); 
    Bitmap bitmap = imageView.getDrawingCache();
    Intent intent = new Intent(getBaseContext(), NextActivity.class);
    intent.putExtra("Image", imageBitmap);

在NextActivity.class的onCreate函数中

Bitmap hotel_image;
Intent intent = getIntent();
hotel_image= intent.getParcelableExtra("Image");

Write this code from where you want to Intent into next activity.

    yourimageView.setDrawingCacheEnabled(true); 
    Drawable drawable = ((ImageView)view).getDrawable(); 
    Bitmap bitmap = imageView.getDrawingCache();
    Intent intent = new Intent(getBaseContext(), NextActivity.class);
    intent.putExtra("Image", imageBitmap);

In onCreate Function of NextActivity.class

Bitmap hotel_image;
Intent intent = getIntent();
hotel_image= intent.getParcelableExtra("Image");
日暮斜阳 2024-10-12 19:41:01

您可以在不使用像这样的捆绑包的情况下简短地传递图像
这是发送者 .class 文件的代码

Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher;
Intent intent = new Intent();
Intent.setClass(<Sender_Activity>.this, <Receiver_Activity.class);
Intent.putExtra("Bitmap", bitmap);
startActivity(intent);

,这是接收者类文件的代码。

Bitmap bitmap = (Bitmap)this.getIntent().getParcelableExtra("Bitmap");
ImageView viewBitmap = (ImageView)findViewById(R.id.bitmapview);
viewBitmap.setImageBitmap(bitmap);

无需压缩。
就是这样

You can pass image in short without using bundle like this
This is the code of sender .class file

Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher;
Intent intent = new Intent();
Intent.setClass(<Sender_Activity>.this, <Receiver_Activity.class);
Intent.putExtra("Bitmap", bitmap);
startActivity(intent);

and this is receiver class file code.

Bitmap bitmap = (Bitmap)this.getIntent().getParcelableExtra("Bitmap");
ImageView viewBitmap = (ImageView)findViewById(R.id.bitmapview);
viewBitmap.setImageBitmap(bitmap);

No need to compress.
that's it

写给空气的情书 2024-10-12 19:41:01

最好将文件保存在 temp/cache 文件夹中,并像我一样通过意图数据传递文件路径。这是示例代码:

从按钮单击(这里 bitmapFullScreen 是我从 Live Server 收集的位图数据)

Intent intent = new Intent(context, FullscreenActivity.class);
String fPath = CreateTempFile(bitmapFullScreen);
if(!StringUtils.isEmpty(fPath)) {
    intent.putExtra("image", fPath);
    startActivity(intent);
}

在 Temp/Cache 文件夹第二个文件上创建文件的函数

public String CreateTempFile(Bitmap mBitmap) {
    File f3 = new File(Environment.getExternalStorageDirectory() + "/inpaint/");
    if (!f3.exists())
        f3.mkdirs();

    OutputStream outStream = null;
    SimpleDateFormat dateFormatter;
    dateFormatter = new SimpleDateFormat("MMddyyyyhhmmss", Locale.US);
    String FN = Environment.getExternalStorageDirectory() + "/inpaint/" + dateFormatter.format(Calendar.getInstance().getTime()) + ".png";
    File file = new File(FN);
    try {
        outStream = new FileOutputStream(file);
        mBitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream);
        outStream.close();
        return file.getAbsolutePath();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return "";
}

,我们需要该文件

Global var

String FileName = "";

接收 Intent String 数据作为 FilePath在 ImageView 上查看图像
此代码将在 onCreate

ImageView imgUpload = findViewById(R.id.imgUpload);
try {
    if (getIntent().hasExtra("image")) {
        FileName = getIntent().getStringExtra("image");
        Bitmap b = BitmapFactory.decodeFile(FileName);
        imgUpload.setImageBitmap(b);
    }
} catch (Exception ex) {
    Toast.makeText(context, "Error: " + ex.getMessage(), Toast.LENGTH_LONG).show();
}

显示图像后我们需要删除临时文件

@Override
public void onBackPressed() {
    super.onBackPressed();
    try {
        File file = new File(FileName);
        file.delete();
    } catch (Exception ex) {
        Toast.makeText(context, "Error: " + ex.getMessage(), Toast.LENGTH_LONG).show();
    }
}

It's better to save the file in temp/cache folder and pass the file path through intent data as I did it. here is sample code:

from on Button Click (Here bitmapFullScreen is a bitmap data which I have collected from Live Server)

Intent intent = new Intent(context, FullscreenActivity.class);
String fPath = CreateTempFile(bitmapFullScreen);
if(!StringUtils.isEmpty(fPath)) {
    intent.putExtra("image", fPath);
    startActivity(intent);
}

Function to create a File on Temp/Cache folder

public String CreateTempFile(Bitmap mBitmap) {
    File f3 = new File(Environment.getExternalStorageDirectory() + "/inpaint/");
    if (!f3.exists())
        f3.mkdirs();

    OutputStream outStream = null;
    SimpleDateFormat dateFormatter;
    dateFormatter = new SimpleDateFormat("MMddyyyyhhmmss", Locale.US);
    String FN = Environment.getExternalStorageDirectory() + "/inpaint/" + dateFormatter.format(Calendar.getInstance().getTime()) + ".png";
    File file = new File(FN);
    try {
        outStream = new FileOutputStream(file);
        mBitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream);
        outStream.close();
        return file.getAbsolutePath();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return "";
}

2nd File where we need the file

Global var

String FileName = "";

Receive the Intent String data as FilePath to View Image on ImageView
this code will be onCreate

ImageView imgUpload = findViewById(R.id.imgUpload);
try {
    if (getIntent().hasExtra("image")) {
        FileName = getIntent().getStringExtra("image");
        Bitmap b = BitmapFactory.decodeFile(FileName);
        imgUpload.setImageBitmap(b);
    }
} catch (Exception ex) {
    Toast.makeText(context, "Error: " + ex.getMessage(), Toast.LENGTH_LONG).show();
}

After display the Image we need to delete temp file

@Override
public void onBackPressed() {
    super.onBackPressed();
    try {
        File file = new File(FileName);
        file.delete();
    } catch (Exception ex) {
        Toast.makeText(context, "Error: " + ex.getMessage(), Toast.LENGTH_LONG).show();
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文