Exoplayer收到警告“ SimpleExoPlayer:在错误的线程上访问了播放器。”如何解决?

时间:2019-03-15 05:37:10

标签: java android exoplayer

在Activity的mainThread中,我的图像处理器和Exo播放器(用于播放音乐)  用过的。 OS-9(Nokia)设备中的螺母无法正常工作imageHandler->连接到Workhandler的图像处理器。 代码下方: WorkHandler

public class WorkHandler extends android.os.HandlerThread {
    private Handler workHandler = null;

    private volatile List<WorkMessageProxy> messageProxyList;

    public WorkHandler() {
        super("WorkHandler", Process.THREAD_PRIORITY_BACKGROUND);
        start();
        workHandler = new Handler(getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                if (messageProxyList != null) {
                    for (WorkMessageProxy workMessageProxy : messageProxyList) {
                        Log.i("workHandler", "handleMessage: Message: " + msg.toString());
                        workMessageProxy.handleMessage(msg);
                    }
                }
            }
        };
    }


    public void post(Runnable run) {
        workHandler.post(run);
    }

    public void postAtFrontOfQueue(Runnable runnable) {
        workHandler.postAtFrontOfQueue(runnable);
    }

    public void postDelayed(Runnable runnable, long delay) {
        workHandler.postDelayed(runnable, delay);
    }

    public void postAtTime(Runnable runnable, long time) {
        workHandler.postAtTime(runnable, time);
    }

    public void addMessageProxy(WorkMessageProxy proxy) {
        initMessageProxyList();
        messageProxyList.add(proxy);
    }

    public void removeMessageProxy(WorkMessageProxy proxy) {
        initMessageProxyList();
        messageProxyList.remove(proxy);
    }

    private void initMessageProxyList() {
        if (messageProxyList == null) {
            messageProxyList = new ArrayList<>();
        }
    }

    public Handler getHandler() {
        return workHandler;
    }

    public interface WorkMessageProxy {
        void handleMessage(Message msg);
    }

}

ImageHandler

public class ImageFrameHandler implements WorkHandler.WorkMessageProxy {

    private static final String TAG = "ImageFrameHandler";
    private Resources resources;
    private int[] resArray;
    private int width;
    private int height;
    public boolean isRunning;
    public final WorkHandler workHandler;
    private File[] files;


    private static final int FILE = 0;
    private static final int RES = 1;
    private int type;
    private boolean isOpenCache;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({FILE, RES})
    public @interface Operation {
    }

    ImageFrameHandler(@Operation int type) {
        this.type = type;
        imageCache = new ImageCache();
        workHandler = new WorkHandler();
    }

    @Deprecated
    public ImageFrameHandler() {
        imageCache = new ImageCache();
        workHandler = new WorkHandler();
    }

