2

I'm trying to show a AlertDialog when I press a button from a ViewHolder from my adapter. But when I launch this crash with the next message.

E/AndroidRuntime: FATAL EXCEPTION: main Process: cl.abitsoft.todotick, PID: 4172 android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running? at android.view.ViewRootImpl.setView(ViewRootImpl.java:798)

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) {
        [...]
    }

}

EDIT: Added MainActivity.class

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();
    }
    [...]

4 Answers4

4

Pass the context that you have declared globally

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

and change the following line to

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

to

adapter = new CustomAdapter(row_models, this);

I hope this will help.

hfarhanahmed
  • 184
  • 1
  • 7
  • yea, that's work perfectly, but can you explain the difference between the `getContext` and `this`? – Christopher Vivar Vivar Feb 12 '19 at 12:54
  • getApplicationContext() returns the context of the whole application as per its name meanwhile this was referring to your current Activity i.e MainActivity in your case on which you want the dialog to pop up. – hfarhanahmed Feb 12 '19 at 13:15
  • @ChristopherVivarVivar please mark the answer (correct) so other facing the same issue can easily get to the solution. – hfarhanahmed Feb 13 '19 at 06:26
2

Make this 3 changes to resolve your problem,

  1. first pass "this" in CustomAdapter.

    adapter = new CustomAdapter(row_models,this);
    
  2. get Activity in CustomAdapter.

    public CustomAdapter(ArrayList<RowModel> data, Activity activity) {
    super(context, R.layout.list_item_main, data);
    this.DataSet = data;
    this.context = context;
    }
    
  3. Create AlertDialoge using "activity".

    AlertDialog.Builder builder = new AlertDialog.Builder(activity);
    
Mayur Dabhi
  • 3,607
  • 2
  • 14
  • 25
0

You can get the Context from your View like this:

@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; 
    } 
}
Jackey
  • 3,184
  • 1
  • 11
  • 12
0

You will have to use either Activity instance or can TypeCast Context to Activity like this following:

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

or

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

and Where you are showing AlertDialog then do something like this

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

You will not get that exception

ॐ Rakesh Kumar
  • 1,318
  • 1
  • 14
  • 24