मैं एक बिटमैप ऑब्जेक्ट को एक गतिविधि से दूसरी गतिविधि में कैसे पारित कर सकता हूं


146

अपनी गतिविधि में, मैं एक Bitmapऑब्जेक्ट बनाता हूं और फिर मुझे एक और लॉन्च करने की आवश्यकता है Activity, मैं इस Bitmapऑब्जेक्ट को उप-गतिविधि (जो लॉन्च होने जा रहा है) से कैसे पारित कर सकता हूं ?

जवाबों:


297

Bitmapऔजार Parcelable, ताकि आप हमेशा इसे इरादे से पास कर सकें:

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

और इसे दूसरे छोर पर पुनः प्राप्त करें:

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

85
बिटमैप फ़ाइल या एक संसाधन के रूप मौजूद है, तो इसके हमेशा पारित करने के लिए बेहतर है URIया ResourceIDबिटमैप बिटमैप ही की और नहीं। पूरे बिटमैप को पास करने के लिए बहुत अधिक मेमोरी की आवश्यकता होती है। URL पास करने के लिए बहुत कम मेमोरी की आवश्यकता होती है और प्रत्येक गतिविधि को बिटमैप को लोड करने और स्केल करने की अनुमति देता है, क्योंकि उन्हें इसकी आवश्यकता होती है।
स्लैटन

3
मेरे लिए काम नहीं करता है, लेकिन यह एक काम करता है: stackoverflow.com/questions/11010386/…
हसबेंड

1
@ सेलेटन हम यूआरआई / रिसोर्सआईडी के रूप में चित्र कैसे पास करते हैं? उदाहरण? धन्यवाद!
वाइट इट

बिटमैप को इस तरह से जोड़ना, सबसे अच्छा अभ्यास नहीं है, अगर बिटमैप ऑब्जेक्ट का आकार बड़ा है, तो आपको "java.lang.SecurityException: caller android.app.ApplicationThreadxroxy ......" का ऐप ढूंढने में असमर्थ है। अनुशंसित तरीका @slayton की तरह है, आपको बाहरी संग्रहण पर बिटमैप को सहेजना होगा और बस यूआरआई पास करना होगा।
AITAALI_ABDERRAHMANE

1
बिटमैप का अधिकतम आकार क्या है जिसे पारित किया जा सकता है?
आतिफसिंग्स

24

वास्तव में, एक बिटमैप को पार्सल के रूप में पारित करने के परिणामस्वरूप "JAVA BINDER FAILURE" त्रुटि होगी। बिटमैप को बाइट सरणी के रूप में पास करने की कोशिश करें और इसे अगली गतिविधि में प्रदर्शन के लिए बनाएं।

मैंने अपना समाधान यहां साझा किया:
आप बंडलों का उपयोग करके एंड्रॉइड गतिविधियों के बीच छवियां (बिटमैप) कैसे पास करते हैं?


17

गतिविधि के बीच बंडल में पैरेसेबल के रूप में बिटमैप को पास करना पारसेबल (1mb) के आकार की सीमा के कारण एक अच्छा विचार नहीं है। आप किसी फ़ाइल में बिटमैप को आंतरिक संग्रहण में संग्रहीत कर सकते हैं और संग्रहीत बिटमैप को कई गतिविधियों में पुनर्प्राप्त कर सकते हैं। यहाँ कुछ नमूना कोड है।

आंतरिक संग्रहण में 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;
}

फिर अगली गतिविधि में आप निम्न कोड का उपयोग करके बिटमैप को इस फ़ाइल को डिकोड कर सकते हैं:

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

नोट बिटमैप के लिए अशक्त और स्केलिंग के लिए बहुत सारी जाँच की जाती है।


यह संकलन नहीं करेगा - विधि का समाधान नहीं कर सकता openFileOutput
हॉक जैसी

4

यदि छवि बहुत बड़ी है और आप इसे सहेज नहीं सकते हैं और इसे स्टोरेज में लोड नहीं कर सकते हैं, तो आपको बिटमैप पर एक वैश्विक स्थिर संदर्भ (प्राप्त गतिविधि के अंदर) का उपयोग करने पर विचार करना चाहिए, जो कि onDestory पर शून्य करने के लिए रीसेट हो जाएगा, केवल तभी जब "ChancConfigurations " सच लौटाता है।


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

माई ब्रॉडकास्टसीवर

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एक अलग फ़ाइल स्वरूप के रूप में एक में संकुचित किया जाना चाहिए जेपीजी एक द्वारा प्रतिनिधित्वByteArray है, तो यह सुरक्षित रूप से एक के माध्यम से पारित किया जा सकता Intent

कार्यान्वयन

कोटलिन कॉरटाइन्स का उपयोग करके फ़ंक्शन को एक अलग थ्रेड में समाहित किया गया है क्योंकि एक यूआरएल से निर्मित Bitmapहोने के बाद संपीड़न जंजीर Bitmapहै StringBitmapनिर्माण से बचने के क्रम में एक अलग थ्रेड की आवश्यकता है आवेदन प्रतिसाद नहीं (ANR) त्रुटियों।

प्रयुक्त अवधारणाओं

  • कोटलिन कॉरटुइन नोट्स
  • लोड हो रहा है, सामग्री, त्रुटि (एलसीई) पैटर्न नीचे किया जाता है। यदि रुचि है तो आप इसके बारे में इस बात और वीडियो में अधिक जान सकते हैं
  • डेटा को वापस करने के लिए LiveData का उपयोग किया जाता है। मैंने अपने पसंदीदा LiveData संसाधन को इन नोटों में संकलित किया है ।
  • में चरण 3 , toBitmap()एक है Kotlin विस्तार समारोह है कि पुस्तकालय की आवश्यकता होती है अनुप्रयोग निर्भरता के लिए जोड़ा जा करने के लिए।

कोड

1. जेपीजी के बनने के बाद उसे संपीड़ित Bitmapकरें । 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

इस नमूने में यह एक फ्रैगमेंट से एक सेवा के लिए पारित किया गया है । दो गतिविधियों के बीच साझा किए जाने पर यह एक ही अवधारणा है

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

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

फिर दूसरी कक्षा / खंड पर यह करें ।।

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

फिर, दूसरी कक्षा में:

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

-2

मेरे मामले में, ऊपर बताए गए तरीके ने मेरे लिए काम नहीं किया। हर बार जब मैंने बिटमैप को इरादे में रखा, तो दूसरी गतिविधि शुरू नहीं हुई। वही हुआ जब मैंने बिटमैप को बाइट के रूप में पारित किया []।

मैंने इस लिंक का अनुसरण किया और इसने बहुत ही तेजी से काम किया और बहुत तेजी से:

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

और यहाँ मेरी दूसरी गतिविधि का हिस्सा है ():

@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
नाथन हटन

बुरा अभ्यास। पूरी प्रक्रिया के मनोरंजन के दौरान गतिविधि वर्ग में स्थैतिक क्षेत्र के साथ क्या होगा (उदाहरण के लिए, रनटाइम में ऐप के लिए बदलती अनुमति के कारण)? इसका उत्तर है NPE।
अलेक्जेंडर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.