    private ImageCache imageCache;
    private Handler handler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            if (onImageLoadListener != null) {
                onImageLoadListener.onImageLoad(bitmapDrawable);
            }
            switch (msg.what) {
                case RES:
                    load((int[]) msg.obj);
                    break;
                case FILE:
                    load((File[]) msg.obj);
                    break;
            }
        }
    };

    private volatile float frameTime;
    private volatile float delayTime;//in  millisecond
    private volatile int index = 0;
    private volatile BitmapDrawable bitmapDrawable;
    private OnImageLoadListener onImageLoadListener;
    private boolean loop;


    /**
     * load frame form file directory;
     *
     * @param width        request width
     * @param height       request height
     * @param fileDir      file directory
     * @param fps          The number of broadcast images per second
     * @param onPlayFinish finish callback
     */
    @Deprecated
    public void loadImage(final String fileDir, int width, int height, int fps,
                          OnImageLoadListener onPlayFinish) {
        if (!isRunning) {
            isRunning = true;
            this.width = width;
            this.height = height;
            loadImage(fileDir, fps, onPlayFinish);
        }

    }

    /**
     * load frame form file directory;
     *
     * @param fileDir      file directory
     * @param fps          The number of broadcast images per second
     * @param onPlayFinish finish callback
     */
    @Deprecated
    public void loadImage(final String fileDir, int fps, OnImageLoadListener onPlayFinish) {
        if (!isRunning && !TextUtils.isEmpty(fileDir) && fps > 0) {
            isRunning = true;
            File dir = new File(fileDir);
            if (dir.exists() && dir.isDirectory()) {
                File[] files = dir.listFiles();
                loadImage(files, width, height, fps, onPlayFinish);
            }
        }


    }


    /**
     * load frame form file files Array;
     *
     * @param width        request width
     * @param height       request height
     * @param files        files Array
     * @param fps          The number of broadcast images per second
     * @param onPlayFinish finish callback
     */
    @Deprecated
    public void loadImage(final File[] files, int width, int height, int fps,
                          OnImageLoadListener onPlayFinish) {
        if (!isRunning) {
            setImageFrame(files, width, height, fps, onPlayFinish);
            load(files);
        }
    }

    /**
     * load frame form file files Array;
     *
     * @param files        files Array
     * @param fps          The number of broadcast images per second
     * @param onPlayFinish finish callback
     */
    @Deprecated
    public void loadImage(final File[] files, int fps, OnImageLoadListener onPlayFinish) {
        loadImage(files, width, height, fps, onPlayFinish);
    }


    private void setImageFrame(final File[] files, int width, int height, float fps,
                               OnImageLoadListener onPlayFinish) {
        this.width = width;
        this.height = height;
        if (imageCache == null) {
            imageCache = new ImageCache();
        }
        this.onImageLoadListener = onPlayFinish;
        frameTime = 1000f / fps + 0.5f;
        workHandler.addMessageProxy(this);
        this.files = files;
    }


    /**
     * load frame form file resources Array;
     *
     * @param resArray     resources Array
     * @param width        request width
     * @param height       request height
     * @param fps          The number of broadcast images per second
     * @param onPlayFinish finish callback
     */
    @Deprecated
    public void loadImage(Resources resources, @RawRes int[] resArray, int width, int height, int fps,
                          OnImageLoadListener onPlayFinish) {
        loadImage(resources, resArray, width, height, fps, onPlayFinish);
    }

    private void setImageFrame(Resources resources, @RawRes int[] resArray, int width, int height,
                               float fps,
                               OnImageLoadListener onPlayFinish) {
        this.width = width;
        this.height = height;
        this.resources = resources;
        if (imageCache == null) {
            imageCache = new ImageCache();
        }
        this.onImageLoadListener = onPlayFinish;
        frameTime = 1000f / fps + 0.5f;
        workHandler.addMessageProxy(this);
        this.resArray = resArray;
    }

    /**
     * load frame form file resources Array;
     *
     * @param resArray     resources Array
     * @param fps          The number of broadcast images per second
     * @param onPlayFinish finish callback
     */
    @Deprecated
    public void loadImage(Resources resources, @RawRes int[] resArray, int fps,
                          OnImageLoadListener onPlayFinish) {
        if (!isRunning) {
            setImageFrame(resources, resArray, width, height, fps, onPlayFinish);
            load(resArray);
        }
    }


    /**
     * loop play frame
     *
     * @param loop true is loop
     */
    public ImageFrameHandler setLoop(boolean loop) {
        if (!isRunning) {
            this.loop = loop;
        }
        return this;
    }


    /**
     * stop play frame
     */
    public void stop() {
        workHandler.getHandler().removeCallbacksAndMessages(null);
        workHandler.removeMessageProxy(this);
        handler.removeCallbacksAndMessages(null);
        resources = null;
        isRunning = false;

        if (onImageLoadListener != null) {
            onImageLoadListener.onPlayStop();
        }
    }


public void pause() {
    isRunning = false;
    workHandler.getHandler().removeCallbacksAndMessages(null);
    // workHandler.removeMessageProxy(this);
    handler.removeCallbacksAndMessages(null);
}

