Problem updating Listactivity using a custom adapter

Asked

Viewed 1,057 times

0

I’m working on an app where I populate a ListActivity using data from a SQLite created by the program itself. When adding items in the database, the list is automatically updated, but when removing, the list is not updated.

I insert new items into a Activity separate from the main, but when deleting items, I do the same within a DialogFragment called from within the ListActivity. Here is my code:

package activities;

import adapters.ItemListAdapter;
import android.app.FragmentManager;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
import br.bravosix.historico.R;
import classes.Database;
import classes.ListItem;
import fragments.QuickViewFragment;

public class ActivityList extends ListActivity {

    ItemListAdapter adapter;


    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // carrega os itens salvos no banco de dados quando
        // a tela é criada
        loadItems();
    }

    // re-carrega os itens após o resumo da activity

    public void onResume() {
        super.onResume();
        loadItems();
    }


    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_list_items, menu);
        return true;
    }


    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.menu_list_add) {
            // activity responsável por adicionar novos itens
            // ao banco de dados
            Intent addItem = new Intent(this, ActivityNewItem.class);
            startActivity(addItem);
            return true;
        }
        return super.onOptionsItemSelected(item);
    }


    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);

        ListItem item = (ListItem) l.getItemAtPosition(position);
        FragmentManager fm = getFragmentManager();
        QuickViewFragment quickView = QuickViewFragment.newInstance(item);
        quickView.show(fm, "tag_quick_view");
        // testei o notifyDataSetChanged aqui e não funcionou, o mesmo
        // ocorreu quando usei a função loadItems();
        adapter.notifyDataSetChanged();
    }

    public void loadItems() {
        Database db = new Database(this);
        adapter = new ItemListAdapter(this, db.readItems());
        setListAdapter(adapter);
    }
}

What I need to do to that, when the QuickViewFragment is closed, the list is updated?

  • This insertion of new items in another Activity, by chance could not be done adding new items in Dialog Fragment?

  • It is indifferent in the case. It is an application for personal use and does not need to be very complex. I created a new Activity for convenience, but it could perfectly be something similar to the way I’m using to view/delete items. But why the question?

  • The why of the question is that if it is a simple item, for example a name, you could do so: a list Fragment that uses loaders. In this list you have a menu to add. If you click add opens a Fragment dialog asking for the name, you enter and the list is automatically updated due to you being using loaders. If you press an item, it displays a dialog giving you the option to edit and delete. It is also updated automatically due to the use of loaders. I find it so much simpler when the list is simple.

  • The item in the case is a form, with 5 different fields. But how do loaders work? Have any reference link?

  • I do, but it’s in English, it’ll do?

  • Could be, no problem at all.

  • [Official Documentation on Loaders][1] [Translated Website Documentation][2] [I learned from this website about loaders][3] [1]: http://developer.android.com/guide/components/loaders.html [2]: http://celeiroandroid.blogspot.com.br/2011/04/loaders.html [3]: http://www.androiddesignpatterns.com/2012/07/loaders-and-loadermanager-background.html

  • One more thing, have preferences for Fragments, after that use and accustom you will not want anything else. I saw that you are using Listactivity.

  • 1

    I thought it would be simpler to use a Listactivity instead of a Listfragment for reasons of the application being for personal use. In other projects, I use Listfragment more for the simplicity that Fragments brought.

Show 4 more comments

1 answer

1


I will suggest a solution to the problem of Fragment but I have another suggestion to improve the way you update your list on ActivityList.

From what I understand, you update the list whenever your Activity That includes the call to onResume resulting from the finalisation of ActivityNewItem, but there is a negative effect in this form due to the life cycle of the Activity. When your app goes into the background and comes back, you’ll go to BD needlessly.

In the case of Fragment there is no interference in the life cycle of the Activity then the onResume is not called. Nor is it good to call the notifyDataSetChanged because at that moment the Fragment will be displayed, and the user has not yet deleted the item, given the asynchronicity.


1. Updating the list after iteration with Quickviewfragment

In the method onListItemClick, i would make a small change. Pass a Listener for the Fragment (or leave the onAttach set it), so that at the end of the interaction (update, delete, any other), it calls the method to update the list.

The ActionListener in the code, is the form of communication (avoiding coupling) between the Fragment and the Activity. With the interface methods the Fragment may notify the Activity of the interactions made that require updating in the Activity.

It would look something like:

Class ActivityList:

public class ActivityList extends ListActivity implements QuickViewFragment.ActionListener {

// ... Codigo e mais codigo

    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);

        ListItem item = (ListItem) l.getItemAtPosition(position);
        FragmentManager fm = getFragmentManager();
        QuickViewFragment quickView = QuickViewFragment.newInstance(item);
        quickView.setActionListener(this);
        // Sendo generico, pois nao sei que acoes poderiam ocorrer no fragment 
        quickView.show(fm, "tag_quick_view");
        // Nao precisa do adapter.notifyDataSetChanged();
    }

    @Override
    public void onDelete(Item item) {
        atualizaLista(item);
        // O metodo atualiza pode ser de duas formas:
        // Ou ele remove o item da lista, sem ir no banco.
        // Ou ele atualiza toda a lista, select no banco.
    }

    // Demais metodos da interface

}

