【问题标题】:AlertDialog can't get context in custom adapterAlertDialog 无法在自定义适配器中获取上下文
【发布时间】:2019-02-11 22:23:38
【问题描述】:

当我从适配器的 ViewHolder 中按下按钮时,我试图显示一个 AlertDialog。但是当我使用下一条消息启动此崩溃时。

E/AndroidRuntime: 致命异常: main 进程:cl.abitsoft.todotick,PID:4172 android.view.WindowManager$BadTokenException: 无法添加窗口--token null 无效;您的活动正在运行吗? 在 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) {
        [...]
    }

}

编辑:添加 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();
    }
    [...]

【问题讨论】:

    标签: android android-arrayadapter android-alertdialog android-context


    【解决方案1】:

    传递您已全局声明的上下文

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

    并将以下行更改为

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

    adapter = new CustomAdapter(row_models, this);
    

    我希望这会有所帮助。

    【讨论】:

    • 是的,这很好用,但你能解释一下getContextthis 之间的区别吗?
    • getApplicationContext() 根据其名称返回整个应用程序的上下文,同时这指的是您当前的活动,即 MainActivity 在您希望弹出对话框的情况下。
    • @ChristopherVivarVivar 请标记答案(正确),以便其他面临相同问题的人可以轻松找到解决方案。
    【解决方案2】:

    进行这 3 项更改以解决您的问题,

    1. 首先在 CustomAdapter 中传递“this”。

      adapter = new CustomAdapter(row_models,this);
      
    2. 在 CustomAdapter 中获取 Activity。

      public CustomAdapter(ArrayList<RowModel> data, Activity activity) {
      super(context, R.layout.list_item_main, data);
      this.DataSet = data;
      this.context = context;
      }
      
    3. 使用“活动”创建 AlertDialoge。

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

    【讨论】:

    • 只有第一遍有效,2和3不是必须的,这个:)
    • 2 和 3 也需要,因为如果您提到 Context 而不是 Activity,那么您的问题仍然存在!
    【解决方案3】:

    您可以像这样从您的View 获取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(v.getContext()); 
                builder.show();
                break; 
        } 
    }
    

    【讨论】:

    • 问题仍然存在。我尝试,v.getContext()、MainActivity.getApplicationContext()、context、getContext() 和所有时间都是同一个问题
    • 抱歉,没有看到您已经通过构造函数传入了上下文。看起来您遇到的崩溃与获取上下文无关,但托管适配器的 Activity 不再存在。即使在活动被破坏后,您是否仍持有适配器,例如在旋转更改等之后?
    • 现在我添加了 MainActivity
    • 你为什么将这个添加到我的答案而不是你的问题中?
    • 我的错,现在我修复它
    【解决方案4】:

    您必须使用Activity 实例,或者可以将Context 类型转换为Activity,如下所示:

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

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

    你在哪里显示AlertDialog 然后做这样的事情

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

    你不会得到那个异常

    【讨论】:

    • 我试试这个,但不行,我需要将 MainActivity 中的上下文提供给带有this 的适配器
    • @ChristopherVivarVivar,我已经更新了答案,请检查您的问题是否没有解决。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多