如何将 Bitmap 对象从一个活动传递到另一个活动
Posted
技术标签:
【中文标题】如何将 Bitmap 对象从一个活动传递到另一个活动【英文标题】:How can I pass a Bitmap object from one activity to another 【发布时间】:2011-01-28 09:46:20 【问题描述】:在我的活动中,我创建了一个Bitmap
对象,然后我需要启动另一个Activity
,
如何从子活动(即将启动的活动)中传递这个Bitmap
对象?
【问题讨论】:
【参考方案1】:Bitmap
实现了Parcelable
,因此您始终可以按意图传递它:
Intent intent = new Intent(this, NewActivity.class);
intent.putExtra("BitmapImage", bitmap);
并在另一端检索它:
Intent intent = getIntent();
Bitmap bitmap = (Bitmap) intent.getParcelableExtra("BitmapImage");
【讨论】:
如果位图作为文件或资源存在,最好传递位图的URI
或ResourceID
,而不是位图本身。传递整个位图需要大量内存。传递 URL 只需要很少的内存,并允许每个活动根据需要加载和缩放位图。
不适合我,但这个可以:***.com/questions/11010386/…
@slayton 我们如何将图像作为 URI / ResourceIDs 传递?例子?谢谢!
可以传递的最大位图尺寸是多少?
android.os.TransactionTooLargeException
抛出这个。【参考方案2】:
实际上,将位图作为 Parcelable 传递会导致“JAVA BINDER FAILURE”错误。尝试将位图作为字节数组传递并构建它以在下一个活动中显示。
我在这里分享了我的解决方案:how do you pass images (bitmaps) between android activities using bundles?
【讨论】:
【参考方案3】:由于 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
。【参考方案4】:
压缩并发送Bitmap
当Bitmap
太大时,接受的答案会崩溃。我相信这是 1MB 的限制。 Bitmap
必须被压缩成不同的文件格式,例如由ByteArray
表示的JPG,然后才能通过Intent
安全地传递。
实施
该函数包含在使用 Kotlin Coroutines 的单独线程中,因为 Bitmap
压缩是在从 URL String
创建 Bitmap
之后链接的。 Bitmap
创建需要单独的线程以避免 Application Not Responding (ANR) 错误。
使用的概念
Kotlin 协程 notes. Loading, Content, Error (LCE) 模式在下面使用。如果有兴趣,您可以通过this talk and video了解更多信息。 LiveData 用于返回数据。我在these notes 中编译了我最喜欢的LiveData 资源。 在第 3 步中,toBitmap()
是一个 Kotlin extension function,要求将该库添加到应用依赖项中。
代码
1。创建后将Bitmap
压缩为JPG 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。通过Intent
将图像作为ByteArray
传递。
在此示例中,它从 Fragment 传递到 Service。如果在两个 Activity 之间共享,这是同一个概念。
Fragment.kt
ContextCompat.startForegroundService(
context!!,
Intent(context, Audioservice::class.java).apply
action = CONTENT_SELECTED_ACTION
putExtra(CONTENT_SELECTED_BITMAP_KEY, contentPlayer.image)
)
3。将ByteArray
转换回Bitmap
。
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()
【讨论】:
【参考方案5】:如果图像太大并且您无法将其保存并加载到存储中,您应该考虑只使用对位图的全局静态引用(在接收活动内部),它将在 onDestory 上重置为 null,仅当"isChangingConfigurations" 返回 true。
【讨论】:
【参考方案6】:因为 Intent 有大小限制。 我使用公共静态对象将位图从服务传递到广播 ....
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();
);
我的广播接收器
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);
;
【讨论】:
【参考方案7】:可能会晚,但可以提供帮助。 在第一个片段或活动上声明一个类...例如
@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;
然后在第二个类/片段上执行此操作..
Bitmap bm = postFragment.constan.photoMap;
final String itemName = postFragment.constan.namePass;
希望对你有帮助。
【讨论】:
【参考方案8】:以上所有解决方案都不适合我,以parceableByteArray
发送位图也会产生错误android.os.TransactionTooLargeException: data parcel size
。
解决方案
-
在内部存储中将位图保存为:
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;
-
并以
putExtra(String)
的身份发送
Intent intent = new Intent(ActivitySketcher.this,ActivityEditor.class);
intent.putExtra("KEY", saveBitmap(bmp));
startActivity(intent);
-
并在其他活动中接收它:
if(getIntent() != null)
try
src = BitmapFactory.decodeStream(openFileInput("myImage"));
catch (FileNotFoundException e)
e.printStackTrace();
【讨论】:
【参考方案9】:您可以创建位图传输。试试这个....
第一堂课:
1) 创建:
private static Bitmap bitmap_transfer;
2) 创建getter和setter
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());
那么,在第二节课中:
ImageView image2 = (ImageView) view.findViewById(R.id.img2);
imagem2.setImageDrawable(new BitmapDrawable(getResources(), classe1.getBitmap_transfer()));
【讨论】:
【参考方案10】:就我而言,上述方法对我不起作用。每次我将位图放入意图中时,第二个活动都没有开始。当我将位图作为字节 [] 传递时,也发生了同样的情况。
我关注了这个link,它的运行速度非常快:
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);
这是我的第二个活动的 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
。
不好的做法。在整个过程的重新创建过程中,Activity 类中的静态字段会发生什么(例如,由于在运行时更改应用程序的权限)?答案是 NPE。以上是关于如何将 Bitmap 对象从一个活动传递到另一个活动的主要内容,如果未能解决你的问题,请参考以下文章