【问题标题】:Need help getting an Android TextWatcher to work with incoming compound barcode data需要帮助让 Android TextWatcher 处理传入的复合条形码数据
【发布时间】:2017-03-02 20:38:19
【问题描述】:

我正在编写一个使用和外部连接的 USB 条形码/RFID 扫描仪的应用程序。正在扫描的数据是“复合”数据。这是一个例子:

=+03000=W12560712345600=%2800&>0090452359

这是来自复合数据扫描。数据中的分隔符是等号 (=) 或与号 (&)。第一个位=+03000表示扫描中有三个数据部分:

=W12560712345600

=%2800

&>0090452359

此数据可以包含从 1 到 N 的任意数量的数据部分。

在我的 Android 应用程序中,我有一个包含三个 EditText 元素的表单。我需要对这个复合扫描数据做的是使用分隔符将其分解,并将每条数据粘贴到正确的 EditText 字段中。

在经历了很多痛苦之后,我意识到我不能只操作标准输入,而且我需要在我的 EditText 字段之一上使用 TextWatcher 来捕获扫描的数据,以便我可以操作它。

我的问题是我无法弄清楚如何做到这一点。这是我所拥有的:

activity_main.xml

<LinearLayout>
    <TextView />
    <EditText android:id="@+id/datafield01" />
    <EditText android:id="@+id/datafield02" />
    <EditText android:id="@+id/datafield03" />
    <Button />
</LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        EditText dataField01 = (EditText)findViewById(R.id.datafield01);
        EditText dataField02 = (EditText)findViewById(R.id.datafield02);
        EditText dataField02 = (EditText)findViewById(R.id.datafield03);

        dataField01.addTextChangedListener(editTextWatcher);
    }

    TextWatcher editTextWatcher = new TextWatcher(){
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after){
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count){
        }

        @Override
        public void afterTextChanged(CharSequence s){
        }
    };
}

我尝试将 CharSequence 捕获到 StringBuffer 中 - 使用 before、on 和 afterTextChanged - 所以我可以操纵它并将其放入正确的 EditText 元素中,但我没有成功。

修改 MainActivity.java

public class MainActivity extends AppCompatActivity {
    private StringBuffer stringBuffer;
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        stringBuffer = new StringBuffer();

        EditText dataField01 = (EditText)findViewById(R.id.datafield01);
        EditText dataField02 = (EditText)findViewById(R.id.datafield02);
        EditText dataField02 = (EditText)findViewById(R.id.datafield03);
        dataField01.addTextChangedListener(editTextWatcher);

        System.out.println(stringBuffer.toString());
    }

    TextWatcher editTextWatcher = new TextWatcher(){
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after){
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count){
            stringBuffer.append(s);
        }

        @Override
        public void afterTextChanged(CharSequence s){
        }
    };
}

每当我尝试System.out.println(stringbuffer); 时,那里什么都没有。

扫描的代码没有给出换行符或任何其他类型的分隔符,它已经结束,数据部分的数量可以是 1 到 N,但每个数据部分确实有一个已知的固定长度。

肯定有其他人在做这样的事情,但我的谷歌搜索没有结果。

那么,有什么方法可以完成我想做的事情,还是我完全不走运?

谢谢。

【问题讨论】:

  • 我会有一个 EditText 来捕获传入的数据,然后使用 textwatcher 将数据解析/分解为 3 个不同的字段,然后更新 01-03 EditText 字段。
  • 是的......这就是我正在尝试做的事情,但没有运气。
  • 您的扫描文本是否出现在数据字段 01 中?
  • 是的,确实如此。或任何有焦点的领域。

标签: android textwatcher


【解决方案1】:

我确信有一些TextWatcher 实现可以做到这一点;当您看到分隔符字符等时切换焦点。

但我认为,当您知道您拥有来自条形码扫描仪的所有输入时,处理起来会更容易。然后您可以简单地解析数据并将其放在适当的位置。

因此,诀窍是弄清楚您何时拥有所有扫描仪输入,以便您可以解析它。

以下代码使用了我从查看 Android 的 Filter 适配器类中学到的技巧。对于多次快速按键,有一个延迟机制只过滤一次。 (遗憾的是,它是 Google 私有的,所以我们这些凡人不应该使用这个有用的功能。)

由于您的扫描仪显然像键盘一样工作,因此按键暂停应该意味着扫描仪已完成输入。让我们用它来确定扫描何时完成。

首先,我们将定义一个回调接口,因为我是一个 IoC 类型的人:

    interface ScanProcessor {

       void process(CharSequence input);
    }