public void start() {
    if (!isRunning) {
        isRunning = true;
        switch (type) {
            case FILE:
                load(files);
                break;
            case RES:
                load(resArray);
                break;
        }
    }

}

private void load(final File[] files) {
    Log.i(TAG, "load: files");
    Message message = Message.obtain();
    message.obj = files;
    message.what = FILE;
    workHandler.getHandler().sendMessage(message);
    workHandler.postDelayed(this::start, 10000);
}

private void load(@RawRes int[] res) {
    Message message = Message.obtain();
    message.obj = res;
    message.what = RES;
    workHandler.getHandler().sendMessage(message);

}


private void loadInThreadFromFile(final File[] files) {
    Log.i(TAG, "loadInThreadFromFile: " + files.length);
    Log.i(TAG, "loadInThreadFromFile: " + index);

    if (index < files.length) {
        File file = files[index];
        //Log.i(TAG, "loadInThreadFromFile: " + file != null ? file.getAbsolutePath() : "");

        if (file.isFile() && file.exists() && isPicture(file)) {
            if (bitmapDrawable != null) {
                imageCache.mReusableBitmaps.add(new SoftReference<>(bitmapDrawable.getBitmap()));
            }
            long start = System.currentTimeMillis();
            bitmapDrawable = BitmapLoadUtils.decodeSampledBitmapFromFile(file.getAbsolutePath(), width, height, imageCache, isOpenCache);
            long end = System.currentTimeMillis();

            long diff = end - start;
            //Log.i(TAG, "loadInThreadFromFile: frameTime: " + frameTime + "\tdelayTime: " + delayTime + "\tdiff=" + diff);
            //Log.i(TAG, "loadInThreadFromFile: mod:" + ANIMATED_FRAME + "~" + Math.round(ANIMATED_FRAME));
            float time = 0;
            Log.i(TAG, "loadInThreadFromFile: ANIMATED_FRAME: " + (index % Math.round(ANIMATED_FRAME)));
            if (index % Math.round(ANIMATED_FRAME) != 0) {
                time = frameTime;
            } else {
                Log.e(TAG, "Have delay @" + index);
                time = delayTime;
            }
            float updateTime = (time - diff) > 0 ? (time - diff) : 0;
            Message message = Message.obtain();
            message.what = FILE;
            message.obj = files;
            handler.sendMessageAtTime(message, (int) (SystemClock.uptimeMillis() + updateTime));
            //Log.i(TAG, "loadInThreadFromFile: updateTime:" + updateTime + "\tindex:" + index + "\tlength:" + files.length);
            index++;
        } else {
            index++;
            loadInThreadFromFile(files);
        }
    } else {
        if (loop) {
            Log.i(TAG, "loadInThreadFromFile: loop: IF");
            index = 0;

            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    loadInThreadFromFile(files);
                }
            }, (long) delayTime);

        } else {
            Log.i(TAG, "loadInThreadFromFile: loop=> " + loop);
            index++;
            bitmapDrawable = null;
            frameTime = 0;
            if (onImageLoadListener != null) {
                onImageLoadListener.onPlayFinish();
            }
            isRunning = false;
            onImageLoadListener = null;
        }

    }

    if (onImageLoadListener != null) {
        Log.i(TAG, "loadInThreadFromFile: index: " + index);
        onImageLoadListener.onIndexChange(index);
    }


}


private void loadInThreadFromRes(final int[] resIds) {
    if (index < resIds.length) {
        int resId = resIds[index];
        if (bitmapDrawable != null) {
            imageCache.mReusableBitmaps.add(new SoftReference<>(bitmapDrawable.getBitmap()));
        }
        long start = System.currentTimeMillis();
        bitmapDrawable = BitmapLoadUtils.decodeSampledBitmapFromRes(resources, resId, width, height, imageCache, isOpenCache);
        long end = System.currentTimeMillis();
        float updateTime = (frameTime - (end - start)) > 0 ? (frameTime - (end - start)) : 0;
        Message message = Message.obtain();
        message.what = RES;
        message.obj = resIds;
        handler.sendMessageAtTime(message, index == 0 ? 0 : (int) (SystemClock.uptimeMillis() + updateTime));
        index++;
    } else {
        if (loop) {
            index = 0;
            loadInThreadFromRes(resIds);
        } else {
            index++;
            bitmapDrawable = null;
            frameTime = 0;
            if (onImageLoadListener != null) {
                onImageLoadListener.onPlayFinish();
            }
            isRunning = false;
            onImageLoadListener = null;
        }
    }
}

