java - 读取 USB 数据而不阻塞 UI

标签 java android android-asynctask

如果出现任何新数据,此函数会从 USB 设备获取 USB 数据:

gpiointerface.java

  //usb input data handler
  private class handler_thread  extends Thread {
        FileInputStream instream;

        handler_thread(FileInputStream stream ){
            instream = stream;
        }

        public void run()
        {
            while(READ_ENABLE)
            {
                try{
                    if(instream != null)
                    {
                    readcount = instream.read(usbdata,0,4);
                    }
                }catch (IOException e){}
            }
        }
   }

我可以使用此函数访问 usbdata:

 /*read port*/
 public byte ReadPort(){
        return usbdata[1];
 }

我想要实现的是:

如果 handler_thread 读取任何新数据,我想立即将该新数据发送到 MainActivity 并显示在 UI 中。

我想出了这个 AsyncTask,但新数据出现后它不会在 UI 中显示新数据。

MainActivity.java

class usbrun extends AsyncTask<Byte, String, Byte>
{
    @Override
    protected Byte doInBackground(Byte... params) {
        try {
            inData = gpiointerface.ReadPort();   //Get usbdata
            Thread.sleep(100);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return inData;
    }
    @Override
    protected void onProgressUpdate(String... values) {
        super.onProgressUpdate(values);
    }
    @Override
    protected void onPostExecute(Byte result) {
        readdata.setText(Integer.toHexString(result));  //Show in UI
        Log.d("LED", "istegeldi "+ result);

    }
}
<小时/>

完整代码

gpiointerface.java

//User must modify the below package with their package name
/******************************FT311 GPIO interface class******************************************/
public class FT311GPIOInterface extends Activity
{

    private static final String ACTION_USB_PERMISSION =    "com.GPIODemo.USB_PERMISSION";
    public UsbManager usbmanager;
    public UsbAccessory usbaccessory;
    public PendingIntent mPermissionIntent;
    public ParcelFileDescriptor filedescriptor;
    public FileInputStream inputstream;
    public FileOutputStream outputstream;
    public boolean mPermissionRequestPending = false;
    public boolean READ_ENABLE = true;
    public handler_thread handlerThread;

    private byte [] usbdata; 
    private byte [] writeusbdata;
    private int readcount;

    public byte inData;

    public Context global_context;

    public static String ManufacturerString = "mManufacturer=FTDI";
    public static String ModelString = "mModel=FTDIGPIODemo";
    public static String VersionString = "mVersion=1.0";

        /*constructor*/
     public FT311GPIOInterface(Context context){
            super();
            global_context = context;
            /*shall we start a thread here or what*/
            usbdata = new byte[4]; 
            writeusbdata = new byte[4];

            /***********************USB handling******************************************/

            usbmanager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
            //Log.d("LED", "usbmanager" +usbmanager);
            mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
            IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
            filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
            context.registerReceiver(mUsbReceiver, filter);

            inputstream = null;
            outputstream = null;
        }

/*  reset port*/
     public void ResetPort()
     {
        writeusbdata[0] = 0x14;
        writeusbdata[1] = 0x00;
        writeusbdata[2] = 0x00;
        writeusbdata[3] = 0x00;

         new android.os.Handler().postDelayed(
                 new Runnable() {
                     public void run() {
                         try {
                             if(outputstream != null){
                                 outputstream.write(writeusbdata,0,4);
                             }
                         } catch (IOException e) {
                             // TODO Auto-generated catch block
                             e.printStackTrace();
                         }
                     }
                 },
                 30);
     }


        /*read port*/
        public byte ReadPort(){
            Log.d("LED", "istegeldi "+ Integer.toHexString(usbdata[1] & 0xff));
            return usbdata[1];
        }

