首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >警报对话框简化

警报对话框简化
EN

Stack Overflow用户
提问于 2021-07-28 05:03:34
回答 2查看 743关注 0票数 2

我试图写一个简化的AlertDialog,这样我就可以更多的在家与科特林,如果我不能使自己的语言做机器人,然后使科特林的行为,就像PureBasic将是理论。

我遇到的问题是这个错误:

代码语言:javascript
复制
4027-4027/com.example.cardgamexxx E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.cardgamexxx, PID: 4027
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
    at android.view.ViewRootImpl.setView(ViewRootImpl.java:1444)
    at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:469)
    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:114)
    at android.app.Dialog.show(Dialog.java:505)
    at android.app.AlertDialog$Builder.show(AlertDialog.java:1157)
    at com.example.cardgamexxx.Requester.messageRequester(Requester.kt:33)
    at com.example.cardgamexxx.MainActivity.onCreate$lambda-3(MainActivity.kt:695)
    at com.example.cardgamexxx.MainActivity.lambda$Zt8ODWx7LLRfq4535q7hQg5xQfw(Unknown Source:0)
    at com.example.cardgamexxx.-$$Lambda$MainActivity$Zt8ODWx7LLRfq4535q7hQg5xQfw.onClick(Unknown Source:2)
    at android.view.View.performClick(View.java:8160)
    at android.widget.TextView.performClick(TextView.java:16222)
    at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1119)
    at android.view.View.performClickInternal(View.java:8137)
    at android.view.View.access$3700(View.java:888)
    at android.view.View$PerformClick.run(View.java:30236)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:246)
    at android.app.ActivityThread.main(ActivityThread.java:8512)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)

使用此代码:

代码语言:javascript
复制
package com.example.cardgamexxx

import android.app.AlertDialog
import android.content.Context
import com.example.cardgamexxx.RequesterType.MessageRequester_Ok
import com.example.cardgamexxx.RequesterType.MessageRequester_YesNo
import com.example.cardgamexxx.RequesterType.MessageRequester_YesNoCancel

//------------------------------------------------------------------------------
//  Very PureBasic'ish 'Requester' dialogs.
//------------------------------------------------------------------------------

object RequesterType {
    const val MessageRequester_Ok = 1            // to have the 'ok' only button (default)
    const val MessageRequester_YesNo = 2         // to have 'yes' or 'no' buttons
    const val MessageRequester_YesNoCancel = 3   // to have 'yes', 'no' and 'cancel' buttons
}

class Requester {

    fun inputRequester() {

    }

    fun messageRequester(appContext: Context,title: String,message: String,flags: Int) : Int {

        var result: Int = 0

        if( flags == MessageRequester_Ok ) {
            AlertDialog.Builder(appContext)
                .setTitle(title) // R.string.question_title
                .setMessage(message) // R.string.question_message
                .setPositiveButton("Ok") { _, _ -> result = 0 }
                .show()
        }

        if( flags == MessageRequester_YesNo ) {
            AlertDialog.Builder(appContext)
                .setTitle(title) // R.string.question_title
                .setMessage(message) // R.string.question_message
                .setPositiveButton("Yes") { _, _ -> result = 0 }
                .setNegativeButton("No") { _, _ -> result = 1 }
                .show()
        }

        if( flags == MessageRequester_YesNoCancel ) {
            AlertDialog.Builder(appContext)
                .setTitle(title) // R.string.question_title
                .setMessage(message) // R.string.question_message
                .setPositiveButton("Yes") { _, _ -> result = 0 }
                .setNegativeButton("No") { _, _ -> result = 1 }
                .setNegativeButton("Cancel") { _, _ -> result = 2 }
                .show()
        }

        return result

    }

    fun openFileRequester() {

    }

    fun pathRequester() {

    }

    fun saveFileRequester() {

    }

}

另一个问题是,在打开时请求者应该是‘代码’阻塞的意思,而不是这一切都很重要,但是如果"messageRequester()“返回一个结果,那么调用"messageRequester()”的代码就可以根据所给出的答案更改流。

我走错路了吗?我是否需要抛出这个想法,重新创造轮子,从根本上制造我自己的。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-07-28 05:22:24

假设您使用应用程序上下文(因为您将其命名为appContext)来显示对话框,我相信这是异常的根本原因。

您应该传递当前的Activity上下文。

更改您的函数签名以确保传递一个活动:

代码语言:javascript
复制
fun messageRequester(activity: Activity, title: String, message: String, flags: Int) : Int {
...
}

关于代码阻塞,只有在后台线程上调用messageRequester函数才有可能,而这不是Android的原生方式。

您需要使用一些并发锁来锁定名为messageRequester的线程,并从AlertDialog的按钮侦听器中解锁它,通过将其保存到一个变量来转发它们的答案。

通常,我不建议使用锁,因为如果您不熟悉并发原则,那么使用锁是很危险的。

无论如何,我建议简单地在函数中传递一个lambda回调,然后用按钮侦听器的答案调用它。

使用回调

代码语言:javascript
复制
// enum to hold the answer (you're free to use whatever type you want for callback)
enum class Answer { YES, NO, CANCEL }

// Function signature
fun messageRequester(activity: Activity, title: String, message: String, flags: Int, callback: (answer: Answer) -> Unit) {
...

}

// How to pass result to callback from buttons listener
callback(Answer.YES)

// Passing callback to function
myRequester.messageRequester(activity, message, flags) { answer ->
  // Handle answer here
}

使用锁

代码语言:javascript
复制
// enum to hold the answer (you're free to use whatever type you want for callback)
enum class Answer { YES, NO, CANCEL }

