Solucionado (ver solução)

Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

Solucionado
(ver solução)
21
respostas

Uso do Bitmap no ImageView

Olá, pessoal.

No meu formulário, é possível tirar uma foto pela câmera e depois atribuir a uma ImageView. Ela aparece na miniatura do formulário utilizando o set visita.setFoto(fotoDaCamera);. Dessa forma, o set está funcionando normalmente ao meu ver.

Contudo, o erro acontece quando tento alterar esse cadastro (dá crash ao abrir o formulário) e parece que o erro é neste comando: campoFoto.setImageBitmap(visita.getFoto());, pois quando tenho um cadastro sem foto, a edição ocorre naturalmente.

No log, não entendi o erro, pois aparece "Parcelable encountered IOException writing serializable object"

Observação: estou utilizando o serializable.

Alguém teria uma luz? Obrigado.

21 respostas

Thiago, tudo bem ?

Qual é o formato que você está salvando essa foto ?

Se for string você vai precisar fazer a conversão dela.

Além disso, se tiver salvando o bitmap, bitmap é uma classe que implementa parcelable e o comportamento entre serializable e parcelable não é muito bom.

Recomendo que você salve o caminho da foto e quando necessário abre o arquivo.

Semelhante com o que é feito no curso

Ah tá. Estou usando bitmap com serializable. Vou mudar e te falo. Obrigado

Fala, Matheus. Parcelable implementado e inicialmente funcionando rsrsrs.

Tiro a foto, salvo o formulário e ela aparece quando eu abro o formulário para edição. Contudo, ao salvar a edição e abrir novamente, a foto fica vazia.

Código se achar melhor: https://github.com/thiagornela/visita

Um método está assim:

protected Visita(Parcel in) {
        foto_familia = (Bitmap) in.readValue(Bitmap.class.getClassLoader());
//restante.....

O outro:

@Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeValue(foto_familia);
//restante.....

Coloquei o Bitmap usando o comando "Value", pois, em um tutorial, vi o cara fazendo essa recomendação.

Já o get e o set estão assim:

public Bitmap getFoto_familia() {
        return foto_familia;
    }

    public void setFoto_familia(Bitmap foto_familia) {
        this.foto_familia = foto_familia;
    }

Acho que tu pode usar writeParcelable no lugar do writeValue e na hora de recuperar readParcelable invés do readValue

Ficou assim: dest.writeParcelable(foto_familia, flags); e foto_familia = in.readParcelable(Bitmap.class.getClassLoader());, mas na segunda edição o ImageView continuou "em branco". aff

Rapaz, fui ler umas coisas agora e me toquei em algo.

O bitmap geralmente ultrapassa os 1MB máximo que o Bundle, que fica dentro da Intent consegue trafegar, por isso deve estar ficando em branco.

Olhando aqui a galera recomenda que você passe apenas uma referencia para ter acesso a esse bitmap do outro lado, como o caminho da foto por exemplo se for local, caso seja web, passar a url.

Rapaz, já estava difícil antes... kkkk.

Não sei o caminho da foto não kkkkk

O código está assim:

public void tirarFoto(View view) {
        Intent intentTirarFoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        startActivityForResult(intentTirarFoto, RESULT_TIRAR_FOTO);
    }

    private void pegaFotoGaleria() {
        Intent intentPegaFoto = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
        startActivityForResult(intentPegaFoto, RESULT_PEGA_FOTO_GALERIA);
    }

    @Override
    protected void onActivityResult(int requestCode, int resulteCode, Intent data) {
        super.onActivityResult(requestCode, resulteCode, data);
        if (requestCode == RESULT_TIRAR_FOTO) {
            if (data != null) {
                Bundle bundle = data.getExtras();
                if (bundle != null) {
                    fotoDaFamilia = (Bitmap) bundle.get("data");
                    campoFotoFamilia.setImageBitmap(fotoDaFamilia);
                }
            }
        } else if (requestCode == RESULT_PEGA_FOTO_GALERIA && resulteCode == RESULT_OK) {
            carregarImagemGaleria(data);
        }
    }

Provavelmente estaria salvando em uma pasta temporária? Ainda estou usando o savedInstanceState. Como está quase finalizado, no decorrer da semana mudarei isso.

               Uri selectedImage = data.getData();
                String[] filePathColumn = { MediaStore.Images.Media.DATA };

                Cursor cursor = getContentResolver().query(selectedImage,
                        filePathColumn, null, null, null);
                cursor.moveToFirst();

                int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                String imgDecodableString = cursor.getString(columnIndex);
                cursor.close();

                imgView.setImageBitmap(BitmapFactory.decodeFile(imgDecodableString));

senão estiver enganado esse código te dá o caminho da foto :)

Vamos lá, Matheus. Força. Preciso de vc para não desistir, cara kkkkkk

Deu NEP. Veja se meu raciocínio está certo, por favor rs

