Lib Fresco Para Carregamento de Imagens (com GIFs e WebPs Animados). Material Design Android - Parte 12

Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba grátis conteúdos Android sem precedentes! Você receberá um email de confirmação. Somente depois de confirma-lo é que eu poderei lhe enviar os conteúdos semanais exclusivos. Os artigos em PDF são entregues somente para os inscritos na lista.

Email inválido.
Blog /Android /Lib Fresco Para Carregamento de Imagens (com GIFs e WebPs Animados). Material Design Android - Parte 12

Lib Fresco Para Carregamento de Imagens (com GIFs e WebPs Animados). Material Design Android - Parte 12

Vinícius Thiengo
(6139) (37)
Go-ahead
"O método consciente de tentativa e erro é mais bem-sucedido que o planejamento de um gênio isolado."
Peter Skillman
Prototipagem Android
Capa do curso Prototipagem Profissional de Aplicativos
TítuloAndroid: Prototipagem Profissional de Aplicativos
CategoriasAndroid, Design, Protótipo
AutorVinícius Thiengo
Vídeo aulas186
Tempo15 horas
ExercíciosSim
CertificadoSim
Acessar Curso
Quer aprender a programar para Android? Acesse abaixo o curso gratuito no Blog.
Lendo
TítuloManual de DevOps: como obter agilidade, confiabilidade e segurança em organizações tecnológicas
CategoriaEngenharia de Software
Autor(es)Gene Kim, Jez Humble, John Willis, Patrick Debois
EditoraAlta Books
Edição
Ano2018
Páginas464
Conteúdo Exclusivo
Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba gratuitamente conteúdos Android sem precedentes!
Email inválido

Opa, blz?

Nesse vídeo apresento a lib Fresco para carregamento de imagens no Android. Liberada a pouco pelo Facebook essa lib tem como principal diferencial a administração de bitmaps em cache utilizando uma heap que não é acessada pelo Garbage Collector do Java, mais precisamente a heap ashmem, isso para versões anteriores a API 21, pois segundo o post de apresentação da lib, muitas das partes ineficazes de administração de cache das versões 4.x ou abaixo foram solucionadas a partir da API 21. Essa administração eficiente da memória / cache faz com que a lib Fresco fique menos propícia a gerar um OutOfMemoryError. A lib tem suporte a partir da API 9 e não é uma lib do Material Design, apenas foi abordada nessa série do Blog.

Antes de utilizar a lib Fresco eu estava rodando alguns testes com a lib Glide, que mesmo seguindo o passo-a-passo da documentação não conseguia parar com a série de OutOfMemoryError, isso baixando imagens em torno de 30 a 50 Kb.

Além da administração diferenciada da memória do device para com o uso de imagens, a lib Fresco traz uma série de features como por exemplo o arredondamento de bordas da imagem, a apresentação com a animação de fadeIn (não busquei se é possível fornecer uma animação personalizada, muito provavelmente sim), a aplicação de filtro com cor na imagem e a execução de animações de imagens no formato .GiF e .WEBP. Para trabalhar com a requisição, carregamento e apresentação da imagem a lib utiliza o padrão MVC onde a entidade DraweeView é responsável por realizar a requisição e a apresentação da Imagem (ou imagens, tendo em mente que podem ser difinidas as imagens de placeholder, erro, retentativa e imagens de background) trabalhando como sendo a View do padrão. A interface DraweeHierarchy trabalha como sendo a entidade que renderiza o conteúdo em DraweeView podendo alterar algumas caracteristicas de apresentação, como as bordas arredondadas, sendo assim o Model do padrão. E por fim temos o DraweeController que fica com o trabalho de gerenciar o carregamento da imagem da memória, network, local,... mais precisamente de se comunicar com o Pipeline que realiza todo esse trabalho de cache e load de imagem. No vídeo mostro a utilização das três entidades, muito mais a utilização do DraweeControler e do DraweeView por meio da entidade SimpleDraweeView.

