创建在对话框中使用NFC的首选项

时间:2013-04-02 12:36:17

标签: android nfc android-preferences

我有一个EditTextPreference的子类,允许用户输入一些结构化文本,并在关闭对话框之前对其进行验证。我想让用户在首选项的对话框打开时通过扫描NFC标签来输入此文本。扫描标记会使用收到的文本填充EditText。在首选项的对话框未打开时扫描标签将不起作用(即,它将允许任何其他已注册的应用程序处理ACTION_NDEF_DISCOVERED Intent)。

我已经在相关的Activity中有类似的工作,所以我不需要任何有关NFC部件本身的帮助。当NFC API与托管Preference绑定时,问题是通过Activity连接所有内容: -

  1. enableForegroundDispatch()采用Activity参数
  2. 结果通过Activity.onNewIntent()
  3. 传递

    我有两个关于如何继续的想法,有不同的缺点: -

    1. 要求包含我Activity的{​​{1}}为我完成所有设置。首次创建时,需要告知Preference Preference的{​​{1}}身份,以便Activity稍后在右侧调用PreferenceenableForegroundDispatch倍。它还需要将disableForegroundDispatch次呼叫转发给onNewIntent()。这看起来非常脆弱 - 特别是考虑到Preference通常会在Preference内,而PreferenceFragment不需要了解个人偏好 - 但它会更合理如果Activity可以找出托管它的Preference
    2. 停止成为Activity并将对话框替换为以对话框为主题的私有DialogPreference。创建布局没有问题,这将使所有与NFC相关的代码保持在特殊Activity内。但问题是如何Activity来自startActivityForResult。在Preference中设置Intent是不够的,因为它使用Preference并且没有用于获取结果的机制。即使我确实设法startActivity,我也遇到了与上面相同的问题,即会传递给托管startActivityForResult的{​​{1}},这会使机制再次变得脆弱。如果我可以使用其他渠道从Activity中获取文本,则此选项会更合适。
    3. 你能帮助解决这些问题吗?获得替代工作就足够了,但我更喜欢选项2,因为它可以帮助我解决另一个类似的问题。

3 个答案:

答案 0 :(得分:1)

使用1)并创建两个接口:

  1. 用于接收意图(或更好的NFC数据,如NDEF记录等)
  2. B用于设置或删除A
  3. 的实例

    让活动实现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}内它调用:包含PreferenceActivity不需要任何代码。由于我在几个屏幕上具有相同类型的首选项,因此这是一个巨大的代码重用获胜,当然还有更好的封装。

同样的技术可以用于其他想要使用PreferenceActivity中难以实现的功能的首选项,例如GL,视频,声音或嵌入地图片段。