我有一个EditTextPreference
的子类,允许用户输入一些结构化文本,并在关闭对话框之前对其进行验证。我想让用户在首选项的对话框打开时通过扫描NFC标签来输入此文本。扫描标记会使用收到的文本填充EditText
。在首选项的对话框未打开时扫描标签将不起作用(即,它将允许任何其他已注册的应用程序处理ACTION_NDEF_DISCOVERED
Intent
)。
我已经在相关的Activity
中有类似的工作,所以我不需要任何有关NFC部件本身的帮助。当NFC API与托管Preference
绑定时,问题是通过Activity
连接所有内容: -
enableForegroundDispatch()
采用Activity
参数Activity.onNewIntent()
我有两个关于如何继续的想法,有不同的缺点: -
Activity
的{{1}}为我完成所有设置。首次创建时,需要告知Preference
Preference
的{{1}}身份,以便Activity
稍后在右侧调用Preference
和enableForegroundDispatch
倍。它还需要将disableForegroundDispatch
次呼叫转发给onNewIntent()
。这看起来非常脆弱 - 特别是考虑到Preference
通常会在Preference
内,而PreferenceFragment
不需要了解个人偏好 - 但它会更合理如果Activity
可以找出托管它的Preference
。Activity
并将对话框替换为以对话框为主题的私有DialogPreference
。创建布局没有问题,这将使所有与NFC相关的代码保持在特殊Activity
内。但问题是如何Activity
来自startActivityForResult
。在Preference
中设置Intent
是不够的,因为它使用Preference
并且没有用于获取结果的机制。即使我确实设法startActivity
,我也遇到了与上面相同的问题,即会传递给托管startActivityForResult
的{{1}},这会使机制再次变得脆弱。如果我可以使用其他渠道从Activity
中获取文本,则此选项会更合适。你能帮助解决这些问题吗?获得替代工作就足够了,但我更喜欢选项2,因为它可以帮助我解决另一个类似的问题。
答案 0 :(得分:1)
使用1)并创建两个接口:
让活动实现B并将A存储在字段中。在NFC事件中,如果设置了A字段,则调用接口。
让UI类在构造函数的字段中实现A并存储B.
根据A字段是对象还是null来切换nfc前台模式。
答案 1 :(得分:1)
除非我忽视了一些显而易见的事情,否则实施2号理念似乎并不困难。
您可能希望在框架中查看RingtonePreference的源代码,该代码从startActivityForResult()
方法调用onClick()
并处理其收到的意图作为结果,非常与你的想法相似。
答案 2 :(得分:1)
我最终能够通过一些巧妙的意图来解决这个问题。我从选项2开始:
Activity
,并带有对话框主题。新活动包含所有NFC代码:它将自身传递给enableForegroundDispatch
,并且在扫描代码时使用onNewIntent
方法更新其文本。setResult
将其结果返回给调用者,而是使用一些标识信息构建Intent
,指示是否按下了OK或取消了对话框,以及新的文本。它从onPause
发送受if (isFinishing())
保护的意图,以确保即使从外部触摸或后退键关闭意图也会发送该意图。EditTextPreference
的新子类替换了我的Preference
子类。新类看起来与EditTextPreference
非常相似,但不需要那么大的灵活性。Preference
包含一个匿名BroadcastReceiver
子类,它从收到的Intent
获取结构化文本并设置首选项的值,更新GUI并触发{{1}听众。onPreferenceChange
方法调用onClick()
,传递匿名getContext().registerReceiver
和与对话活动设置的识别信息相匹配的意图过滤器。然后,它会调用BroadcastReceiver
(不 getContext().startActivity
)来启动对话活动。还有一个额外的复杂因素:如果在对话框打开时发生配置更改(例如重定向),则会销毁首选项并重新创建其托管活动。因为我使用活动的上下文而不是应用程序上下文来注册接收器,所以旧的接收器将被取消注册,并且新的首选项需要注册接收器。 (使用应用程序上下文会泄漏旧活动及其所有首选项,并且可能会在旧的首选项更新时导致崩溃。)因此,首选项还有一些事情要做:
startActivityForResult
还设置一个标志,以便它知道接收器已注册。接收器清除标志。 onClick
获取“接收者已注册”标志的副本。SavedState
检查此标志,如果设置,则使用与之前相同的接收方和意图过滤器调用onRestoreInstanceState
。结果是来自getContext().registerBroadcastReceiver
,我可以使用与Preference
相同的功能,但实现此目的的所有代码都保留在startActivityForResult
和{{1}内它调用:包含Preference
或Activity
不需要任何代码。由于我在几个屏幕上具有相同类型的首选项,因此这是一个巨大的代码重用获胜,当然还有更好的封装。
同样的技术可以用于其他想要使用PreferenceActivity
中难以实现的功能的首选项,例如GL,视频,声音或嵌入地图片段。