Làm cách nào tôi có thể truyền đối tượng Bitmap từ hoạt động này sang hoạt động khác


145

Trong hoạt động của mình, tôi tạo một Bitmapđối tượng và sau đó tôi cần khởi chạy một đối tượng khác Activity, Làm thế nào tôi có thể vượt qua Bitmapđối tượng này từ hoạt động phụ (đối tượng sẽ được khởi chạy)?

Câu trả lời:


297

Bitmapthực hiện Parcelable, vì vậy bạn luôn có thể vượt qua nó với mục đích:

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

và lấy nó ở đầu bên kia:

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

84
Nếu bitmap tồn tại dưới dạng tệp hoặc tài nguyên, thì tốt hơn là vượt qua URIhoặc ResourceIDcủa bitmap chứ không phải chính bitmap. Vượt qua toàn bộ bitmap đòi hỏi rất nhiều bộ nhớ. Việc truyền URL đòi hỏi rất ít bộ nhớ và cho phép mỗi hoạt động tải và chia tỷ lệ bitmap khi chúng cần.
slayton

3
Nó không hoạt động với tôi, nhưng cái này thì có: stackoverflow.com/questions/11010386/
Kẻ

1
@slayton làm thế nào để chúng ta truyền hình ảnh dưới dạng URI / ResourceID? thí dụ? cảm ơn!
WantIt

đưa bitmap vào thêm như vậy, không phải là cách tốt nhất, nếu kích thước đối tượng bitmap lớn hơn, bạn sẽ nhận được "java.lang.SecurityException: Không thể tìm thấy ứng dụng cho người gọi android.app.ApplicationThreadProxy ......". cách được đề xuất giống như @slayton nói, bạn phải lưu bitmap trên bộ nhớ ngoài và chỉ truyền URI.
AITAALI_ABDERRAHMANE

1
kích thước tối đa của bitmap có thể được thông qua là gì?
AtifSayings


16

Truyền bitmap dưới dạng parcable trong gói giữa các hoạt động không phải là một ý tưởng tốt vì giới hạn kích thước của Có thể di chuyển (1mb). Bạn có thể lưu trữ bitmap trong một tệp trong bộ nhớ trong và truy xuất bitmap đã lưu trong một số hoạt động. Đây là một số mã mẫu.

Để lưu trữ bitmap trong tệp myImage trong bộ nhớ trong:

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

Sau đó, trong hoạt động tiếp theo, bạn có thể giải mã tệp này myImage thành bitmap bằng mã sau:

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

Lưu ý Rất nhiều kiểm tra null và tỉ lệ bitmap là không phổ biến.


Điều này sẽ không biên dịch - không thể giải quyết phương pháp openFileOutput.
Hawklike

4

Nếu hình ảnh quá lớn và bạn không thể lưu và tải nó vào bộ lưu trữ, bạn nên xem xét chỉ sử dụng tham chiếu tĩnh toàn cục cho bitmap (bên trong hoạt động nhận), sẽ được đặt lại thành null trên onDestory, chỉ khi "isChangingConfigurations" trả về đúng


3

Bởi vì Intent có giới hạn kích thước. Tôi sử dụng đối tượng tĩnh công khai để truyền bitmap từ dịch vụ sang phát sóng ....

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

vượt qua trong dịch vụ của tôi

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 của tôi

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

Nén và gửi Bitmap

Câu trả lời được chấp nhận sẽ sụp đổ khi Bitmapquá lớn. Tôi tin rằng đó là giới hạn 1MB . Các Bitmapphải được nén vào một định dạng file khác nhau như một JPG đại diện bởi một ByteArray, sau đó nó có thể được thông qua một cách an toàn thông qua một Intent.

Thực hiện

Hàm này được chứa trong một luồng riêng biệt bằng cách sử dụng Kotlin Coroutines vì việc Bitmapnén được xâu chuỗi sau khi Bitmapđược tạo từ một url String. Việc Bitmaptạo yêu cầu một luồng riêng biệt để tránh các lỗi Ứng dụng không phản hồi (ANR) .

Khái niệm được sử dụng

  • Ghi chú của Corlinines .
  • Mẫu Tải, Nội dung, Lỗi (LCE) được sử dụng bên dưới. Nếu quan tâm bạn có thể tìm hiểu thêm về nó trong bài nói chuyện và video này .
  • LiveData được sử dụng để trả về dữ liệu. Tôi đã biên soạn tài nguyên LiveData yêu thích của mình trong các ghi chú này .
  • Trong Bước 3 , toBitmap()là một chức năng mở rộng Kotlin yêu cầu thư viện đó được thêm vào các phụ thuộc ứng dụng.

1. Nén Bitmapvào JPG ByteArray sau khi được tạo.

Kho lưu trữ.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. Truyền hình ảnh như ByteArraythông qua một Intent.

Trong mẫu này, nó được chuyển từ Fragment sang Service . Đó là khái niệm tương tự nếu được chia sẻ giữa hai Hoạt động .

Mảnh vỡ

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

3. Chuyển đổi ByteArraytrở lại Bitmap.

Sử dụng.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

Nó có thể muộn nhưng có thể giúp. Trên đoạn hoặc hoạt động đầu tiên, hãy khai báo một lớp ... ví dụ

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

Sau đó, trên lớp thứ hai / đoạn làm điều này ..

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

Hy vọng nó giúp.


1

Tất cả các giải pháp trên không hoạt động với tôi, Gửi bitmap parceableByteArraycũng tạo ra lỗi android.os.TransactionTooLargeException: data parcel size.

Giải pháp

  1. Đã lưu bitmap trong bộ nhớ trong như:
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. và gửi putExtra(String)dưới dạng
Intent intent = new Intent(ActivitySketcher.this,ActivityEditor.class);
intent.putExtra("KEY", saveBitmap(bmp));
startActivity(intent);
  1. và Nhận nó trong hoạt động khác như:
if(getIntent() != null){
  try {
           src = BitmapFactory.decodeStream(openFileInput("myImage"));
       } catch (FileNotFoundException e) {
            e.printStackTrace();
      }

 }


0

Bạn có thể tạo chuyển bitmap. thử cái này....

Trong lớp đầu tiên:

1) Tạo:

private static Bitmap bitmap_transfer;

2) Tạo getter và setter

public static Bitmap getBitmap_transfer() {
    return bitmap_transfer;
}

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

3) Đặt hình ảnh:

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

Sau đó, trong lớp thứ hai:

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

-2

Trong trường hợp của tôi, cách được đề cập ở trên không làm việc cho tôi. Mỗi lần tôi đưa bitmap vào mục đích, hoạt động thứ 2 không bắt đầu. Điều tương tự cũng xảy ra khi tôi truyền bitmap dưới dạng byte [].

Tôi đã theo liên kết này và nó hoạt động như một bùa mê và rất nhanh:

package your.packagename

import android.graphics.Bitmap;

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

trong acitiviy đầu tiên của tôi:

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

và đây là onCreate () của Hoạt động thứ 2 của tôi:

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

Tôi đã thử điều này, đã không làm việc. Tôi đã theo liên kết, và có vẻ như bạn nên sử dụng CommonResources.photoFinishBitmapthay vì Constants.photoFinishBitmap.
Nathan Hutton

Thực hành xấu. Điều gì sẽ xảy ra với trường tĩnh trong lớp Activity trong khi giải trí toàn bộ quá trình (ví dụ: do thay đổi quyền cho ứng dụng trong thời gian chạy)? Câu trả lời là NPE.
Alexander
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.