Solucionado (ver solução)
Solucionado
(ver solução)
16
respostas

swip refresh

ola, gostaria de saber porque que quando arrasto a tela para baixo, o swipe refresh aparece, muda de cor, gira. Mas, não atualiza a lista.

no projeto criei um fragment para receber a resposta do json. Porém, para poder atualizar a lista inserir esse swiperefresh para poder atualizar. porém, ele faz o que eu disse mas não atualiza.

package br.com.cadastroDeAluno;


import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;

import java.util.List;

import br.com.cadastroDeAluno.adapter.MediaDasNotasAdapter;
import br.com.cadastroDeAluno.dao.AlunoDAO;
import br.com.cadastroDeAluno.modelo.MediaDasNotas;
import br.com.cadastroDeAluno.tasks.EnviaAlunosTask;


/**
 * A simple {@link Fragment} subclass.
 */
public class ListarMediasFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {

    private ListView listaDasMediaAlunos;
    private View viewMedia;

    private SwipeRefreshLayout mSwipeRefreshLayout;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        setHasOptionsMenu(true); //mostra o menu no fragment

        viewMedia = inflater.inflate(R.layout.fragment_listar_medias, container, false);
        listaDasMediaAlunos = (ListView) viewMedia.findViewById(R.id.lista_mediaDasNotas);
        mSwipeRefreshLayout = (SwipeRefreshLayout) viewMedia.findViewById(R.id.swipeContainer);
        listaDasMediaAlunos.setEmptyView(viewMedia.findViewById(R.id.list_media_vazia));//caso a lista de media esteja fazia

        mSwipeRefreshLayout.setColorSchemeResources(R.color.color_vermelho,
                R.color.color_verde,
                R.color.color_azul,
                R.color.color_laranja);
        // Listenerをセット
        mSwipeRefreshLayout.setOnRefreshListener(this);

        registerForContextMenu(listaDasMediaAlunos);
        return viewMedia;
    }


    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.menu_lista_media, menu);
        super.onCreateOptionsMenu(menu, inflater);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_enviar_notas:
                new EnviaAlunosTask(getActivity()).execute();  //essa  linha mostra a resposta do json
                break;
            case R.id.menu_baixar_provas:
                Intent vaiParaProvas = new Intent(getActivity(), ProvasActivity.class);
                startActivity(vaiParaProvas);
                break;
            case R.id.menu_mapa:
                Intent vaiParaMapa = new Intent(getActivity(), MapaActivity.class);
                startActivity(vaiParaMapa);
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    public void carregaMediaAlunos() {
        AlunoDAO daoMedia = new AlunoDAO(getActivity());
        List<MediaDasNotas> media = daoMedia.buscaMediaAlunos();
        daoMedia.close();
        //criando um MediaDasNotasAdapter
        MediaDasNotasAdapter adapterMedia = new MediaDasNotasAdapter(getActivity(), media);
        listaDasMediaAlunos.setAdapter(adapterMedia);
    }

    @Override
    public void onResume() {
        super.onResume();
        carregaMediaAlunos();
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, final ContextMenu.ContextMenuInfo menuInfo) {
        //-- recuperando o aluno clicado --------------
        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
        final MediaDasNotas mediaDasNotas = (MediaDasNotas) listaDasMediaAlunos.getItemAtPosition(info.position);
        // --------------------------------------------

        //-- menu item deletar no contexto  -----------
        MenuItem deletar = menu.add(getString(R.string.deletar_media));
        deletar.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem menuItem) {

                //deletando do aluno
                AlunoDAO dao = new AlunoDAO(getActivity());
                dao.deletaMedia(mediaDasNotas);
                dao.close();

                //mostrando mensagem e atualizando a lista
                Toast.makeText(getActivity(), getString(R.string.media_deletado_sucesso), Toast.LENGTH_SHORT).show();
                carregaMediaAlunos();
                return false;
            }
        });
        //-----------------------------------------------------
        //@Override
        //public void onRequestPermissionResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantTesults) {
        //super.onRequestPermissionResult(requestCode, permissions, grantResults);

        // if (requestCode == 123) {
        // faz a ligacao
        //  }
        //}

    }

    @Override
    public void onRefresh() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                mSwipeRefreshLayout.setRefreshing(false);
            }
        }, 2000);
    }
}
16 respostas