// Function signature
fun messageRequester(activity: Activity, title: String, message: String, flags: Int) : Answer? {
  // Don't use main thread!!!!!!
  if (Looper.getMainLooper() == Looper.myLooper()) {
    throw IllegalStateException("Suspending main thread is forbidden!")
  }

  // Variable to hold the answer
  var answer: Answer? = null

  // The lock that holds the thread until an answer is given
  val countDownLatch = CountDownLatch(1)

  // How to pass answer from buttons listener (in AlertDialog creation)
  Listener {
    answer = Answer.YES
    countDownLatch.countDown()
  }
  
  // Wait for answer forever (not recommended since you can exit dialog without clicking buttons and block the thread forever)
  countDownLatch.await()

  // Wait for answer for 10 seconds (answer will be null in case of a timeout). returns false for timeouts.
  val handled = countDownLatch.await(10L, TimeOut.SECONDS)
  return answer 
}
票数 2
EN

Stack Overflow用户

发布于 2021-07-28 10:42:43

虽然我会很好,并张贴的代码,以防别人发现它有用。

更新添加输入请求程序

像这样打电话;

代码语言:javascript
复制
myreq.messageRequester(this,
                  "Testing Ok!","with this message",
                       MessageRequester_Ok) { a ->

    Log.d("debug","$a")
}

添加了最后一个函数,openFileRequester / PathRequester

添加这个类文件。

代码语言:javascript
复制
package com.example.cardgamexxx

import android.app.Activity
import android.app.AlertDialog
import android.net.Uri
import android.text.InputType
import android.widget.EditText
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.net.toUri
import com.example.cardgamexxx.RequesterType.InputRequester_Password
import com.example.cardgamexxx.RequesterType.MessageRequester_Ok
import com.example.cardgamexxx.RequesterType.MessageRequester_YesNo
import com.example.cardgamexxx.RequesterType.MessageRequester_YesNoCancel

//------------------------------------------------------------------------------
//  Very PureBasic'ish 'Requester' dialogs.
//
//  Alert Simplification
//  https://stackoverflow.com/questions/68554654/alert-dialog-simplification
//
//  Help From:
//
//  Shlomi Katriel
//  Ticherhaz FreePalestine
//------------------------------------------------------------------------------

object RequesterType {
    const val MessageRequester_Ok = 1            // to have the 'ok' only button (default)
    const val MessageRequester_YesNo = 2         // to have 'yes' or 'no' buttons
    const val MessageRequester_YesNoCancel = 3   // to have 'yes', 'no' and 'cancel' buttons
    const val InputRequester_Password = 4
}

enum class RequesterAnswer { YES, NO, CANCEL, OK }

class Requester {

    fun inputRequester(activity: Activity, title: String, message: String, flags: Int,callback: (answer: String) -> Unit) {

        val editText = EditText(activity)

        when (flags) {
            InputRequester_Password -> {
                editText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
            }
        }

        val inputDialog = AlertDialog.Builder(activity)
            inputDialog.setTitle(title)
            .setView(editText)
            .setCancelable(false)
            .setNegativeButton("Cancel") { _, _ -> callback("CANCEL") }
            .setPositiveButton("OK") { _,_ -> callback (editText.text.toString()) }
            inputDialog.show()

    }

    fun messageRequester(activity: Activity, title: String, message: String, flags: Int,callback: (answer: RequesterAnswer) -> Unit) {

        if( flags == MessageRequester_Ok ) {
            AlertDialog.Builder(activity)
                .setTitle(title)
                .setMessage(message)
                .setPositiveButton("Ok") { _, _ -> callback(RequesterAnswer.OK) }
                .show()
        }

        if( flags == MessageRequester_YesNo ) {
            AlertDialog.Builder(activity)
                .setTitle(title)
                .setMessage(message)
                .setPositiveButton("Yes") { _, _ -> callback(RequesterAnswer.YES) }
                .setNegativeButton("No") { _, _ -> callback(RequesterAnswer.NO) }
                .show()
        }

        if( flags == MessageRequester_YesNoCancel ) {
            AlertDialog.Builder(activity)
                .setTitle(title)
                .setMessage(message)
                .setPositiveButton("Yes") { _, _ -> callback(RequesterAnswer.YES) }
                .setNegativeButton("No") { _, _ -> callback(RequesterAnswer.NO) }
                .setNegativeButton("Cancel") { _, _ -> callback(RequesterAnswer.CANCEL) } // doesn't work :(
                .show()
        }

    }

    fun openFileRequester(cActivity: AppCompatActivity,filter : String,callback: (answer: Uri) -> Unit) {
        val openFileRequester = cActivity.registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri ->
            callback(uri)
        }
        openFileRequester.launch(filter)
    }

    fun pathRequester(cActivity: AppCompatActivity,filter : String,callback: (answer: Uri) -> Unit) {
        val getUserFolderData = cActivity.registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri: Uri ->
            callback(uri)
        }
        getUserFolderData.launch(filter.toUri())
    }

    fun saveFileRequester(cActivity: AppCompatActivity,filter : String,callback: (answer: Uri) -> Unit) {
        val getUserFolderData = cActivity.registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri: Uri ->
            callback(uri)
        }
        getUserFolderData.launch(filter.toUri())
    }

}

/*

    How to use.

myreq.messageRequester(this,
                       "Testing Ok!","with this message",
                       MessageRequester_Ok) { a ->

    Log.d("debug","$a")
}

myreq.messageRequester(this,
                       "Testing Yes / No","with this message",
                       MessageRequester_YesNo) { a ->

    Log.d("debug","$a")
}

myreq.messageRequester(this,
                       "Testing Yes/No Cancel!","with this message",
                       MessageRequester_YesNoCancel) { a ->

    Log.d("debug","$a")
}
*/
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68554654

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档