Voltando ao Pipeline, o que ele faz é: obtendo uma requisicão, verificar se na cache de bitmap há a imagem solicitada, essa cache é a heap ashmem quando em versões 4.x ou abaixo, no Android. Caso a imagem esteja na cache de bitmaps, retorne ela sem a necessidade de decodificação, pois na cache de bitmaps as entidades são salvas de forma não comprimidas. Se não houver uma correspondência da imagem na cache de bitmaps o Pipeline vai para a cache de memória, encontrando uma correspondência a entidade é decodificada e enviada ara ser salva na cache de bitmap, e então enviada para ser apresentada no DraweeView. Se mesmo na cache de memória não houver uma correspondência da imagem, então o pipeline verifica a cache de disco, essa é a única das caches que persiste depois que a APP não está sendo mais utilizada, ou seja, foi para o background ou até mesmo foi removida da parte da memória de APPs em execução. Encontrando uma correspondência na cache de disco essa é decodificada, enviada para ser salva na cache de memória, logo após na cache de bitmap e então para ser apresentada na DraweeView. Caso nem mesmo na cache de disco tenha uma correspondência então a imagem é baixada da internet ou acessada em algum local do device (folder assets, raw, sdcard).

Bom é isso, se estiver utilizando qualquer uma das outras libs de carregamento de imagem recomendo que migre para o Fresco que tem suporte a partir da API 9. O carregamento de imagens em sua APP tende a ficar mais confiavel quanto ao não problema com OutOfMemoryError. Leia os links do Fresco e do IOSched que apresento na vídeo e deixo logo abaixo, pois eles vão complementar com segurança o conteúdo do vídeo. Dê muita atenção ao conteúdo do post do IOSched no GitHub, pois nele tem uma maneira / lógica de trabalhar com folders no servidor como se fossem os folders drawable do Android. Algo interessante é como são criadas as cópias de diferentes tamanhos da imagem updada no servidor deles, ao invés de realizar esse processo logo no envio da imagem ao servidor (um user realizando um cadastro com foto, por exemplo), o que é feito é que a imagem é salva e somente depois um script que é chamado pelo "crontab" do linux é que é realizado o processo de replicação da imagem pelos outros folders do servidor, permitindo então que um script de verificação de tamanho de imagem no Andorid consiga baixar as imagens do folder correto no servidor.

O link para download do projeto se entcontra logo abaixo no post.

Para assistir aos outros vídeos da série Material Design no Android, siga a PlayList abaixo:

Material Design no Android

Segue os links apresentados no vídeo:

Página da lib Fresco

Post no Facebook Blog sobre a lib Fresco

Página do IOSched no GitHub apresentando uma lógica de armazenamento de imagens no Servidor para posterior carregamento em APPs Android

Post no Stackoverflow de discussão sobre Picasso Lib, ImageLoader Volley, Glide e Fresco no Android

Vlw

Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba grátis conteúdos Android sem precedentes!
Email inválido

Relacionado

Sliding Tabs Toolbar, Material Design Android - Parte 8Sliding Tabs Toolbar, Material Design Android - Parte 8Android
SwipeRefreshLayout e Snackbar, Material Design Android - Parte 9SwipeRefreshLayout e Snackbar, Material Design Android - Parte 9Android
Utilizando Transitions, Material Design Android - Parte 10Utilizando Transitions, Material Design Android - Parte 10Android
Design Support Library e CollapsingToolbarLayout, Material Design Android - Parte 11Design Support Library e CollapsingToolbarLayout, Material Design Android - Parte 11Android

Compartilhar

Comentários Facebook

Comentários Blog (37)

Para código / script, coloque entre [code] e [/code] para receber marcação especifica.
Forneça seu nome válido.
Forneça seu email válido.
Forneça o comentário.
Enviando, aguarde...
Rafael (1) (0)
22/12/2016
Olá Thiengo, na minha aplicação os dados carregam normalmente em portrait (paginação), mas em landscape não busca novos dados, fica apenas na primeira página.
Poderia me dar alguma sugestão sobre esse problema?
Obrigado
Responder
Vinícius Thiengo (0) (0)
24/12/2016
Rafael, tudo bem?

Esse comportamento ainda não tinha visto. Se possível, verifique se nos logs do Android Studio está sendo printado alguma informação de erro ou warning.