Para utilizar a parte data.getData() do seu código (1ª linha), coloquei Uri selectedImage como atributo da classe. Por quê?

Para eu usá-lo no método que tira a foto ou pega na galeria. Assim:

protected void onActivityResult(int requestCode, int resulteCode, Intent data) {
        super.onActivityResult(requestCode, resulteCode, data);
        if (requestCode == RESULT_TIRAR_FOTO) {
            if (data != null) {
                Bundle bundle = data.getExtras();
                if (bundle != null) {
                    fotoDaFamilia = (Bitmap) bundle.get("data");
                    campoFotoFamilia.setImageBitmap(fotoDaFamilia);
                    this.selectedImage = data.getData(); ///////////////////////////////// USEI ELE AQUI
                }
            }
        } else if (requestCode == RESULT_PEGA_FOTO_GALERIA && resulteCode == RESULT_OK) {
            carregarImagemGaleria(data);
        }
    }

    public void carregarImagemGaleria(Intent data) {
        InputStream stream = null;
        try {
            if (fotoDaFamilia != null) {
                fotoDaFamilia.recycle();
            }
            stream = getContentResolver().openInputStream(data.getData());
            fotoDaFamilia = BitmapFactory.decodeStream(stream);
            this.selectedImage = data.getData();///////////////////////////////// USEI ELE AQUI
            campoFotoFamilia.setImageBitmap(fotoDaFamilia);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

Aí, no método preencheCamposEdicao() que eu coloquei o restante do código:

String[] filePathColumn = { MediaStore.Images.Media.DATA };

        Cursor cursor = getContentResolver().query(selectedImage,
                filePathColumn, null, null, null);
        cursor.moveToFirst();

        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
        String imgDecodableString = cursor.getString(columnIndex);
        cursor.close();

        campoFotoFamilia.setImageBitmap(BitmapFactory.decodeFile(imgDecodableString));

Muita coisa errada?

O que eu te mandei é pra ser utilizado no instante que você pega a foto da galeria, assim você consegue armazenar o caminho relativo da foto


                Uri selectedImage = data.getData();
                String[] filePathColumn = { MediaStore.Images.Media.DATA };

                Cursor cursor = getContentResolver().query(selectedImage,
                        filePathColumn, null, null, null);
                cursor.moveToFirst(); 

                int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                String imgDecodableString = cursor.getString(columnIndex);
                cursor.close(); // aqui voce tem o caminho -> essa string voce precisa armazenar na sua aplicação para que consiga trabalhar com ela sem problemas maiores

                imgView.setImageBitmap(BitmapFactory.decodeFile(imgDecodableString));


Ahhhhh tá kkkk. Funciounou não rsrs. Qdo seleciono a foto na galeria, o ImageView fica em branco. Ficou assim:

public void carregarImagemGaleria(Intent data) {
        InputStream stream = null;
        try {
            if (fotoDaFamilia != null) {
                fotoDaFamilia.recycle();
            }
            stream = getContentResolver().openInputStream(data.getData());
            fotoDaFamilia = BitmapFactory.decodeStream(stream);
            Uri selectedImage = data.getData();
            String[] filePathColumn = { MediaStore.Images.Media.DATA };

            Cursor cursor = getContentResolver().query(selectedImage,
                    filePathColumn, null, null, null);
            cursor.moveToFirst();

            int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
            imgDecodableString = cursor.getString(columnIndex);
            cursor.close(); 

            campoFotoFamilia.setImageBitmap(BitmapFactory.decodeFile(imgDecodableString));

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
solução!

Se tentarmos fazer algo assim então?

   @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);

                if(requestCode == RESULT_PEGA_FOTO_GALERIA && resulteCode == RESULT_OK){
                    Uri selectedImage = intent.getData();

                     Bitmap   bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), selectedImage);
        String caminho =  selectedImage.toString(); // o caminho deve estar aqui
                    imageView.setImageBitmap(bitmap);

                }
        }
    }
}

Deu não. Quando seleciono a foto na galeria, ela aparece no ImageView, mas dá erro ao abrir para edição.

Mas já fiz tanta mudança nesse código que não sei mais nada... se é bagunça mesmo ou outra coisa . Desespero mode on rs

Bom dia, Matheus. Bom? Tem como dar uma olhada direto no código? Pq tá difícil entender essa parte kkkk

Cara, peguei seu código aqui e rodei, fiz um pequena alteração e acredito que esteja funcionando.

Fiz o seguinte:

  • no seu método preencheVisitaFinalizada adicionei o um if para validar se precisa ou não mudar a foto:

      if (fotoDaFamilia != null)
          visita.setFoto_familia(fotoDaFamilia);
  • no seu método preencheCamposEdicao apenas mudei a fonte de onde pegava a foto:

      campoFotoFamilia.setImageBitmap(visita.getFoto_familia());

Está tudo funcionando, testa ai e vê se esse era o resultado que você quer