private boolean isPicture(File file) {
    return file.getName().endsWith("png") || file.getName().endsWith("jpg");
}

@Override
public void handleMessage(Message msg) {
    switch (msg.what) {
        case RES:
            loadInThreadFromRes((int[]) msg.obj);
            break;
        case FILE:
            Log.i("ImageFrameHandler", "msg.obj; " + msg.obj.toString());
            loadInThreadFromFile((File[]) msg.obj);
            break;
    }


}

public void setFps(float fps) {
    Log.e(TAG, "setFps: " + fps);
    //frameTime = 1000f / fps + 0.5f;
    frameTime = 1000f / fps;
}

/**
 * @param dps seconds in Sec
 */
public void setDelays(float dps) {
    Log.e(TAG, "setDelays: " + dps);
    delayTime = dps * 1000.0f;
}

public void setOnImageLoaderListener(OnImageLoadListener onPlayFinish) {
    this.onImageLoadListener = onPlayFinish;
}


public interface OnImageLoadListener {
    void onImageLoad(BitmapDrawable drawable);

    void onPlayStop();

    void onPlayFinish();

    void onIndexChange(int index);
}

public static class FileHandlerBuilder implements FrameBuild {
    private int width;
    private int height;
    private float fps = 30;
    private float delays = 2;
    private File[] files;
    private OnImageLoadListener onPlayFinish;
    private ImageFrameHandler imageFrameHandler;
    private int startIndex;
    private int endIndex;

    public FileHandlerBuilder(@NonNull File[] files) {
        if (files.length == 0) {
            throw new IllegalArgumentException("fileDir is not empty");
        }
        this.files = files;
        createHandler();
    }

    public FileHandlerBuilder(@NonNull String fileDir) {
        Log.i(TAG, "FileHandlerBuilder: fileDir");
        if (TextUtils.isEmpty(fileDir)) {
            throw new IllegalArgumentException("fileDir is not empty");
        }
        File dir = new File(fileDir);
        if (dir.exists() && dir.isDirectory()) {
            files = dir.listFiles();
        }
        createHandler();
    }

    @Override
    public FrameBuild setLoop(boolean loop) {
        imageFrameHandler.setLoop(loop);
        return this;
    }

    @Override
    public FrameBuild stop() {
        imageFrameHandler.stop();
        return this;
    }

    // Just change the length of the array
    @Override
    public FrameBuild setStartIndex(int startIndex) {
        if (startIndex >= files.length) {
            throw new IllegalArgumentException("startIndex is not  big to files length");
        }
        this.startIndex = startIndex;
        return this;
    }

    @Override
    public FrameBuild setEndIndex(int endIndex) {
        if (endIndex > files.length) {
            throw new IllegalArgumentException("endIndex is not  big to files length");
        }
        if (endIndex <= startIndex) {
            throw new IllegalArgumentException("endIndex is not to small startIndex");
        }
        this.endIndex = endIndex;
        return this;
    }

    @Override
    public FrameBuild setWidth(int width) {
        this.width = width;
        return this;
    }

    @Override
    public FrameBuild setHeight(int height) {
        this.height = height;
        return this;
    }

    @Override
    public FrameBuild setFps(float fps) {
        this.fps = fps;
        imageFrameHandler.setFps(fps);
        return this;
    }

    @Override
    public FrameBuild setDelays(float dps) {
        this.delays = dps;
        imageFrameHandler.setDelays(dps);
        return this;
    }