现在我们将定义一个Handler 类。此处理程序将在主 (UI) 线程上运行,因此我们不能在处理器中太忙。

    public static class InputDelayHandler extends Handler {

       private static final int INPUT_MESSAGE = 0x20170308;

       private static final int PROCESS_MESSAGE = 0x20170309;

       // You'll have to tweak this value to ensure all input is entered, 
       // while the app remains responsive to the scan
       private static final long DELAY_MS = 250;

       private CharSequence mInput;

       private ScanProcessor mScanProcessor;

       InputDelayHandler(ScanProcessor scanProcessor) {
           super();  // associate the handler with the Looper for the current thread
           mScanProcessor = scanProcessor;
       }

       void setInput(CharSequence input) {

           // removing this message is the key to how this works
           // since it's delayed, we can cancel before input is complete.
           removeMessages(PROCESS_MESSAGE);
           removeMessages(INPUT_MESSAGE);
           Message inputMessage = obtainMessage(INPUT_MESSAGE);
           inputMessage.obj = input;
           sendMessage(inputMessage);
           Message startMessage = obtainMessage(PROCESS_MESSAGE);
           sendMessageDelayed(startMessage, DELAY_MS);
       }

       @Override
       public void handleMessage(Message msg) {

           switch (msg.what) {
           case INPUT_MESSAGE:
               // remember the last input
               mInput = (CharSequence) msg.obj;
               break;
           case PROCESS_MESSAGE:
               // callback
               if (/*mInput looks like valid scan data*/) {
                   mScanProcessor.process(mInput);
               }
               break;
           }
       }
   }

具有EditText 字段的类应保留对处理程序的引用。

        private InputDelayHandler mHandler;

现在你的TextWatcher 只需要告诉处理程序发生了什么事:

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

            mHandler.setInput(s);
        }

这将它们联系在一起:

            mHandler = new InputDelayHandler(new ScanProcessor() {

                @Override void process(CharSequence input) {

                    // parse the input, set the EditText fields, etc.
                }
            });

【讨论】:

    【解决方案2】:

    首先,您应该将 TextWatcher 设置到所有 3 个字段上,这样哪个字段具有焦点并不重要。然后只关注afterTextChanged

    private String[] mCompound;
    
    public void afterTextChanged(CharSequence s) {
        //first check and make sure we only try to split up compound data
        //and don't loop forever each time we set data back to ourselves
        if (s.contains("=")) {
    
            //create an array of the compound data parts
            //by splitting every time we find = or &
            mCompound = s.split("(\\=)|(&)");
            //Your example =+03000=W12560712345600=%2800&>0090452359 is now
            //mCompound = { "+03000", "W12560712345600", "%2800", ">0090452359" }     
    
            //Clear/reset all our fields first
            dataField01.setText(null);
            dataField02.setText(null);
            dataField03.setText(null);
    
            //We check if >1 because we know mCompound[0] is always the count
            if (mCompound.length > 1) {
                //we wrap with string.valueof() because the data might just be a number
                dataField01.setText( String.valueOf(mCompound[1]) );
                if (mCompound.length > 2) {
                    dataField02.setText( String.valueOf(mCompound[2]) );
                    if (mCompound.length > 3) {
                        dataField02.setText( String.valueOf(mCompound[3]) );
                    }
                }
            } 
    
        }
    }
    

    【讨论】:

      【解决方案3】:

      你真正想做的包括几个部分:

      1. 从 rfid 读取数据:

      实现这一点的正确方法是首先添加正确的权限:

      <uses-permission android:name="android.permission.NFC" />
      <uses-sdk android:minSdkVersion="10"/>
      <uses-feature android:name="android.hardware.nfc" android:required="true" />
      

      然后,添加您的意图,它“知道”如何处理扫描的数据:

      <intent-filter>
          <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
          <category android:name="android.intent.category.DEFAULT"/>
          <data android:mimeType="text/plain" />
      </intent-filter>
      

      然后,您想在单独的 res xml 文件中添加您的应用支持的 NFC 技术:

      <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
          <tech-list>
              <tech>android.nfc.tech.IsoDep</tech>
              <tech>android.nfc.tech.NfcA</tech>
              <tech>android.nfc.tech.NfcB</tech>
              <tech>android.nfc.tech.NfcF</tech>
              <tech>android.nfc.tech.NfcV</tech>
              <tech>android.nfc.tech.Ndef</tech>
              <tech>android.nfc.tech.NdefFormatable</tech>
              <tech>android.nfc.tech.MifareClassic</tech>
              <tech>android.nfc.tech.MifareUltralight</tech>
          </tech-list>
      </resources>
      

      最后,在 AndroidManifest.xml 文件中将您的 Activity 绑定到 Intent:

      <activity>
      ...
      <intent-filter>
          <action android:name="android.nfc.action.TECH_DISCOVERED"/>
      </intent-filter>
      
      <meta-data android:name="android.nfc.action.TECH_DISCOVERED"
          android:resource="@xml/nfc_tech_filter" />
      ...
      </activity>
      
      1. 收到数据后,您希望将消息分成 3 部分,如您所指出的,它们用“=”符号或“&”符号分隔:

        Parcelable[] rawMsgs = intent.getParcelableArrayExtra( NfcAdapter.EXTRA_NDEF_MESSAGES);

        NdefMessage msg = (NdefMessage) rawMsgs[0]; String st = new String(msg.getRecords()[0].getPayload()); 英石。 String[]tokens = st.split("=|&");

      完成后,令牌数组应保存您的消息。

      https://developer.android.com/guide/topics/connectivity/nfc/nfc.html#tag-dispatch

      【讨论】:

        猜你喜欢
        • 2022-07-20
        • 1970-01-01
        • 1970-01-01
        • 2014-03-19
        • 2020-08-25
        • 1970-01-01
        • 1970-01-01
        • 2014-04-06
        • 1970-01-01
        相关资源
        最近更新 更多