Assim será possível saber o porquê disso acontecer. Abraço.
Responder
Rafael (1) (0)
26/12/2016
Obrigado por responder, no log não há erro, meu código está assim:
public class Categorias extends AppCompatActivity implements Transaction {
    private static final String TAG = "LOG";
    private Toolbar mToolbar;
    private RecyclerView mRecyclerView;
    private List<Image> mList;
    private ProgressBar mPbLoad;
    SwipeRefreshLayout mSwipeRefreshLayout;
    private boolean isLastItem;
    private String ncat;
    private AdView mAdView;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_categories);

        mAdView = (AdView) findViewById(R.id.adView);
        mAdView.loadAd(new AdRequest.Builder().build());

        mToolbar = (Toolbar) findViewById(R.id.tb_main);
        assert mToolbar != null;
        mToolbar.setTitle(R.string.app_name);

        setSupportActionBar(mToolbar);

        if(getSupportActionBar() != null){
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        }
        getSupportActionBar().setHomeButtonEnabled(false);
        if(savedInstanceState != null){
            mList = savedInstanceState.getParcelableArrayList("mListAux");
        }
        else{
            mList = new ArrayList<>();
        }

        mPbLoad = (ProgressBar) findViewById(R.id.pb_load);

        mRecyclerView = (RecyclerView) findViewById(R.id.rv_list);
        assert mRecyclerView != null;
        mRecyclerView.setHasFixedSize(true);
        if(isTablet(Categorias.this) && isOrientation(Categorias.this)) {

            mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);

                    StaggeredGridLayoutManager llm = (StaggeredGridLayoutManager) mRecyclerView.getLayoutManager();
                    int[] aux = llm.findLastCompletelyVisibleItemPositions(null);
                    int max = -1;
                    for (int anAux : aux) {
                        max = anAux > max ? anAux : max;
                    }

                    if (!isLastItem
                            && mList.size() == max + 1
                            && (mSwipeRefreshLayout == null || !mSwipeRefreshLayout.isRefreshing())) {
                        NetworkConnection.getInstance(Categorias.this).execute(Categorias.this, Categorias.class.getName());
                    }
                }
            });

            StaggeredGridLayoutManager llm = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
            mRecyclerView.setLayoutManager(llm);
        }else{
            mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);

                    LinearLayoutManager llm = (LinearLayoutManager) mRecyclerView.getLayoutManager();

                    if (!isLastItem
                            && mList.size() == llm.findLastCompletelyVisibleItemPosition() + 1
                            && (mSwipeRefreshLayout == null || !mSwipeRefreshLayout.isRefreshing())) {
                        NetworkConnection.getInstance(Categorias.this).execute(Categorias.this, Categorias.class.getName());
                    }
                }
            });

            LinearLayoutManager llm = new LinearLayoutManager( this );
            llm.setOrientation(LinearLayoutManager.VERTICAL);
            mRecyclerView.setLayoutManager(llm);
        }


        ImageAdapter adapter = new ImageAdapter(this, mList);
        mRecyclerView.setAdapter(adapter);

        hendleSearch( getIntent() );
        verifica_conexao();
    }

    private static boolean isTablet(Context c) {
        return (c.getResources().getConfiguration().screenLayout & 15) >= 3;
    }
    private static boolean isOrientation(Context c) {
        return c.getResources().getConfiguration().orientation == 2;
    }

    private void verifica_conexao(){
        if (!Util.verifyConnection(this)) {
            Toast.makeText(this, R.string.message_no_internet_connection, Toast.LENGTH_LONG).show();
        }

    }

    @Override
    protected void onNewIntent(Intent intent) {
        setIntent(intent);
        hendleSearch(intent);
    }

    private void hendleSearch(Intent intent){
        Bundle bundle = intent.getExtras();
        String q = bundle.getString("nCategoria");
        String nomeCat = bundle.getString("tituloCategoria");
        this.ncat = q;
        mToolbar.setSubtitle(nomeCat);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        outState.putParcelableArrayList("mListAux", (ArrayList<Image>) mList);
        super.onSaveInstanceState(outState);
    }

    @Override
    public void onStop() {
        super.onStop();
        NetworkConnection.getInstance(this).getRequestQueue().cancelAll(Categorias.class.getName());
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        SearchView searchView;
        getMenuInflater().inflate(R.menu.menu_image_activity, menu);
        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        MenuItem item = menu.findItem(R.id.action_searchable_activity_c);

        if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ){
            searchView = (SearchView) item.getActionView();
        }
        else{
            searchView = (SearchView) MenuItemCompat.getActionView(item);        }

        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        searchView.setQueryHint(getResources().getString(R.string.search_hint));

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.button_favorite:
                startActivity(new Intent(this, Favoritos.class));
                break;

            default:
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onResume() {
        super.onResume();
        if (mAdView != null) {
            mAdView.resume();
        }
        if(mList == null || mList.size() == 0){
            callVolleyRequest();
        }
    }

    private void callVolleyRequest(){
        NetworkConnection.getInstance(this).execute(this, Categorias.class.getName());
    }


    // NETWORK
    @Override
    public WrapObjToNetwork doBefore() {
        if( Util.verifyConnection(Categorias.this)){
            mPbLoad.setVisibility((mSwipeRefreshLayout != null && mSwipeRefreshLayout.isRefreshing()) ? View.GONE : View.VISIBLE);

            Image image = new Image();
            image.setCat(Integer.parseInt(this.ncat));

            if( mList != null && mList.size() > 0 ){
                image.setId(mSwipeRefreshLayout != null && mSwipeRefreshLayout.isRefreshing() ? mList.get(0).getId() : mList.get(mList.size() - 3).getId());
                image.setPg(mList.get(mList.size()-1).getPg());
            }

            return( new WrapObjToNetwork(image, "get-images", (mSwipeRefreshLayout != null && mSwipeRefreshLayout.isRefreshing()) ) );
        }
        return null;
    }

    @Override
    public void doAfter(JSONArray jsonArray) {
        mPbLoad.setVisibility(View.GONE );

        if( jsonArray != null ){
            ImageAdapter adapter = (ImageAdapter) mRecyclerView.getAdapter();
            Gson gson = new Gson();
            int auxPosition = 0;

            if( mSwipeRefreshLayout != null && mSwipeRefreshLayout.isRefreshing() ){
                mSwipeRefreshLayout.setRefreshing(false);
                auxPosition = 1;
            }

            try{
                for(int i = 0, tamI = jsonArray.length(); i < tamI; i++){
                    int position;
                    Image image = gson.fromJson( jsonArray.getJSONObject( i ).toString(), Image.class );
                    if (auxPosition == 0) {
                        position = this.mList.size();
                    } else {
                        position = 0;
                    }
                    adapter.addListItem(image, position);

                    if( auxPosition == 1 ){
                        mRecyclerView.getLayoutManager().smoothScrollToPosition(mRecyclerView, null, position);
                    }
                }

                if( jsonArray.length() == 0 && auxPosition == 0 ){
                    isLastItem = true;
                    Log.i("fim da lista", String.valueOf(true));
                }

            }
            catch(JSONException e){
                Log.i(TAG, "doAfter(): "+e.getMessage());
            }
        }
        else{
            Toast.makeText(this, R.string.error_new_refresh, Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onPause() {
        if (mAdView != null) {
            mAdView.pause();
        }
        super.onPause();
    }

    @Override
    public void onDestroy() {
        if (mAdView != null) {
            mAdView.destroy();
        }
        super.onDestroy();
    }

}
Responder
Vinícius Thiengo (0) (0)
26/12/2016
Rafael, verifique se quando em Landscape se o condicional do isTablet() é que e aceito, digo, a lógica dentro dele é que é a utilizada.

Utilize um Log.i() para verificar caso não esteja trivial.

Aparentemente a lógica de negócio dentro desse condicional para carregar novos itens está errada, ou seja, ela não ativa o carregamento de itens.

Não vejo necessidade de ter lógicas distintas para diferentes telas e orientações de tela, mas caso em seu domínio do problema seja realmente preciso, corrija a lógica do primeiro condicional que está logo depois de:

mRecyclerView.setHasFixedSize(true);

Não deixe de verificar se utilizando somente a condicional do "else" se funciona sem problemas.

Pode ser o "max + 1" o problema no primeiro condicional. Veja como corrigir isso. Abraço.
Responder
Lucas Cunha (1) (0)
08/11/2016
Boa noite
Primeiramente gostaria de agradecer pelo trabalho que vem fazendo, estou me desenvolvendo através dessas videos aulas que você faz, muito obrigado!!

Estou com um pequeno problema, não estou conseguindo tirar o Gif e deixar a imagem do carro, eu tentei implementar aquele parte "ivCar.setIUri (uri);" como falou mas não estou conseguindo.

Sou um pouco novato em Java e acho que estou esquecendo de algo, tentei fazer de algumas formas aqui, mas sem sucesso.
Se possível, poderia me ajudar ?
Responder
Vinícius Thiengo (1) (0)
10/11/2016
Lucas, tudo bem?

Show de bola que curti o conteúdo do Blog / canal. Mas vamos ao problema.

Está conferindo como está chegando a URI (a String) para carregamento junto ao Fresco?

Pergunto isso, pois já vi problemas similares antes e era o URL da imagem que não estava correta.

Se possível, print as URLs logo antes de tentar coloca-las para serem carregadas pelo Fresco. Utilize o Log.i() para isso. Depois copie a url que aparecer e tente abri-la no navegador, isso se a imagem estiver localizada remotamente.

Caso esteja local, tente somente verificar se esse arquivo é acessível por meio de um código similar ao abaixo:

File file = new File(filePath);
if(file.exists()){ Log.i(?Log?, ?Imagem ?+filePath+" existe") }
else{ Log.i(?Log?, ?Imagem ?+filePath+" NÃO existe") }

Se abrir sem problemas, volte aqui para trabalharmos outra hipótese. Caso não abra, local ou remotamente, corrija o uri da imagem.

Abraço.
Responder
Lucas Cunha (1) (0)
11/11/2016
Tudo certo e ae?

Na verdade estou com o mesmo problema que o Gabriel Souza, se eu colocar Uri uri = Uri.parse("http://dominio.com.br/android/glide/w1185/imagem.jpg "); da certo, mas vai trazer uma única imagem para todos cardview, e não a que o usuario clicou, e também quero que identifique e pegue o tamanho ideal da tela (w395, w593, w790, w1185).

Entendeu? =/
Responder
Vinícius Thiengo (0) (0)
11/11/2016
Lucas, sim. Se não me engano o código do projeto já faz isso, digo, obtém a melhor imagem de acordo com a dependência de pixels (DP) suportada pelo device.

Veja no link abaixo, a partir da linha 135, a busca do width correto para então obter a imagem ideal para o device:

https://github.com/viniciusthiengo/tc-material-design/blob/master/app/src/main/java/br/com/thiengo/tcmaterialdesign/adapters/CarAdapter.java

A obtenção da imagem está nessa classe: https://github.com/viniciusthiengo/tc-material-design/blob/master/app/src/main/java/br/com/thiengo/tcmaterialdesign/extras/DataUrl.java

Mais precisamente no método getUrlCustom().

O uri http://dominio.com.br/android/glide/w1185/imagem.jpg seria um teste, na verdade você utilizará a uri dinâmica que vem de seu servidor, cada imagem tem a sua.

Veja se seu código está utilizando o mesmo modelo de código dos links acima. Abraço.
Responder
03/11/2016
+Thiengo Calopsita O meu SimpleDraweeView não carrega uri quando ela esta concatenada assim:

Uri uri =Uri.parse("http://teste.com/galeria/ "+teste.get(position)+"/"+list_test.get(position)+"/1.jpg");
Porém se eu colocar a uri assim: Uri uri =Uri.parse("http://teste.com/galeria/ teste/diretorio/1.jpg");
ele funciona, mesmo sendo o mesmo conteúdo das duas strings. Alguma dica do que pode ser?
Responder
Vinícius Thiengo (0) (0)
05/11/2016
Gabriel, tudo bem?

Print com o Log.i() do Android o conteúdo de teste.get(position) e de list_test.get(position) para ter certeza que todo esse conteúdo na construção da String de uri constrói realmente a uri esperada.

Aparentemente o problema está em algum (ou ambos) dessas duas invocações.

Abraço.
Responder
14/09/2015
Ola Thiengo, comecei a utilizar a lib fresco e gostaria de saber a forma correta para utilizar a uri de uma imagem salva internamente no android. Por exemplo: salvei o array de byte de uma imagem com: fos = context.openFileOutput(idAttraction.toString(), Context.MODE_PRIVATE);
            fos.write(encodeByte);

depois tenho utilizar ela no fresco pegando a uri mas não encontra a imagem:
Uri uri = new Uri.Builder()
                .scheme(UriUtil.LOCAL_FILE_SCHEME)
                .path(mContext.getFilesDir() + "/" + mAttractionsList.get(position).getIdServer())
                .build();
Responder
Vinícius Thiengo (0) (0)
17/09/2015
Fala Pedro, blz?
Conseguiu utilizar a imagem apenas com um ImageView? Somente para saber se o problema é com o Fresco, pois aparentemente o path fornecido está errado. Suas constantes, tem algum com o Environment: Environment.getExternalStoragePublicDirectory()? Abraço
Responder
henrique miller (2) (0)
01/07/2015
boa tarde thiengo, queria saber se tem alguma lib para manipular tempo, pois tenho o date do objeto quando ele foi criado, e queria colocar em uma listView tipo o tempo que ja decorreu desde a criação, por exemplo: 30min, 1 sem, 10 sem. tipo como ocorrer no facebook, instagran e outros. ^^ e parabens pelas aulas. muito boas.
Responder
Vinícius Thiengo (0) (0)
02/07/2015
Fala Henrique, blz?
Não sei se tem uma lib para isso, pode verificar nesse link (https://android-arsenal.com/search?q=time ) se há algo assim. Porém vejo esse como um script que pode ser criado sem mta dor de cabeça, basta salvar o time em que houve a ação (pode utilizar o System.currentTimeInMillis()), depois em tempo de execução é trabalhar com divisão e resto (%) para definir a maior unidade (1 segundo, 20 minutos, 2 horas, ...). Abraço
Responder
Gabriel (2) (0)
29/06/2015
Ola Thiengo, blz?
eu gostaria de saber se tem como usar uma gif local ( da minha drawable) deixando de lado a gif da web. é possível?
abraço.
Responder
Vinícius Thiengo (1) (0)
29/06/2015
Fala Gabriel, blz sim.
É possível sim, somente coloque a imagen nos folders drawable e carregue via ressource. Abraço
Responder
henrique miller (1) (0)
17/06/2015
Boa tarde Thiengo, você tem alguma aula que fala sobre imageView redonda?
Responder
Vinícius Thiengo (0) (0)
18/06/2015
Fala Henrique, blz?
Não tenho um vídeo especifico sobre isso, mas a lib Fresco faz isso com uma linha de código. Depois de ter vinculado a lib no projeto, coloca o seguinte atributo / valor no xml do SimpleDraweeView (pode utilizar como ImageView):

fresco:roundAsCircle="true"

A imagem deve ficar circular. Ve se consegue ai. Qualquer coisa volte ae. Abraço
Responder
Henrique Miller (1) (0)
18/06/2015
Desculpa se não entendi ^^, estou usando o com.facebook.widget.ProfilePictureView para carregar as imagens do profile do usuário. como faço pra mudar pro fresco -> simpleDraweeView pra utilizar a imagem circular? vlw
Responder
Vinícius Thiengo (0) (0)
19/06/2015
Henrique, o Facebook tb lhe permite acessar a url da imagem do user (https://graph.facebook.com/vinicius.abolarithiengo/picture ), com isso vc apenas coloca no SimpleDreweeView como no vídeo e arredonda com fresco:roundAsCircle="true"

Somente certifique-se se essa é mesmo a url para baixar a imagem com o id do user, pois o Facebook agora retorna o id do user na APP e não geral no Facebook (o que seria um para todos). Testei no navegador e foi sem problemas. Abraço
Responder
henrique (1) (0)
24/06/2015
thiengo, mais uma vez parabens pelas aulas ^^
thiengo comecei a usar a lib fresco pra fazer  a imagem circular como vc tinha falado na resposta anterior. troquei o profilePictureView do facebook pelo simpleDraweeView. o problema é que a qualidade da imagem que vem do facebook para o simpleDraweeView esta muito ruim. comparando com a profilePictureView do facebook que size eh normal. desculpa ai rsrsrsr pelas perguntas.
Responder
Vinícius Thiengo (0) (0)
25/06/2015
Fala Henrique, blz?
Faça o seguinte, coloque a imagem no profilePictureView e então retire dela o Bitmap (mt provavelmente é possível se ela extend a view ImageView). Com o Bitmap em fora do profilePictureView ai é somente coloca-lo no simpleDraweeView. Provavelmente vc terá de colocar o profilePictureView na tela, porém pode escondelo com setVisibility( View.INVISIBLE ), não coloque DONE, pois pode ser que ele não carregue. Essa gambiarra deve funcionar. Dê uma olhada na resposta certa desse link (http://stackoverflow.com/questions/8306623/get-bitmap-attached-to-imageview ) para ver como obter um bitmap de um imageView. Abraço
Responder
Wesley (1) (0)
08/07/2015
Fala Thiengo e Henrique, blz? Aproveitando o comentário de vocês, gostaria de tirar uma dúvida relacionada. Thiengo, estou fazendo exatamente como orientou o Henrique, porém, meu método está salvando a imagem do ProfilePictureView (aquele avatar default do facebook). Como faço pra salvar a imagem somente após ela ter carregado no objeto?
Responder
Vinícius Thiengo (0) (0)
10/07/2015
Fala Wesley, blz sim.
Está salvando a imagem no SDCard? Esse objeto é um bitmap no Java code ou um ImageView no XML? Não entendi mt bem a dúvida. Foi mal. Abraço
Responder
Wesley (1) (0)
13/07/2015
Então, eu estou utilizando o ProfilePictureView do facebook. Então faço o seguinte: uso os métodos
buildDrawingCache() e getDrawingCache() do ProfilePictureView, nesse momento eu tenho a imagem na minha variável bitmap. Em seguida utilizo um método que criei para salvar a imagem na memória interna do aparelho e ele salva, porém não salva a foto do usuário logado, salva aquela imagem padrão do ProfilePictureView. É como se ele estivesse salvando antes da imagem acabar de carregar. Consegui ser mais claro ou ainda está confuso? Muito obrigado.
Responder
Vinícius Thiengo (0) (0)
14/07/2015
Ok, não sei se já está fazendo assim, mas tente aguardar a imagem ser apresentada no ProfilePictureView e então acessar o Bitmap desse ProfilePictureView. Para obter o Bitmap do ProfilePictureView tente esse script (http://stackoverflow.com/a/14537962/2578331 ). Abraço
Responder
Wesley (1) (0)
14/07/2015
Fala Thiengo, blz?
Cara, então... o problema é como aguardar essa imagem ser carregada. Eu ja havia conseguido fazer através do click de um botão, mas isso não é viável. Então fiz o seguinte, aproveitei esse código do link que me passou e implementei isso no onDestroy() da activity, pois nele é bem provável que a imagem ja foi carregada completamente. Sei que não é a melhor forma, mas foi dessa forma que consegui. Obrigado.
Responder
Vinícius Thiengo (0) (0)
15/07/2015
Se funcionou, blz. Dei uma olhada nos listeners do ProfilePictureView e não encontrei um para imagem carregada, logo essa solução do onDestroy() parece ser sim viável, tente em outros métodos, como o onStop(). Abraço
Responder
Wesley (1) (0)
15/07/2015
Ótimo Thiengo, blz! Valeu pelas dicas ai. Grande abraço.
Responder
Ricardo (1) (0)
16/06/2015
Fala Thiengo, deu certo .
Cara outra coisa a primeira vez que carrega da fade nas imagens , porem quando estou no ultimo item da lista e subo o scroll novamente ele parece que recarrega as imagens tudo novamente como que tiro esse fade , como as imagens fica em cache não deveria sumir .
Responder
Vinícius Thiengo (0) (0)
16/06/2015
Ricardo, vou assumir que está utilizando o Fresco. O que pode fazer é o seguinte, nos objetos da lista que é carregada no adapter do RecyclerView vc pode adicionar uma variável que trabalhará como sendo uma flag, pode ser um boolean. Logo no método onBindViewHolder() o script verifica se essa flag é true, se não for então pode carregar a imagem com o fade sem alteração, pois isso indica que é a primeira vez que ela é carregada, porém logo nessa parte de carregamento o script deve alterar a flag para true. Na próxima vez que esse item passar no onBindViewHolder() a flag será true e então a outra parte do script é executada, no caso a parte onde em tempo de execução seu script vai alterar o Fade animation duration para esse item / imagem para 0. Logo ele não terá fade algum, carregará instantâneo.

Nessa página do Fresco (http://frescolib.org/docs/using-drawees-code.html#_ ) vc consegue visualizar como alterar o duration no Java API. Não crie outro hierarchy, utilize o já existente em seu DraweeView (view.getHierarchy()), pois criar um outro hierarchy é um processo pesado com a lib Fresco. Abraço
Responder
Ricardo (1) (0)
16/06/2015
Você quis dizer assim  que carregar o objeto que sera recebido terá uma variável exemplo loadImage ela esta false entao apos executar o carregamento abaixo seto  para true a primeira vez ?Quando passar novamente estara true entao nao faz nada isso?

if(!loadImage)
{Uri uri = Uri.parse(DataUrl.getUrlCustom( mList.get(position).getUrlPhoto(), w )  );
        DraweeController dc = Fresco.newDraweeControllerBuilder()
                .setUri( uri )
                .setTapToRetryEnabled(true)
                .setControllerListener( listener )
                .setOldController( myViewHolder.ivCar.getController() )
                .build();
}
Responder
Vinícius Thiengo (0) (0)
17/06/2015
Quase isso, na verdade essa variavel loadImage deve ser um atributo dos da classe dos objetos que está na lista sendo apresentada no RecyclerView. Quando verificado que esse atributo ainda é false, então significa que esse item ainda não passou na tela do device, logo ele vai passar a primeira vez com o fade. Nas próximas vezes o atributo estará true, a chamada para view.getHierarchy().setFadeDuration(0) será com 0. O DraweeControler fica fora de todos os condicionais, ele não entra nessa lógica e continua sendo carregado dentro do SimpleDraweeView com o atributo sendo true ou false, não há modificação nele. O que ficará dentro dos condicionais será:

if( !obj.getLoadedImage() ){
view.getHierarchy().setFadeDuration(800)
}
else{
view.getHierarchy().setFadeDuration(0)
}
Responder
Ricardo (1) (0)
17/06/2015
Fala Thiengo, então mesmo dessa forma que você falou parece que a imagem não fica no cache,e carrega novamente .
Responder
Vinícius Thiengo (0) (0)
17/06/2015
Ele está dando o fade novamente? Se sim, provavelmente esqueceu de atualizar o atributo loadedImage do objeto atual. Dentro dos condicionais que enviei acabei no os colocando, seria assim:

if( !obj.getLoadedImage() ){
    view.getHierarchy().setFadeDuration(800)
    obj.setLoadedImage( true );
}
else{
    view.getHierarchy().setFadeDuration(0)
}
Responder
Ricardo (1) (0)
15/06/2015
Muito bom, Thiengo no meu app sera carregado sempre a mesma imagem para todos devices ? Como que eu faço ?
Tanto porque ele captura a foto da câmera e envia para o servidor depois pode ser vista para todos os pessoas.
Responder
Vinícius Thiengo (0) (0)
16/06/2015
Fala Ricardo, blz?
No servidor vc salva a imagem em algum diretório que vc definiu para essa ação. Então no banco de dados vc salva apenas o nome da imagem, o caminho com diretórios vc terá de ter já definido em scripts em seu servidor. Depois é somente devolver aos users de sua APP o caminho completo de acesso a imagem em seu servidor, assim permitindo que libs de download de imagem realizem o trabalho pesado (como a lib Fresco do vídeo acima). Porém leia esse post (https://github.com/google/iosched/blob/master/doc/IMAGES.md ), para saber como realmente deve ser replicada a imagem quando no servidor. Era isso? Abraço
Responder