You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android设备使用RxJava实现USB读卡器后台每秒轮询需求

Solution for USB Card Reader Background Polling with RxJava on Android

Got it, let's walk through how to build this USB card reader polling feature that runs reliably even when your app is in the background, using RxJava. Here's a step-by-step breakdown with code examples:

Core Concepts

  • Use RxJava's interval operator to handle the 1-second polling interval.
  • Offload the USB reading work to a background thread (via Schedulers.io() or a custom scheduler) to avoid blocking the main thread.
  • Use a Foreground Service to host the polling task—this ensures the system won't kill the thread when the app moves to the background (critical for Android O and above, where background services are restricted).
  • Switch back to the main thread with observeOn(AndroidSchedulers.mainThread()) to update UI or process results safely.

Step 1: Add Dependencies

First, make sure you have RxJava and RxAndroid in your build.gradle (Module level):

dependencies {
    // RxJava 3
    implementation 'io.reactivex.rxjava3:rxjava:3.1.5'
    implementation 'io.reactivex.rxjava3:rxandroid:3.0.2'
}

Step 2: Implement USB Reader Polling Logic

Wrap your USB card reading logic into an Observable. This method will handle the actual read operation, and we'll use it with the interval operator:

private Observable<String> pollUsbCardReader() {
    return Observable.defer(() -> {
        try {
            // Replace this with your actual USB card reading logic
            String cardData = readDataFromUsbReader();
            return Observable.just(cardData);
        } catch (Exception e) {
            // Handle read errors without breaking the polling loop
            return Observable.error(e);
        }
    });
}

// Dummy method for your actual USB reading code
private String readDataFromUsbReader() throws Exception {
    // Implement your USB communication here (e.g., using UsbManager)
    return "Card ID: 123456789";
}

Step 3: Create a Foreground Service to Host Polling

Foreground services require a persistent notification, so the user is aware the app is running in the background. Here's the service implementation:

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import androidx.core.app.NotificationCompat;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import java.util.concurrent.TimeUnit;

public class UsbPollingService extends Service {
    private static final int NOTIFICATION_ID = 1001;
    private static final String CHANNEL_ID = "USB_POLLING_CHANNEL";
    private CompositeDisposable compositeDisposable = new CompositeDisposable();

    @Override
    public void onCreate() {
        super.onCreate();
        createNotificationChannel();
        startForeground(NOTIFICATION_ID, buildNotification());
        startPolling();
    }

    private void startPolling() {
        Disposable pollingDisposable = Observable.interval(0, 1, TimeUnit.SECONDS)
                .flatMap(ignored -> pollUsbCardReader())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                        cardData -> {
                            // Handle successful card read result on main thread
                            // e.g., send to Activity via BroadcastReceiver or LiveData
                            handleCardData(cardData);
                        },
                        error -> {
                            // Handle read errors (e.g., log, show toast)
                            error.printStackTrace();
                        }
                );
        compositeDisposable.add(pollingDisposable);
    }

    private void handleCardData(String cardData) {
        // Example: Send data to your Activity using a LocalBroadcast
        Intent intent = new Intent("USB_CARD_DATA_RECEIVED");
        intent.putExtra("CARD_DATA", cardData);
        sendBroadcast(intent);
    }

    private Notification buildNotification() {
        return new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("USB Card Reader Polling")
                .setContentText("Running in background")
                .setSmallIcon(R.drawable.ic_usb_icon) // Replace with your icon
                .setPriority(NotificationCompat.PRIORITY_LOW)
                .build();
    }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    CHANNEL_ID,
                    "USB Polling",
                    NotificationManager.IMPORTANCE_LOW
            );
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // Dispose all subscriptions to stop polling and avoid memory leaks
        compositeDisposable.dispose();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null; // We're using a started service, not bound
    }
}

Step 4: Start the Service from Your Activity

To kick off the polling, start the service from your Activity (or wherever makes sense in your app):

import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;

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

        // Start the polling service
        Intent serviceIntent = new Intent(this, UsbPollingService.class);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForegroundService(serviceIntent);
        } else {
            startService(serviceIntent);
        }
    }
}

Key Notes & Best Practices

  • USB Permissions: Don't forget to request USB device permissions in your manifest and at runtime. Add this to AndroidManifest.xml:
    <uses-feature android:name="android.hardware.usb.host" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    
  • Error Handling: Use operators like onErrorResumeNext() or retry() if you want to automatically recover from read errors without stopping the polling loop.
  • Memory Leaks: Always dispose of your RxJava subscriptions in the service's onDestroy() method (we use CompositeDisposable here to manage multiple subscriptions easily).
  • Communication: To send results from the service to your UI, use LocalBroadcastManager, LiveData with a shared ViewModel, or an EventBus library—choose what fits your app architecture best.

内容的提问来源于stack exchange,提问作者Mohammed Daoud

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:43:01