        /*resume accessory*/
        public void ResumeAccessory()
        {
            // Intent intent = getIntent();
            if (inputstream != null && outputstream != null) {
                return;
            }

            UsbAccessory[] accessories = usbmanager.getAccessoryList();
            if(accessories != null)
            {
                Toast.makeText(global_context, "Accessory Attached", Toast.LENGTH_SHORT).show();
            }

            UsbAccessory accessory = (accessories == null ? null : accessories[0]);
            if (accessory != null) {
                if( -1 == accessory.toString().indexOf(ManufacturerString))
                {
                    Toast.makeText(global_context, "Manufacturer is not matched!", Toast.LENGTH_SHORT).show();
                    return;
                }

                if( -1 == accessory.toString().indexOf(ModelString))
                {
                    Toast.makeText(global_context, "Model is not matched!", Toast.LENGTH_SHORT).show();
                    return;
                }

                if( -1 == accessory.toString().indexOf(VersionString))
                {
                    Toast.makeText(global_context, "Version is not matched!", Toast.LENGTH_SHORT).show();
                    return;
                }

                Toast.makeText(global_context, "Manufacturer, Model & Version are matched!", Toast.LENGTH_SHORT).show();

                if (usbmanager.hasPermission(accessory)) {
                    OpenAccessory(accessory);
                } 
                else
                {
                    synchronized (mUsbReceiver) {
                        if (!mPermissionRequestPending) {
                            Toast.makeText(global_context, "Request USB Permission", Toast.LENGTH_SHORT).show();
                            usbmanager.requestPermission(accessory,
                                    mPermissionIntent);
                            mPermissionRequestPending = true;
                        }
                    }
                }
            } else {}

        }

        /*destroy accessory*/
        public void DestroyAccessory(){

            READ_ENABLE = false;  // set false condition for handler_thread to exit waiting data loop
//          ResetPort(); // send dummy data for instream.read going
            try{Thread.sleep(10);}
            catch(Exception e){}
            CloseAccessory();
        }

/*********************helper routines*************************************************/     

        public void OpenAccessory(UsbAccessory accessory)
        {
            filedescriptor = usbmanager.openAccessory(accessory);
            if(filedescriptor != null){
                usbaccessory = accessory;
                FileDescriptor fd = filedescriptor.getFileDescriptor();
                inputstream = new FileInputStream(fd);
                outputstream = new FileOutputStream(fd);
                /*check if any of them are null*/
                if(inputstream == null || outputstream==null){
                    return;
                }
            }

            handlerThread = new handler_thread(inputstream);
            handlerThread.start();
        }

        private void CloseAccessory()
        {
            try{
                if(filedescriptor != null)
                    filedescriptor.close();

            }catch (IOException e){}

            try {
                if(inputstream != null)
                        inputstream.close();
            } catch(IOException e){}

            try {
                if(outputstream != null)
                        outputstream.close();

            }catch(IOException e){}
            /*FIXME, add the notfication also to close the application*/

            filedescriptor = null;
            inputstream = null;
            outputstream = null;

            System.exit(0);
        }


        /***********USB broadcast receiver*******************************************/
        private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() 
        {
            @Override
            public void onReceive(Context context, Intent intent) 
            {
                String action = intent.getAction();
                if (ACTION_USB_PERMISSION.equals(action)) 
                {
                    synchronized (this)
                    {
                        UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
                        if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false))
                        {
                            Toast.makeText(global_context, "Allow USB Permission", Toast.LENGTH_SHORT).show();
                            OpenAccessory(accessory);
                        } 
                        else 
                        {
                            Toast.makeText(global_context, "Deny USB Permission", Toast.LENGTH_SHORT).show();
                            Log.d("LED", "permission denied for accessory "+ accessory);
                        }
                        mPermissionRequestPending = false;
                    }
                } 
                else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) 
                {
                        CloseAccessory();
                }else
                {
                    Log.d("LED", "....");
                }
            }   
        };

        //usb input data handler
        private class handler_thread  extends Thread {
            FileInputStream instream;

            handler_thread(FileInputStream stream ){
                instream = stream;
            }

            public void run()
            {
                while(READ_ENABLE)
                {
                    try{
                        if(instream != null)
                        {
                        readcount = instream.read(usbdata,0,4);

                        }
                    }catch (IOException e){}
                }
            }
        }
    }

MainActivity.java

