Обратный вызов службы с привязкой к Android никогда не срабатывал - PullRequest
0 голосов
/ 03 ноября 2019

Я пытаюсь создать очень простой Service для подачи Activity и предоставления ему набора кадров. Я следовал методологии Bound Service и создал интерфейс обратного вызова для feed Activity.

Клиентская сторона (активность):

public class MainActivity extends AppCompatActivity implements FrameReadyCallBack {
    private Intent videoServiceIntent;
    private VideoService videoService;
    private boolean bound = false;
    private ImageView surfaceView_video = null;
    private String videoPort = "5002";
    private String videoServerAddr = "192.168.10.107";
    private ServiceConnection serviceConnection = null;

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

        surfaceView_video = findViewById(R.id.surfaceView_video);

        serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName className, IBinder service) {
                VideoService.ImagesCollectorBinder binder = (VideoService.ImagesCollectorBinder) service;
                videoService = binder.getService();
                bound = true;
                videoService.registerCallBack(MainActivity.this); // register
            }

            @Override
            public void onServiceDisconnected(ComponentName arg0) {
                bound = false;
            }
        };

        startVideoService();
    }

    @Override
    public void frameReady(byte[] image_data) {
        //TODO: create image and update surfaceView_video
    }

    public void startVideoService()
    {
        videoServiceIntent = new Intent(this, VideoService.class);

        videoServiceIntent.putExtra(VideoService.LOCAL_PORT_KEY, videoPort);
        videoServiceIntent.putExtra(VideoService.LOCAL_VIDEOSERVER_ADDR_KEY, videoServerAddr);

        startService(videoServiceIntent);
    }

    @Override
    protected void onStart() {
        super.onStart();
        bindService();
    }

    @Override
    protected void onStop() {
        super.onStop();
        unbindService();
    }

    private void bindService() {
        bindService(videoServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

    private void unbindService(){
        if (bound) {
            videoService.registerCallBack(null); // unregister
            unbindService(serviceConnection);
            bound = false;
        }
    }
}

Сервисная сторона:

public class VideoService extends Service {
    public static final String LOCAL_PORT_KEY = "video_port";
    public static final String LOCAL_VIDEOSERVER_ADDR_KEY = "video_server_addr";
    private static final int DEFAULT_VIDEO_PORT = 5002;
    private static final int VIDEO_SERVER_RESPAWN = 2000;

    private FrameReadyCallBack frameReadyCallBack = null;
    private VideoReceiver videoReceiver = null;
    private IBinder videoServiceBinder = new VideoServiceBinder();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return videoServiceBinder ;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        videoReceiver.kill();
        return super.onUnbind(intent);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        final int localVideoPort = intent.getIntExtra(LOCAL_PORT_KEY, DEFAULT_VIDEO_PORT);
        final String videoServerAddr = intent.getStringExtra(LOCAL_VIDEOSERVER_ADDR_KEY);

        videoReceiver = new VideoReceiver(videoServerAddr, localVideoPort);
        videoReceiver.start();

        return Service.START_NOT_STICKY;
    }

    public void registerCallBack(FrameReadyCallBack frameReadyCallBack) {
        this.frameReadyCallBack = frameReadyCallBack;
    }

    public class VideoServiceBinder extends Binder {

        public VideoService getService() {
            return VideoService.this;
        }
    }

    private class VideoReceiver extends Thread {
        private boolean keepRunning = true;
        private int VIDEO_SERVER_PORT;
        private String VIDEO_SERVER_ADDR;
        private int bad_frames;
        private int frames;
        private int link_respawn;
        private FrameDecodingStatus status;

        public VideoReceiver(String addr, int listen_port) {
            VIDEO_SERVER_PORT = listen_port;
            VIDEO_SERVER_ADDR = addr;
        }

        public void run() {
            InetAddress serverAddr;
            link_respawn = 0;

            try {
                serverAddr = InetAddress.getByName(VIDEO_SERVER_ADDR);
            } catch (UnknownHostException e) {
                Log.e(getClass().getName(), e.getMessage());
                e.printStackTrace();
                return;
            }

            Socket socket = null;
            DataInputStream stream;

            do {
                bad_frames = 0;
                frames = 0;
                status = FrameDecodingStatus.Idle;

                try {
                    socket = new Socket(serverAddr, VIDEO_SERVER_PORT);

                    stream = new DataInputStream(new BufferedInputStream(socket.getInputStream()));

                    final byte[] _data = new byte[PACKET_SIZE];
                    final byte[] _image_data = new byte[IMAGE_SIZE];
                    int _data_index = 0;

                    while (keepRunning) {
                        if (stream.read(_data, 0, _data.length) == 0)
                            continue;

                        for (byte _byte : _data) {
                            if (status == FrameDecodingStatus.Idle) {
                               //Wait SoM
                            } else if (status == FrameDecodingStatus.Data) {
                               //Collect data
                            } else {
                                    frameReadyCallBack.frameReady(_image_data);
                                    status = FrameDecodingStatus.Idle;
                                }
                            }
                        }
                    }

                    link_respawn++;
                    Thread.sleep(VIDEO_SERVER_RESPAWN);
                    Log.d(getClass().getName(), "Link respawn: " + link_respawn);
                } catch (Throwable e) {
                    Log.e(getClass().getName(), e.getMessage());
                    e.printStackTrace();
                }
            } while (keepRunning);

            if (socket != null) {
                try {
                    socket.close();
                } catch (Throwable e) {
                    Log.e(getClass().getName(), e.getMessage());
                    e.printStackTrace();
                }
            }
        }

        public void kill() {
            keepRunning = false;
        }
    }
}

Интерфейс обратного вызова:

public interface FrameReadyCallBack {
    void frameReady(byte[] image_data);
}

Насколько я вижу, frameReady() обратный вызов никогда не вызывается и весь механизм выходит из строя.

Где ошибка?

...