Olá Leandro,

O swipe refresh não faz nada por si só, você precisa escrever o comportamento do refresh no método onRefresh(...). Por exemplo, se você quer fazer uma requisição e atualizar uma lista quando fizer o refresh, você vai precisar implementar a requisição e a atualização direto no método onRefresh(...).

Como seria esse atualizar?

a linha new EnviaAlunosTask(getActivity(Menu item)) é um botão. onde eu clico e ele faz a requisição no servidor e salva na lista. porem so mostra a resposta se eu sair e voltar para a tela. ele não está atualizando. como posso atualizar ?

public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_enviar_notas:
                new EnviaAlunosTask(getActivity()).execute();  //essa  linha mostra a resposta do json
                break;

Atualizar é recriar o adapterda sua lista e chamar o método setAdapter(...) novamente. Com esse procedimento você consegue atualizar a lista.

não entendi. como faço isso no meu codigo? isso seria dentro do metodo onRefresh?

essas são as classe que recebo a resposta e salvo na lista

package br.com.cadastroDeAluno.tasks;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.List;

import br.com.cadastroDeAluno.R;
import br.com.cadastroDeAluno.converter.AlunoConverter;
import br.com.cadastroDeAluno.dao.AlunoDAO;
import br.com.cadastroDeAluno.modelo.Aluno;
import br.com.cadastroDeAluno.modelo.MediaDasNotas;
import br.com.cadastroDeAluno.web.WebClient;

/**
 * Created by Leandro on 23/09/2016.
 */
//classe responsavel por "rodar" uma outra thread
public class EnviaAlunosTask extends AsyncTask<Void, Void, String> {

    private Context context;
    private ProgressDialog dialog;

    public EnviaAlunosTask(Context context) {
        this.context = context;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        dialog = ProgressDialog.show(context, context.getString(R.string.aguarde_task), context.getString(R.string.enviando_alunos), true, true);
        dialog.show();
    }

    //metodo q serve para realizar uma thread secundaria
    @Override
    protected String doInBackground(Void... params) {

        AlunoDAO dao = new AlunoDAO(context);
        List<Aluno> alunos = dao.buscaAlunos();
        dao.close();

        AlunoConverter conversor = new AlunoConverter();
        String json = conversor.converteParaJSON(alunos);

        //utilizando a clase webClient
        WebClient client = new WebClient();
        String resposta = client.post(json);


        // ---------------------------------------------
        return resposta;
    }

    //este metodo recebe a resposta e é executado na thread primaria
    @Override
    protected void onPostExecute(String resposta) {
        dialog.dismiss();

        try {
            String jsonDeResposta = resposta;
            JSONObject json = new JSONObject(jsonDeResposta);
            String media = json.getString("media");
            int quantidade = json.getInt("quantidade");

            MediaDasNotas notas = new MediaDasNotas(); //instancio a classe para poder fazer os insert

            notas.setMedia(media);
            notas.setQuantidade(quantidade);

            AlunoDAO dao = new AlunoDAO(context);  //instancio o DAO

            dao.insereMediaDasNotas(notas);

            super.onPostExecute(jsonDeResposta);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }


}
public class ListarMediasFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {

    private ListView listaDasMediaAlunos;
    private View viewMedia;

    private SwipeRefreshLayout mSwipeRefreshLayout;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        setHasOptionsMenu(true); //mostra o menu no fragment

        viewMedia = inflater.inflate(R.layout.fragment_listar_medias, container, false);
        listaDasMediaAlunos = (ListView) viewMedia.findViewById(R.id.lista_mediaDasNotas);
        mSwipeRefreshLayout = (SwipeRefreshLayout) viewMedia.findViewById(R.id.swipeContainer);
        listaDasMediaAlunos.setEmptyView(viewMedia.findViewById(R.id.list_media_vazia));//caso a lista de media esteja fazia

        mSwipeRefreshLayout.setColorSchemeResources(R.color.color_vermelho,
                R.color.color_verde,
                R.color.color_azul,
                R.color.color_laranja);
        // Listenerをセット
        mSwipeRefreshLayout.setOnRefreshListener(this);

