首页 > 解决方案 > 如何在 SEservice 中使用 Executor (Open Mobile API for Android 9.0)

问题描述

我正在研究 NFC,目前尝试为 Android 9.0 中内置的 Open Mobile API 编写代码,但不了解在 SEService 中传递 Executor 参数的方式。

public class MainActivity extends Activity implements SEService.OnConnectedListener {

    final String LOG_TAG = "NfcTest";

    private SEService seService;

    private Button button;


    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        LinearLayout layout = new LinearLayout(this);
        layout.setLayoutParams(new LayoutParams(
                LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT));

        button = new Button(this);
        button.setLayoutParams(new LayoutParams(
                LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT));

        button.setText("Click Me");
        button.setEnabled(false);
        button.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                try {

                    Reader[] readers = seService.getReaders();
                    if (readers.length < 1)
                        return;


                    Session session = readers[0].openSession();



                    Channel channel = session.openLogicalChannel(new byte[]{
                            (byte) 0xF0, 0x51, (byte) 0xBC, 0x53, 0x54, 0x69, 0x64,
                            (byte) 0x4D, 0x6F, 0x62, 0x69, (byte) 0x6C,
                            (byte) 0x65, 0x2D, (byte) 0x49, 0x44});


                    byte[] respApdu = channel.transmit(new byte[]{
                            (byte) 0x90, 0x10, 0x00, 0x00, 0x00});

                    channel.close();

                    // Parse response APDU and show text but remove SW1 SW2 first
                    byte[] helloStr = new byte[respApdu.length - 2];
                    System.arraycopy(respApdu, 0, helloStr, 0, respApdu.length - 2);
                    Toast.makeText(MainActivity.this, new String(helloStr), Toast.LENGTH_LONG).show();
                } catch (Exception e) {
                    Log.i(LOG_TAG, "Message: " + e.getClass().getCanonicalName());
                    if(e.getClass().isInstance(new NoSuchElementException()))
                        Toast.makeText(MainActivity.this, "NFC sim", Toast.LENGTH_LONG).show();
                    else if (e.getClass().isInstance(new IOException())){
                        Toast.makeText(MainActivity.this, "No sim found", Toast.LENGTH_LONG).show();
                    }
                    else{
                        Toast.makeText(MainActivity.this, "Normal sim", Toast.LENGTH_LONG).show();
                    }
                }
            }
        });

        layout.addView(button);
        setContentView(layout);


        try {

            seService = new SEService(this, this,this);
        } catch (SecurityException e) {
            Log.e(LOG_TAG, "Binding not allowed, uses-permission org.simalliance.openmobileapi.SMARTCARD?");
        } catch (Exception e) {
            Log.e(LOG_TAG, "Exception: " + e.getMessage());
        }
    }

    @Override
    protected void onDestroy() {
        if (seService != null && seService.isConnected()) {
            seService.shutdown();
        }
        super.onDestroy();
    }

    public void serviceConnected(SEService service) {
        Log.i(LOG_TAG, "seviceConnected()");
        button.setEnabled(true);
    }

    @Override
    public void onConnected() {

    }
}

问题发生在:

seService = new SEService(this, this,this);

第一个和最后一个参数接受了中间一个执行器出现错误!

java.util.concurrent.Executor 这个

如何通过这个?

标签: javaandroidnfcsecure-elementopen-mobile-api

解决方案


您会收到此错误,因为构造函数的第二个参数SEService必须是java.util.concurrent.Executor. 您的 MainActivity(this对象)没有实现执行器。

SEService 使用这个执行器来调用回调方法。因此,您必须自己创建这样一个执行程序才能将其传递给SEService. 例如,您可以简单地ExecutorService使用单个工作线程创建一个来处理回调:

ExecutorService pool = Executors.newSingleThreadExecutor();
seService = new SEService(this, pool, this);

但请注意,这些回调随后会在工作线程(而不是应用程序的主线程)上执行。因此,如果您想在回调中执行任何 UI 操作,您将需要在 UI 线程上显式运行它们,例如

runOnUiThread(new Runnable() {
    void run() {
        button.setEnabled(true); // ... or some other UI modifications
    }
});

推荐阅读