كيف يمكنني تمرير كائن صورة نقطية من نشاط إلى آخر

StackOverflow https://stackoverflow.com/questions/2459524

سؤال

في نشاط بلدي, أنا خلق Bitmap وجوه ثم لا تحتاج إلى إطلاق آخر Activity, كيف يمكنني تمرير هذا Bitmap كائن من دون نشاط (واحد والتي سوف يتم إطلاقها)?

هل كانت مفيدة؟

المحلول

والأدوات Bitmap Parcelable، لذلك يمكن أن تمر دائما مع نية:

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

وواسترجاعها على الطرف الآخر:

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

نصائح أخرى

والواقع، ويمر صورة نقطية كما Parcelable سوف يؤدي إلى خطأ "JAVA BINDER فشل". محاولة تمرير نقطية كما صفيف بايت وبناء عليه للعرض في النشاط القادم.

وتشاطرت بلدي الحل هنا:
كيف يمكنك تمرير الصور ( الصور النقطية) بين أنشطة الروبوت باستخدام حزم؟

وPasssing نقطية كما parceable في حزمة وبين النشاط ليست فكرة جيدة بسبب قيود حجم Parceable (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;
}

وبعد ذلك في النشاط التالي الذي يمكن فك هذا myImage الملف إلى صورة نقطية باستخدام التعليمات البرمجية التالية:

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

<قوية> ملاحظة وommited وهناك الكثير من التحقق من وجود باطل ورفع النقطية.

إذا كانت الصورة كبيرة جدا ولا يمكنك حفظ وتحميل ذلك للتخزين، يجب عليك أن تنظر فقط باستخدام مرجعية عالمية ثابتة إلى الصورة النقطية (داخل النشاط المتلقي)، والتي ستكون إعادة لاغية على onDestory، إلا إذا "isChangingConfigurations" عوائد صحيح.

ولأن نية لديها الحد الأقصى لحجم. يمكنني استخدام كائن ثابت العام للقيام تمرير نقطية من خدمة البث ....

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

ضغط وإرسالها Bitmap

الجواب المقبول سوف تحطم عندما Bitmap هو كبير جدا. أعتقد انها 1MB الحد.على Bitmap يجب أن تكون مضغوطة في تنسيق ملف مختلف مثل JPG ممثلة ByteArray, ثم يمكن أن يكون بأمان مرت عبر Intent.

تنفيذ

الدالة الواردة في موضوع مستقل باستخدام Kotlin Coroutines لأن Bitmap ضغط بالسلاسل بعد Bitmap يتم إنشاؤه من رابط String.على Bitmap إنشاء يتطلب موضوع مستقل لتفادي التطبيق لا يستجيب (ANR) أخطاء.

المفاهيم المستخدمة

  • Kotlin Coroutines ملاحظات.
  • على تحميل المحتوى خطأ (LCE) يستخدم نمط أدناه.إذا كنت مهتما يمكنك معرفة المزيد حول هذا الموضوع في هذا الكلام و الفيديو.
  • LiveData يستخدم لإرجاع البيانات.لقد جمعت المفضلة LiveData الموارد في هذه الملاحظات.
  • في الخطوة 3, toBitmap() هو Kotlin وظيفة ملحق تتطلب تلك المكتبة أن تضاف إلى التطبيق التبعيات.

رمز

1.ضغط Bitmap إلى JPG ByteArray بعد أن تم إنشاؤه.

مستودع.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.

في هذه العينة انها مرت من جزء إلى الخدمة.هو نفس المفهوم إذا كان يجري تقاسمها بين اثنين الأنشطة.

شظية.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()
        }
    }

قد يكون متأخرا لكن يمكن أن تساعد. على جزء الأول أو النشاط تفعل يعلن فئة ... على سبيل المثال

   @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) إنشاء:

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

كل الحلول المذكورة أعلاه لا يعمل بالنسبة لي, إرسال النقطية كما 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();
      }

 }


في حالتي، والطريقة المذكورة أعلاه لا يعمل بالنسبة لي. في كل مرة أضع الصورة النقطية في النية، فإن نشاط 2nd لا تبدأ. حدث نفس الشيء عندما مررت الصورة النقطية كما بايت [].

وتابعت هذه صلة وعملت مثل سحر وسريع جدا:

package your.packagename

import android.graphics.Bitmap;

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

وفي بلدي acitiviy 1ST:

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

وهنا هو OnCreate الخاص () من بلادي نشاط 2nd:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Bitmap photo = Constants.photoFinishBitmap;
    if (photo != null) {
        mViewHolder.imageViewerImage.setImageDrawable(new BitmapDrawable(getResources(), photo));
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top