        registerForContextMenu(listaDasMediaAlunos);
        return viewMedia;
    }


    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.menu_lista_media, menu);
        super.onCreateOptionsMenu(menu, inflater);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_enviar_notas:
                new EnviaAlunosTask(getActivity()).execute();  //essa  linha mostra a resposta do json
                break;
            case R.id.menu_baixar_provas:
                Intent vaiParaProvas = new Intent(getActivity(), ProvasActivity.class);
                startActivity(vaiParaProvas);
                break;
            case R.id.menu_mapa:
                Intent vaiParaMapa = new Intent(getActivity(), MapaActivity.class);
                startActivity(vaiParaMapa);
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    public void carregaMediaAlunos() {
        AlunoDAO daoMedia = new AlunoDAO(getActivity());
        List<MediaDasNotas> media = daoMedia.buscaMediaAlunos();
        daoMedia.close();
        //criando um MediaDasNotasAdapter
        MediaDasNotasAdapter adapterMedia = new MediaDasNotasAdapter(getActivity(), media);
        listaDasMediaAlunos.setAdapter(adapterMedia);
    }

    @Override
    public void onResume() {
        super.onResume();
        carregaMediaAlunos();
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, final ContextMenu.ContextMenuInfo menuInfo) {
        //-- recuperando o aluno clicado --------------
        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
        final MediaDasNotas mediaDasNotas = (MediaDasNotas) listaDasMediaAlunos.getItemAtPosition(info.position);
        // --------------------------------------------

        //-- menu item deletar no contexto  -----------
        MenuItem deletar = menu.add(getString(R.string.deletar_media));
        deletar.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem menuItem) {

                //deletando do aluno
                AlunoDAO dao = new AlunoDAO(getActivity());
                dao.deletaMedia(mediaDasNotas);
                dao.close();

                //mostrando mensagem e atualizando a lista
                Toast.makeText(getActivity(), getString(R.string.media_deletado_sucesso), Toast.LENGTH_SHORT).show();
                carregaMediaAlunos();
                return false;
            }
        });
        //-----------------------------------------------------
        //@Override
        //public void onRequestPermissionResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantTesults) {
        //super.onRequestPermissionResult(requestCode, permissions, grantResults);

        // if (requestCode == 123) {
        // faz a ligacao
        //  }
        //}

    }

    @Override
    public void onRefresh() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                mSwipeRefreshLayout.setRefreshing(false);
            }
        }, 2000);
    }
}

Você já tem um método que atualiza a lista que é o método carregaMediaAlunos(...). Você só precisa invocar esse método depois de salvar os dados no onPostExecute(...). Com isso pronto, basta usar a EnviaAlunosTask no onRefresh para repetir a requisição e atualizar a lista.

então esse metodo carregaMediaAlunos chamo dentro do onPostExecute e o enviaAlunosTask dentro do onRefresh. É isso?

Isso mesmo Leandro.

seria dessa forma:

@Override
    protected void onPostExecute(String resposta) {
        dialog.dismiss();

        try {
            String jsonDeResposta = resposta;
            JSONObject json = new JSONObject(jsonDeResposta);
            String media = json.getString("media");
            int quantidade = json.getInt("quantidade");

            MediaDasNotas notas = new MediaDasNotas(); //instancio a classe para poder fazer os insert

            notas.setMedia(media);
            notas.setQuantidade(quantidade);

            AlunoDAO dao = new AlunoDAO(context);  //instancio o DAO

            dao.insereMediaDasNotas(notas);
            ListarMediasFragment listar = new ListarMediasFragment();
            listar.carregaMediaAlunos();

            super.onPostExecute(jsonDeResposta);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
@Override
    public void onRefresh() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                mSwipeRefreshLayout.setRefreshing(false);
                carregaMediaAlunos();
            }
        }, 2000);
    }

No onRefresh(...) você vai precisar instanciar a sua EnviaAlunosTask e executá-la apenas. Não precisa chamar o carregaMediaAlunos porque sua task já faz isso no onPostExecute.