    @Override
    public FrameBuild setOnImageLoaderListener(OnImageLoadListener onPlayFinish) {
        this.onPlayFinish = onPlayFinish;
        return this;
    }

    @Override
    public FrameBuild openLruCache(boolean isOpenCache) {
        imageFrameHandler.openLruCache(isOpenCache);
        return this;
    }

    @Override
    public ImageFrameHandler build() {
        if (!imageFrameHandler.isRunning) {
            clip();
            imageFrameHandler.setImageFrame(files, width, height, fps, onPlayFinish);
        }
        return imageFrameHandler;
    }

    private void createHandler() {
        if (imageFrameHandler == null) {
            Log.i(TAG, "createHandler: ");
            imageFrameHandler = new ImageFrameHandler(FILE);
        }
    }

    @Override
    public FrameBuild clip() {
        if (startIndex >= 0 && endIndex > 0 && startIndex < endIndex) {
            files = split(files, startIndex, endIndex);
        }
        return this;
    }

    File[] split(File[] resArray, int start, int end) {
        File[] ints = new File[end - start];
        int index = 0;
        for (int i = start; i < end; i++) {
            ints[index] = resArray[i];
            index++;
        }
        return ints;
    }
}

private void openLruCache(boolean isOpenCache) {
    this.isOpenCache = isOpenCache;
}


/**
 * Transform into build builder mode
 * <p>
 * Two kinds are file
 * Resource
 */
public static class ResourceHandlerBuilder implements FrameBuild {
    @NonNull
    private final Resources resources;
    private int width;
    private int height;
    private float fps = 30;
    private int[] resArray;
    private OnImageLoadListener onPlayFinish;
    private ImageFrameHandler imageFrameHandler;
    private int startIndex;
    private int endIndex;

    public ResourceHandlerBuilder(@NonNull Resources resources, @NonNull @RawRes int[] resArray) {
        if (resArray.length == 0) {
            throw new IllegalArgumentException("resArray is not empty");
        }
        this.resources = resources;
        this.resArray = resArray;
        createHandler();
    }

    @Override
    public FrameBuild setLoop(boolean loop) {
        imageFrameHandler.setLoop(loop);
        return this;
    }

    @Override
    public FrameBuild stop() {
        imageFrameHandler.stop();
        return this;
    }

    @Override
    public FrameBuild setStartIndex(int startIndex) {
        if (startIndex >= resArray.length) {
            throw new IllegalArgumentException("startIndex is not to big resArray length");
        }
        this.startIndex = startIndex;
        return this;
    }

    @Override
    public FrameBuild setEndIndex(int endIndex) {
        if (endIndex > resArray.length) {
            throw new IllegalArgumentException("endIndex is not  big to resArray length");
        }
        if (endIndex <= startIndex) {
            throw new IllegalArgumentException("endIndex is not to small startIndex");
        }
        this.endIndex = endIndex;
        return this;
    }

    @Override
    public FrameBuild clip() {
        if (startIndex >= 0 && endIndex > 0 && startIndex < endIndex) {
            resArray = split(resArray, startIndex, endIndex);
        }
        return this;
    }


    @Override
    public FrameBuild setWidth(int width) {
        this.width = width;
        return this;
    }

    @Override
    public FrameBuild setHeight(int height) {
        this.height = height;
        return this;
    }

    @Override
    public FrameBuild setFps(float fps) {
        this.fps = fps;
        imageFrameHandler.setFps(fps);// There is a double calculation here. I want a better way to support dynamic change later.
        return this;
    }

    @Override
    public FrameBuild setDelays(float dps) {
        return null;
    }

    @Override
    public FrameBuild openLruCache(boolean isOpenCache) {
        imageFrameHandler.openLruCache(isOpenCache);
        return this;
    }

    @Override
    public FrameBuild setOnImageLoaderListener(OnImageLoadListener onPlayFinish) {
        this.onPlayFinish = onPlayFinish;
        return this;
    }

