2
votes

AlertDialog ne peut pas obtenir le contexte dans l'adaptateur personnalisé

J'essaie d'afficher un AlertDialog lorsque j'appuie sur un bouton d'un ViewHolder de mon adaptateur. Mais quand je lance ce crash avec le message suivant.

E / AndroidRuntime: FATAL EXCEPTION: main Processus: cl.abitsoft.todotick, PID: 4172 android.view.WindowManager $ BadTokenException: Impossible d'ajouter la fenêtre - le jeton null n'est pas valide; votre activité est-elle en cours? à android.view.ViewRootImpl.setView (ViewRootImpl.java:798)

public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener, View.OnClickListener {

    ListView listview;
    private CustomAdapter adapter;

    private Button no, button_accept;
    private EditText edittext_title;
    private Spinner spinner_classes;

    private RowModel rowModel;

    private ArrayList<RowModel> row_models;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(this);

        DrawerLayout drawer = findViewById(R.id.drawer_layout);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.addDrawerListener(toggle);
        toggle.syncState();

        NavigationView navigationView = findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(this);

        // Se inicializan las variables
        edittext_title = findViewById(R.id.main_edittext_title);
        spinner_classes = findViewById(R.id.main_spinner_classes);
        button_accept = findViewById(R.id.main_button_accept);
        listview = findViewById(R.id.main_listview);
        row_models = new ArrayList<>();
        adapter = new CustomAdapter(row_models, getApplicationContext());
        // AL ListView se le asigna el Adapter con el tipo de objeto que usaremos
        listview.setAdapter(adapter);
        // Creamos un arreglo del tipo String con las variables para el Spinner
        String[] values = {"Pagar", "Cobrar", "Llamar", "Pedir", "Comprar", "Revisar", "Otro"};
        // Agregamos las variables a nuestro Spinner
        spinner_classes.setAdapter(new ArrayAdapter<String>(getApplicationContext(), R.layout.spinner_main, values));
        // Habilitamos el click en nuestro boton
        button_accept.setOnClickListener(this);

        loadRows();
    }
    [...]

EDIT: Ajout de MainActivity.class

public class CustomAdapter extends ArrayAdapter<RowModel> implements View.OnClickListener {

    private ArrayList<RowModel> DataSet;
    Context context;

    private static class ViewHolder {
        [...]
    }

    public CustomAdapter(ArrayList<RowModel> data, Context context) {
        super(context, R.layout.list_item_main, data);
        this.DataSet = data;
        this.context = context;
    }

    @Override
    public void onClick(View v) {
        int position = (Integer) v.getTag();
        final Object object = getItem(position);

        switch (v.getId()) {
            case R.id.list_delete_button:
                AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
                builder.show();
                break;
        }
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        [...]
    }

}


0 commentaires

4 Réponses :


0
votes

Vous pouvez obtenir le Contexte de votre Vue comme ceci:

@Override public void onClick(View v) { 
    int position = (Integer) v.getTag(); 
    final Object object = getItem(position); 

    switch (v.getId()) { 
        case R.id.list_delete_button: 
            AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext()); 
            builder.show();
            break; 
    } 
}


5 commentaires

le problème persiste. J'essaye, v.getContext (), MainActivity.getApplicationContext (), context, getContext () et tout le temps est le même problème


Désolé, je n'ai pas vu que vous avez déjà passé dans un contexte via votre constructeur. Il semble également que le plantage que vous obtenez n'est pas lié à l'obtention du contexte, mais que l'activité qui héberge l'adaptateur n'existe plus. Maintenez-vous l'adaptateur même après la destruction de l'activité, par exemple après un changement de rotation ou etc.?


Maintenant, j'ai ajouté la MainActivity


Pourquoi ajoutez-vous ceci à ma réponse au lieu de votre question?


mon mal, maintenant je le répare



4
votes

Transmettez le contexte que vous avez déclaré globalement

adapter = new CustomAdapter(row_models, this);

et remplacez la ligne suivante par

adapter = new CustomAdapter(row_models, getApplicationContext());

par

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

J'espère que cela vous aidera.


3 commentaires

oui, cela fonctionne parfaitement, mais pouvez-vous expliquer la différence entre getContext et this ?


getApplicationContext () renvoie le contexte de l'ensemble de l'application selon son nom, tandis que cela faisait référence à votre activité actuelle, c'est-à-dire MainActivity dans votre cas sur lequel vous voulez que la boîte de dialogue apparaisse.


@ChristopherVivarVivar veuillez marquer la réponse (correcte) afin que d'autres personnes confrontées au même problème puissent facilement trouver la solution.



2
votes

Apportez ces 3 modifications pour résoudre votre problème,

  1. Passez d'abord "this" dans CustomAdapter.

    AlertDialog.Builder builder = new AlertDialog.Builder(activity);
    
  2. obtenir l'activité dans CustomAdapter.

    public CustomAdapter(ArrayList<RowModel> data, Activity activity) {
    super(context, R.layout.list_item_main, data);
    this.DataSet = data;
    this.context = context;
    }
    
  3. Créez AlertDialoge en utilisant "activité".

    adapter = new CustomAdapter(row_models,this);
    


2 commentaires

seulement avec le premier passage fonctionne, 2 et 3 ne sont pas nécessaires, ceci :)


2 & 3 également nécessaires car si vous avez mentionné le contexte au lieu de l'activité, votre problème reste le même!



0
votes

Vous devrez utiliser une instance Activity ou vous pouvez taper du Context vers Activity comme ceci:

AlertDialog. Builder builder = new AlertDialog.Builder (YourActivity.this);

ou

AlertDialog.Builder builder = nouveau AlertDialog.Builder (contexte (Activité)) ;

et Où vous affichez AlertDialog alors faites quelque chose comme ceci

if(!((Activity)context).isFinishing())
{
    builder.show(); 
} 

Vous n'obtiendrez pas cela exception


2 commentaires

J'essaye ceci, mais ne fonctionne pas, j'ai besoin de donner le contexte dans le MainActivity à l'adaptateur avec ceci


@ChristopherVivarVivar, j'ai mis à jour la réponse, vérifiez si votre problème n'est pas résolu.