Agora, da forma como você invocou o carregaMediaAlunos no onPostExecute não vai funcionar pois você está criando uma nova instância do fragment e não modificando o que já está na tela. Para fazer isso, você vai precisar passar uma referência do fragment no construtor da EnviaAlunosTask e usar essa referência quando for invocar o carregaMediaAlunos.

@Override
    public void onRefresh() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                mSwipeRefreshLayout.setRefreshing(false);
                new EnviaAlunosTask(getActivity()).execute();
            }
        }, 2000);
    }

Ok, mas faltou fazer a segunda parte que falei sobre mandar uma referência do próprio fragment no construtor da async task. Para isso você vai precisar adicionar mais um parâmetro no construtor da sua async task além do Context que vai ser o seu fragment. Vai precisar guardar a referência assim como você faz com o context.

Depois dessas alterações, no onRefresh, você pode passar o fragment assim:

new EnviaAlunosTask(getActivity(), ListarMediasFragment.this).execute();

não entendi mesmo agora. Então como deve ficar essas duas classes então?

teria como me mostrar? como ficaria essas duas classes. para poder entender?

solução!

Vamos lá Leandro, começaremos pela classe EnviaAlunosTask mais especificamente no método onPostExecute(...):

@Override
    protected void onPostExecute(String resposta) {
        dialog.dismiss();

        try {
            String jsonDeResposta = resposta;
            JSONObject json = new JSONObject(jsonDeResposta);
            String media = json.getString("media");
            int quantidade = json.getInt("quantidade");

            MediaDasNotas notas = new MediaDasNotas(); //instancio a classe para poder fazer os insert

            notas.setMedia(media);
            notas.setQuantidade(quantidade);

            AlunoDAO dao = new AlunoDAO(context);  //instancio o DAO

            dao.insereMediaDasNotas(notas);

            // AQUI QUEREMOS ATUALIZAR A LISTA

            super.onPostExecute(jsonDeResposta);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

Mas não conseguimos invocar o método carregaMediaAlunos(...) se não tivermos uma referência para o ListarMediasFragment. Então o que vamos fazer é alterar o construtor da EnviaAlunosTask para receber o fragment como parâmetro e guardar essa referência num atributo da nossa task:

public class EnviaAlunosTask extends AsyncTask<Void, Void, String> {

    private Context context;
    private ProgressDialog dialog;

    // Atributo para a referência do fragment
    private ListarMediasFragment fragment;

    public EnviaAlunosTask(Context context, ListarMediasFragment fragment) {
        this.context = context;
        this.fragment = fragment;
    }

    // resto do código da classe
}

Agora no onPostExecute(...) conseguimos invocar o método que queríamos usar com a referência fragment:

@Override
    protected void onPostExecute(String resposta) {
        dialog.dismiss();

        try {
            String jsonDeResposta = resposta;
            JSONObject json = new JSONObject(jsonDeResposta);
            String media = json.getString("media");
            int quantidade = json.getInt("quantidade");

            MediaDasNotas notas = new MediaDasNotas(); //instancio a classe para poder fazer os insert

            notas.setMedia(media);
            notas.setQuantidade(quantidade);

            AlunoDAO dao = new AlunoDAO(context);  //instancio o DAO

            dao.insereMediaDasNotas(notas);

            // Atualizando a lista no fragment
            fragment.carregaMediaAlunos();

            super.onPostExecute(jsonDeResposta);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

Agora nosso código vai quebrar em todos os lugares onde instanciamos a EnviaAlunosTask pois precisamos passar uma referência do fragment no construtor. Então, por exemplo, no método onRefresh(...) precisaremos fazer:

@Override
    public void onRefresh() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                mSwipeRefreshLayout.setRefreshing(false);
                new EnviaAlunosTask(getActivity(), ListarMediasFragment.this).execute();
            }
        }, 2000);
    }

Agora sim, você deve ter algum resultado ao fazer o swipe refresh.

Agora entendi o porque que estava dando erro no onRefresh. Faltava a referência da classe "ListarMediasFragment" na classe "EnviaAlunosTask".

Muito obrigado!!!

Agradeço de verdade, por todo o apoio, paciência e profissionalismo que você demonstra. Como também, toda essa equipe do Alura.