Class QuickViewFragment:

public class QuickViewFragment extends DialogFragment {

    private ActionListener mAl;

    @Override
    public View onCreateView(...) {
        // ...
    }

    public interface ActionListener {
        public void onDelete(...);
        public void onUpdate(...);
        // ... O que mais quiser
    }

    private void ActionListener al; // Getter/Setter suprimidos

    @Override
    public void onAttach(Activity a) {
        super.onAttach(a);

        if(a instanceof ActionListener) {
            mAl = (ActionListener) a;
        }

        // Apenas uma sugestão de uso, nao precisa ser assim...
    }

    @Override
    public void onDismiss(DialogInterface dialog) {
        if(al != null) {
            //Chamar alguma acao do Listener
        }

        super.onDismiss(dialog);
    }

    @Override
    public void onDestroyView(...) {
        al = null; // Evitar MemoryLeak
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // ... Código

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

        // ... Mais Código

        // Na configuracao do botao negativo (utilizar o ClickListener para chamar a Callback.
        builder.setNegativeButton(R.string.quickview_delete,
            new OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    // Codigo de deleção no BD...
                    if(mAl != null) {
                        mAl.onDelete(...);
                    }
                }
            }
        );
}

In the interface methods you would update your list.

The method onAttach belongs to the life cycle of Fragment, He is called when the Fragment is "attached" to Activity, before being added. I recommend reading the documentation on the life cycle of Fragment.

Already the method onDismiss is called when the Dialog of DialogFragment is being closed. Take a look at the documentation of the method DialogFragment.onDismiss(DialogInterface dialog).

2. Updating the list after return from Activitynewitem

When you call an Activity using Intent, there is an alternative way that indicates that you are expecting a result of the return of ActivityNewItem. The startActivityForResult (Intent intent, int requestCode), and to get the return you need to write the method onActivityResult (int requestCode, int resultCode, Intent data) of his ListActivity to know whether or not to update the list.

In the method onOptionsItemSelected of ListActivity I would make a small change:

public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();

    if (id == R.id.menu_list_add) {
        // activity responsável por adicionar novos itens
        // ao banco de dados
        Intent addItem = new Intent(this, ActivityNewItem.class);
        startActivityForResult(addItem, 999, null); // Guarde o numero 999 pra depois
        return true;
    }

    return super.onOptionsItemSelected(item);
}

And add this class method ListActivity:

protected void onActivityResult(int requestCode /* 999 */, int resultCode, Intent data) {
    if(requestCode == 999 && resultCode == RESULT_OK) {
        // Atualiza lista, pois o retorno foi positivo...
    }

    super.onActivityResult(...);
}

In the ActivityNewItem put something like:

@Override
public void finish() {
    if(houveAlteracao) { // Se houve alguma atualizacao nessa `Activity`
        setResult(RESULT_OK, dado);
        // Diz para a Activity que me chamou
        // Que houve uma alteracao de dados aqui...
    }

    super.finish();
}

I believe with this working, you don’t need to use the method onResume to update the list, unless some external app modifies your BD.

The answer was long, but I hope it helps...

  • I’m having a problem when it comes to using interfaces. I’m not quite sure how to work with them yet. I got the following error: http://pastebin.com/0hb6VBtP How do I fix this? And how do I call the interface functions inside the Fragment buttons? In this case, I have three buttons: one to delete the item, one to send it by email (not yet implemented) and a third that serves only to close the screen.

  • Ah, this mistake is my fault, is that in the method onAttach, I forgot I need to call the super. I will embed this in the reply. I will also include examples of callbacks calls.

  • @gh0st_h4wk, added something to the onCreateView and the method onClick (resulting from clicking the delete button)

  • thanks for the changes, but I don’t think they’ll do. I forgot to mention I’m using the class AlertDialog to build my DialogFragment, so I need to place the execution of the commands inside the buttons that the class provides (PositiveButton, NegativeButton and NeutralButton). How can I assign the functions to these buttons? Sorry I forgot this!

  • Hmm, this information is new, I will take a look and update. It could include the dialog building code?

  • Of course, no problem. I was already preparing to post it. Here’s the code of QuickViewFragment: http://pastebin.com/f4TRTTZs If you need anything else, please let me know and I will release it immediately. Edit: was already included, including the codes you indicated to me when I stopped this issue from the previous comment.

  • @gh0st_h4wk, I added the Listener usage of the negative button, where you delete the Item

  • Okay, I guess I get it then. I should put the code that erases the item within the onDelete procedure, right? After that, I put the code that updates the list in the interface method? Just this was still a bit confusing. And what is the purpose of the onAttach and onDismiss method? Can you point me to a link where you can read more about?

  • @gh0st_h4wk, no need to migrate the deletion code pro onDelete, may even be. But the method onDelete in Activity would be to update the list, can even migrate the deletion there. I will comment on the onAttach and the onDismiss in response.

Show 4 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.