    @Override
    public ImageFrameHandler build() {
        if (!imageFrameHandler.isRunning) {
            clip();
            imageFrameHandler.setImageFrame(resources, resArray, width, height, fps,
                    onPlayFinish);
        }
        return imageFrameHandler;
    }

    private void createHandler() {
        if (imageFrameHandler == null) {
            imageFrameHandler = new ImageFrameHandler(RES);
        }
    }

    int[] split(int[] resArray, int start, int end) {
        int[] ints = new int[end - start];
        int index = 0;
        for (int i = start; i < end; i++) {
            ints[index] = resArray[i];
            index++;
        }
        return ints;
    }
}

}

我在“活动”中同时使用了以下两种方法:

Exoplayer初始化:

private void prepareExoPlayerFromURL() {
        Log.i(TAG, "prepareExoPlayerFromURL: musicFilePath: " + musicFilePath);
        try {

            if (!FileUtils.createValidFile(musicFilePath).exists()) {
                Log.i(TAG, "[prepareExoPlayerFromURL] is not Valid File URL");
                Snackbar.make(toolbar, R.string.err_failed_to_pick_audio, Snackbar.LENGTH_LONG).show();
                onAudioRemove();
                return;
            }
            if (exoPlayer != null) {
                MediaSource mediaSource = audioSource.createMediaSource(Uri.fromFile(FileUtils.createValidFile(musicFilePath)));
                ClippingMediaSource clippingMediaSource = new ClippingMediaSource(mediaSource, 0, (long) totalDurationInSec * 1000 * 1000);
                exoPlayer.prepare(clippingMediaSource);

                btnMute.setVisibility(View.VISIBLE);
                if (exoPlayer.getVolume() > 0) {
                    btnMute.setImageResource(R.drawable.ic_unmute);
                }

                /* TODO Write Permission */
                joinAudio();
            }

        } catch (Throwable e) {
            e.printStackTrace();
        }


        //initMediaControls();
    }

**播放音乐**

private void playMusic() {
        Log.i(TAG, "playMusic: isForeGround: " + isForeGround);

        if (isForeGround && this.layLoad.getVisibility() != View.VISIBLE && this.errorView.getVisibility() != View.VISIBLE &&
                this.exoPlayer != null && !this.exoPlayer.isLoading()) {
            Log.i(TAG, "playMusic: TRUE");
            exoPlayer.seekTo(0);
            exoPlayer.setPlayWhenReady(true);
        } else {
            Log.i(TAG, "playMusic: exoPlayer is null");
        }
    }

ResetMusic当ImageHandler完成一次时:

private void resetMusic() {
        Log.i(TAG, "resetMusic: " + musicFilePath);
        if (isForeGround && this.layLoad.getVisibility() != View.VISIBLE && this.errorView.getVisibility() != View.VISIBLE &&
                this.exoPlayer != null) {

            Log.i(TAG, "resetMusic: getApplicationLooper: "+exoPlayer.getApplicationLooper().getThread().getName());
            Log.i(TAG, "resetMusic: getPlaybackLooper: "+exoPlayer.getPlaybackLooper().getThread().getName());

            Log.i(TAG, "resetMusic: TRUE");
            exoPlayer.seekTo(0);
            exoPlayer.setPlayWhenReady(true);
        } else {
            Log.i(TAG, "resetMusic: exoPlayer is null");
        }
    }

在onCreate()方法中用于Acvitiy的图像处理程序

imageFrameHandler = new ImageFrameHandler.FileHandlerBuilder(SlideShowUtility.getTempDirPath(this))
                //                .setFps((slideShowUtility.getVideoImages().size() - selectedImages.size()) * 1.0f / (selectedImages.size() - 1) * 1.0f)
                .setFps(frameRate)
                .setDelays(seconds)
                .setWidth((int) (mWidth * mulX))
                .setHeight((int) (mHeight * mulY))
                .setLoop(true)
                .build();

-> Exo播放器在位置0重置时,ResetMusic方法已发出警告。

0 个答案:

没有答案