Rapaz, tu é fera. Funcionou 98%. Qdo tirei uma foto pela câmera, salvou e editei (com a foto aparecendo) e salvei novamente. Perfeitamente.

Mas quando peguei a foto da galeria e salvei o cadastro, na edição deu NEP. Contigo aí funcionou?

Não consegui simular a galeria por estar usando emulador, em tese não devia ter problema algum nisso.

Tu consegue mostrar onde o erro ocorre ?

E em qual momento tem quebrado ?

Depois que faço o cadastro, ele aparece no adapter. O erro dá exatamente quando clico nele para abrir a edição.

2021-01-21 14:11:20.356 28128-28128/com.example.cadastrodevisita E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 48772264)
2021-01-21 14:11:20.358 28128-28128/com.example.cadastrodevisita E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.cadastrodevisita, PID: 28128
    java.lang.RuntimeException: Failure from system
        at android.app.Instrumentation.execStartActivity(Instrumentation.java:1722)
        at android.app.Activity.startActivityForResult(Activity.java:5258)
        at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:675)
        at android.app.Activity.startActivityForResult(Activity.java:5203)
        at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:662)
        at android.app.Activity.startActivity(Activity.java:5587)
        at android.app.Activity.startActivity(Activity.java:5555)
        at com.example.cadastrodevisita.ui.activities.MainActivity.vaiParaEditaVisita(MainActivity.java:75)
        at com.example.cadastrodevisita.ui.activities.MainActivity.access$100(MainActivity.java:23)
        at com.example.cadastrodevisita.ui.activities.MainActivity$2.onItemClick(MainActivity.java:64)
        at android.widget.AdapterView.performItemClick(AdapterView.java:374)
        at android.widget.AbsListView.performItemClick(AbsListView.java:1736)
        at android.widget.AbsListView$PerformClick.run(AbsListView.java:4207)
        at android.widget.AbsListView$7.run(AbsListView.java:6692)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:237)
        at android.app.ActivityThread.main(ActivityThread.java:8167)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
     Caused by: android.os.TransactionTooLargeException: data parcel size 48772264 bytes
        at android.os.BinderProxy.transactNative(Native Method)
        at android.os.BinderProxy.transact(BinderProxy.java:575)
        at android.app.IActivityTaskManager$Stub$Proxy.startActivity(IActivityTaskManager.java:4450)
        at android.app.Instrumentation.execStartActivity(Instrumentation.java:1716)
        at android.app.Activity.startActivityForResult(Activity.java:5258) 
        at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:675) 
        at android.app.Activity.startActivityForResult(Activity.java:5203) 
        at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:662) 
        at android.app.Activity.startActivity(Activity.java:5587) 
        at android.app.Activity.startActivity(Activity.java:5555) 
        at com.example.cadastrodevisita.ui.activities.MainActivity.vaiParaEditaVisita(MainActivity.java:75) 
        at com.example.cadastrodevisita.ui.activities.MainActivity.access$100(MainActivity.java:23) 
        at com.example.cadastrodevisita.ui.activities.MainActivity$2.onItemClick(MainActivity.java:64) 
        at android.widget.AdapterView.performItemClick(AdapterView.java:374) 
        at android.widget.AbsListView.performItemClick(AbsListView.java:1736) 
        at android.widget.AbsListView$PerformClick.run(AbsListView.java:4207) 
        at android.widget.AbsListView$7.run(AbsListView.java:6692) 
        at android.os.Handler.handleCallback(Handler.java:883) 
        at android.os.Handler.dispatchMessage(Handler.java:100) 
        at android.os.Looper.loop(Looper.java:237) 
        at android.app.ActivityThread.main(ActivityThread.java:8167) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100) 
2021-01-21 14:11:20.387 2210-2210/? E/Zygote: isWhitelistProcess - Process is Whitelisted
2021-01-21 14:11:20.388 2210-2210/? E/Zygote: accessInfo : 1
2021-01-21 14:11:20.401 2210-2210/? E/ng.android.loo: Not starting debugger since process cannot load the jdwp agent.
2021-01-21 14:11:20.415 18299-18299/? E/DecorView: mWindow.mActivityCurrentConfig is null
2021-01-21 14:11:20.431 1953-1953/? E/libprocessgroup: set_timerslack_ns write failed: Operation not permitted
2021-01-21 14:11:20.464 1053-1308/? E/InputDispatcher: channel '90d23b0 com.example.cadastrodevisita/com.example.cadastrodevisita.ui.activities.MainActivity (server)' ~ Channel is unrecoverably broken and will be disposed!

Não é problema de null pointer cara, olha o erro: TransactionTooLargeException muito grande a foto.

Como te disse, o bundle não aguenta o valor, você vai precisar saber quando a foto é da galeria, pra poder buscar através do caminho da foto e tem mais, se a pessoa deletar a foto da galeria, seu app também tá passível de quebrar :(

Blz. Vou pesquisar esse tipo de tratamento. Muitíssimo obrigado mesmo, cara.