/*FT311 GPIO interface exposes the following methods:
 *   ConfigPort, WritePort and ReadPort are for user to use for port operations.
 *   - ConfigPort(outMap, inMap): to configure the port as input or output, with outMap and inMap 
 *                                are arguments for out bitmap and input bitmap.
 *   - WritePort(outData): to write the port data, with outData as argument.
 *   - ReadPort: to read port, it returns the current level on the input IOs.
 *   
 *   DestroyAccessory and ResumeAccessory methods should be called from
 *   overridden  from onResume() and onDestroy routines of main activity class.
 *   
 *   - DestoryAccessory: to be called from onDestory routine of main activity class.
 *   - ResumeAccessory: to be called from onResume routine of main activity class.
 *   
 *   
 */

public class GPIODemoActivity extends Activity {

    /*declare a FT311 GPIO interface variable*/
    public FT311GPIOInterface gpiointerface;

    /*button object*/
    public Button readbutton;

    /*text boxes for data display*/
    public EditText readdata;

    /*variables*/
    public byte inData; /*input Data*/

    public String sstt;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        /*text boxes for data display*/
        readdata = (EditText)findViewById(R.id.readdata);

        /**** command buttons*****/
        readbutton = (Button)findViewById(R.id.readbutton);

/******************************process button presses*********************************/


        /*user code to read the accessory data*/
        readbutton.setOnClickListener(new View.OnClickListener() {

            //@Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                //readbutton.setBackgroundResource(drawable.start);
                inData = gpiointerface.ReadPort();

                readdata.setText(Integer.toHexString(inData & 0xff));
                //ProcessReadData(inData);
            }
        });

        /*create an object of GPIO interface class*/
         gpiointerface = new FT311GPIOInterface(this);
         resetFT311();

         new usbrun().execute();

    }


    class usbrun extends AsyncTask<Byte, String, Byte>
    {
        @Override
        protected Byte doInBackground(Byte... params) {
            try {
                inData = gpiointerface.ReadPort();
                Thread.sleep(100);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return inData;
        }
        @Override
        protected void onProgressUpdate(String... values) {
            super.onProgressUpdate(values);
        }
        @Override
        protected void onPostExecute(Byte result) {
            readdata.setText("asd");
        }
    }



    protected void resetFT311(){
        gpiointerface.ResetPort();
    }

    @Override
    protected void onResume() {
        // Ideally should implement onResume() and onPause()
        // to take appropriate action when the activity looses focus
        super.onResume();
        gpiointerface.ResumeAccessory();
    }

    @Override
    protected void onPause() {
        // Ideally should implement onResume() and onPause()
        // to take appropriate action when the activity looses focus
        super.onPause();
    }

    @Override 
    protected void onDestroy(){

        gpiointerface.DestroyAccessory();
        super.onDestroy();
    }

}

最佳答案

抽象后台线程类:

public abstract class AbstractPollThread extends Thread {

//the default amount of bytes to read at once
public static final int DEFAULT_PACKET_SIZE = 4;

//flag indicating wether this thread should still run
private volatile boolean isFinished = false;

//the input stream to obtain bytes from
private InputStream inputStream;

//the packet size specified in constructor
private int packetSize;

//constructor using packetSize = DEFAULT_PACKET_SIZE
public AbstractPollThread(@NonNull InputStream inputStream) {
    this(inputStream, DEFAULT_PACKET_SIZE);
}

//constructor using custom packetSize
public AbstractPollThread(@NonNull InputStream inputStream, int packetSize) {
    this.inputStream = inputStream;
    this.packetSize = packetSize;
}

//notify this Thread that it should finish
public void finish() {
    isFinished = true;
    interrupt();
}

//this thread's loop method
@Override
public void run() {
    //loop while finish() has not been called
    while (!isFinished) {
        try {
            //obtain the next packetSize bytes as array
            //this blocks until at least packetSize bytes are available
            byte[] packet = nextPacket();

            //invoke abstract handle method and pass the packet we just read
            handlePacket(packet);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    try {
        //try to close the underlying stream
        inputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

//Child classes need to implement this method
protected abstract void handlePacket(byte[] packet);

private byte[] nextPacket() throws IOException {
    //create a new byte array of packetSize length
    byte[] bytePacket = new byte[packetSize];

    //read in a loop, until exactly packetSize bytes are read
    int c = 0;
    while (c < packetSize) {
        int r = inputStream.read(bytePacket, c, packetSize - c);
        if (r == -1) {
            //if this stream is closed, call finish() on this Thread
            finish();
        } else {
            //increment the index by the amount of bytes we could read at once
            c += r;
        }
    }

    //return the bytePacket we just read
    return bytePacket;
}
}

实际后台线程实现:

public class BufferedPollThread extends AbstractPollThread {

//the initial capacity of the packet buffer
public static final int INITIAL_BUFFER_CAPACITY = 16;

//the read handler that wants to receive packets
private ReadHandler readHandler;

//handler hooked to the UIThread's message loop
private Handler uiThreadHandler = new Handler(Looper.getMainLooper());

//a simple list implementation acting as packetBuffer
private List<byte[]> packetBuffer = new ArrayList<>(INITIAL_BUFFER_CAPACITY);

//same constructor as in AbstractPollThread
public BufferedPollThread(@NonNull InputStream inputStream) {
    super(inputStream);
}

//same constructor as in AbstractPollThread
public BufferedPollThread(@NonNull InputStream inputStream, int packetSize) {
    super(inputStream, packetSize);
}

public void setReadHandler(ReadHandler readHandler) {
    //set the Handler that should handle packets
    this.readHandler = readHandler;

    //if the buffer contains packets, push them to the readHandler
        if (packetBuffer.size() > 0) {
            for (byte[] packet : packetBuffer)
                handlePacket(packet);
        }
        packetBuffer.clear();
}

public void clearReadHandler() {
    //clear the reference to the Handler to avoid memory leaks
    this.readHandler = null;
}

@Override
protected void handlePacket(final byte[] packet) {
    //if a handler is set, push the packet directly
    //otherwise add it to buffer
        uiThreadHandler.post(new Runnable() {
            @Override
            public void run() {
                if (readHandler != null)
                    readHandler.onReadPacket(packet);
                else
                    packetBuffer.add(packet);
            }
        });
}

public interface ReadHandler {
    //this is called for every packet in your custom read handler
    void onReadPacket(byte[] packet);
}
}

主要 Activity 的示例设置:

public class MainActivity extends AppCompatActivity implements BufferedPollThread.ReadHandler {

//hold the reference to the pollThread
private BufferedPollThread bufferedPollThread;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //do your setup here (FileInputStream implements InputStream, so no problems here)
    InputStream usbInputStream = null; //Open the FileInputStream to USB here

    //create and start the pollThread that will deliver USB read packets
    bufferedPollThread = new BufferedPollThread(usbInputStream);
    bufferedPollThread.start();
}

@Override
public void onDestroy() {
    //if this activity is about to be destroyed, stop the background poll thread as well
    bufferedPollThread.finish();
    super.onDestroy();
}

@Override
public void onResume() {
    super.onResume();

    //if this activity is in foreground, listen to packets from USB
    bufferedPollThread.setReadHandler(this);
}

@Override
public void onPause() {
    //if this activity is about to be paused, stop listening to packets from USB
    //this is to avoid memory leaks on configuration changes
    bufferedPollThread.clearReadHandler();
    super.onPause();
}

@Override
public void onReadPacket(byte[] packet) {
    //This method is called on the UIThread, so you can do all your View updates here
}
}

参见https://github.com/newcrows/UsbExample/tree/master/app/src/main/java/com/crowsnet/usbexample来源

关于java - 读取 USB 数据而不阻塞 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49971047/

相关文章:

Android SocketTimeoutException 原因

java - 在 GUI 中显示 Java 控制台

java - 如何在Windows 10上扩展jMeter 5.1.1的HEAP SIZE

Java OpenSSL 验证和获取公钥

java - Utdao.save(object) - java.lang.NullPointerException

android - 如何在android中获取照片拍摄时间

java - 代号一重写 Android onNewIntent Activity 方法

Android位图缓存

php - 从 Android 应用程序在线访问 MySQL 哪一个更好? RESTful Web 服务还是异步任务?

java - 可以在 doInBackground() 方法中创建 StringRequest 吗?