您的位置:首页 > 移动开发 > Android开发

android 多线程 切换视频图片使用心得

2014-08-19 16:41 507 查看
package com.tk.box.activity;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.UUID;

import android.app.Activity;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.Color;

import android.media.MediaPlayer;

import android.media.MediaPlayer.OnCompletionListener;

import android.media.MediaPlayer.OnErrorListener;

import android.media.MediaPlayer.OnPreparedListener;

import android.net.Uri;

import android.os.Bundle;

import android.os.Environment;

import android.os.Handler;

import android.os.Message;

import android.util.Log;

import android.view.Display;

import android.view.KeyEvent;

import android.widget.ImageView;

import android.widget.ImageView.ScaleType;

import android.widget.LinearLayout;

import android.widget.MediaController;

import android.widget.RelativeLayout;

import android.widget.Toast;

import android.widget.VideoView;

import com.tk.box.bo.task.AreaModel;

import com.tk.box.bo.task.MediaModel;

import com.tk.box.bo.task.TaskModel;

import com.tk.box.service.TaskService;

import com.tk.box.service.impl.TaskServiceImpl;

/**
 * 总结下 多线程的使用心得; 1 像是这种 多个布局 同时播放; 但是不同步 更新(每个布局里面的内容不一样) 肯定是 每个布局使用一个多线程进行管理;

 * 因为每个布局的播放时间不一样;不同步; 所以每个 线程里面肯定都各自有 是否改变界面的变量 以及 各自对应的 mediaList; 还有 对应的布局 ;

 * 所以构造器如下;

 *

 * public MyThread(Integer layoutId, List<MediaModel> mediaList, String

 * palyIngType, String threadId) {

 *

 * 每个布局对应一个线程; 把每个布局里面的media素材 装到 list 里面; 取出来第一个进行显示; 每个布局对应一个线程 ; 开始计时 ;

 * 在线程里面; 先 简单的sleep 一下;(原来的时候我根据不同的素材类型进行不同的sleep; 比如 在播放 素材是视频的时候; 我用变量

 * videoIsEnd 以及palyIngType 进行控制; 后来发现 不理想; 我在主线程 根据子线程的id 改变 某个子线程的 palyIngType

 * 变量的时候 发现 效果不理想;界面没有及时更新; 仔细分析了下; 很可能是 在 执行sleep代码的时候(因为sleep

 * 时间比较长;远远超过了代码执行的时间)) 比如原来的palyIngType 是image; 判断完毕进入到if

 * (!"video".equals(palyIngType)) { Thread.sleep(sleepTime);} 里面的时候;此时正在sleep;

 * 我在主线程里面改变了次线程的palyIngType 为video; 这个时候我本来想 让 界面不进行切换; 继续 播放 视频文件;

 * 也就是希望执行while ("video".equals(palyIngType) && !videoIsEnd) {//

 * 没有播放完成;Thread.sleep(sleepTime);} 这段代码; 实际上 却没有执行; 导致切换不理想;

 *

 * 解决方案: 就是在线程里面简单的sleep; 不进行逻辑的判断; 如下; 控制是否切换的逻辑在核心的 控制是否发生消息 来解决 ; 而不是在 控制睡多久来

 * 控制业务逻辑; 大不了跑一圈什么也不做;

 *

 *

 *

 *

 * 原来不好的代码如下; long sleepTime=10000; if (!"video".equals(palyIngType)) {// 图片

 * Thread.sleep(sleepTime);

 *

 * } else { // 原来播放的是视频;如果是视频的话 一直等待; 上一个 播放的是视频; 并且没有播放完; 就一直等待;

 *

 * while ("video".equals(palyIngType) && !videoIsEnd) {// 没有播放完成;

 *

 * Thread.sleep(sleepTime);

 *

 * }

 *

 *

 *

 *

 *

 */

public class InquiryMainActivity extends Activity {

    private TaskService taskService = null;

    private boolean videoIsEnd = false;

    private String TAG = "InquiryMainActivity";

    private LinearLayout videoviewlayout = null;

    private Uri mUri = null;

    private VideoView vv = null;

    private List<MyThread> threadList = new ArrayList<InquiryMainActivity.MyThread>();

    // video view begin ;

    private Handler handler = new UIHander();

    private final class UIHander extends Handler {

        private ImageView imageView = null;

        private RelativeLayout layout = null;

        public void handleMessage(Message msg) {

            switch (msg.what) {

            case 1:

            case 2:

            case 3:

                String path = msg.getData().getString("path");

                String threadId = msg.getData().getString("threadId");

                Integer currentIndex = msg.getData().getInt("currentIndex");

                Integer layoutId = msg.getData().getInt("layoutId");

                layout = (RelativeLayout) InquiryMainActivity.this

                        .findViewById(layoutId);

                layout.removeAllViews();

                if (path.endsWith(".mp4")) {// 下个播放的 是mp4

                    initVideoView();

                    layout.addView(videoviewlayout,

                            new RelativeLayout.LayoutParams(

                                    RelativeLayout.LayoutParams.FILL_PARENT,

                                    RelativeLayout.LayoutParams.FILL_PARENT));

                    for (MyThread perThread : threadList) {

                        //

                        // Log.i(TAG, threadId + "threadId便利每个 线程的id-----"

                        // + perThread.getThreadId());

                        if (threadId.equals(perThread.getThreadId())) {

                            Log.i(TAG, threadId

                                    + "的获取到threadId-----  进行 设置playType"

                                    + perThread.getThreadId());

                            perThread.setPalyIngType("video");

                            videoIsEnd = false;// 没有结束; 否则不等待;

                        }

                        // perThread.getth threadId

                    }

                    // perAreaLayout.addView(videoviewlayout, 0,

                    // new RelativeLayout.LayoutParams(

                    // RelativeLayout.LayoutParams.FILL_PARENT,

                    // RelativeLayout.LayoutParams.FILL_PARENT));

                    // palyIngType = "video";

                    showMp4();

                } else if (path.endsWith(".jpg")) {

                    imageView = new ImageView(InquiryMainActivity.this);

                    Bitmap bitmap = getLoacalBitmap(Environment

                            .getExternalStorageDirectory() + "/" + path); // 从本地取图片(在cdcard中获取)

                    imageView.setScaleType(ScaleType.FIT_XY);// 充满;

                    imageView = new ImageView(InquiryMainActivity.this);

                    imageView.setImageBitmap(bitmap);

                    layout.addView(imageView, new RelativeLayout.LayoutParams(

                            RelativeLayout.LayoutParams.FILL_PARENT,

                            RelativeLayout.LayoutParams.FILL_PARENT));

                    for (MyThread perThread : threadList) {

                        if (threadId.equals(perThread.getThreadId())) {

                            // Log.i(TAG, threadId

                            // + "的获取到threadId-----  进行 设置playType"

                            // + perThread.getThreadId());

                            perThread.setPalyIngType("image");

                            // videoIsEnd = true;//

                        }

                        // perThread.getth threadId

                    }

                } else if (path.endsWith("")) {

                }

                break;

            }

        }

       

    }

    private void initVideoView() {

        // mIntent = getIntent();

        // if (mIntent != null) {

        // 把播放地址取出来

        // mUri =mIntent.getData();

        // file:///mnt/sdcard/pptv/download/%E5%AE%AB%E9%94%81%E7%8F%A0%E5%B8%98(%E7%AC%AC06%E9%9B%86).mp4

        // mUri

        // =Uri.parse("file:///mnt/sdcard/pptv/download/%E5%AE%AB%E9%94%81%E7%8F%A0%E5%B8%98(%E7%AC%AC06%E9%9B%86).mp4");

        // mUri = Uri.parse("file:///data/data/02.avi");

        // mUri = Uri.parse("file:///data/data/01.mp4");

        mUri = Uri.parse("file:///mnt/sdcard/video/01.mp4");

        if (mUri != null) {

            // 传播放地址给播放器

            vv.setVideoURI(mUri);

        }

        // }

        // 当准备好了,会有回调

        vv.setOnPreparedListener(new OnPreparedListener() {

            @Override

            public void onPrepared(MediaPlayer mp) {

                // TODO Auto-generated method stub

                // 1,定位到上次播放的地方(seekTo());2,取消等待画面

                // 当准备好了,开始播放

                if (vv != null)

                    vv.start();

            }

        });

        // 当播放出错了,也会有一个回调

        vv.setOnErrorListener(new OnErrorListener() {

            @Override

            public boolean onError(MediaPlayer mp, int what, int extra) {

                // 进行错误处理:1,提示用户;2,重试,3,进入第三方播放器继续播放;

                Toast.makeText(InquiryMainActivity.this, "播放出错了", 1).show();

                return true;

            }

        });

        // 监听播放完成

        vv.setOnCompletionListener(new OnCompletionListener() {

            @Override

            public void onCompletion(MediaPlayer mp) {

                // 播放完成:1,退出播放器、提示用户是否进入你的软件;2,播放下一个视频

                Toast.makeText(InquiryMainActivity.this, "播放完了", 1).show();

                videoIsEnd = true;

            }

        });

        // 显示系统空间

        MediaController me = new MediaController(InquiryMainActivity.this);

        me.setPadding(200, 0, 0, 0);

        vv.setMediaController(me);

    }

    private void showMp4() {

        initVideoView();

    }

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        videoviewlayout = (LinearLayout) getLayoutInflater().inflate(

                R.layout.videoview, null); // 通过这种方式初始化布局文件;

        vv = (VideoView) videoviewlayout.findViewById(R.id.vv);

        taskService = new TaskServiceImpl(this);

        // 访问sd 卡 ;需要加上 路径;

        String path = Environment.getExternalStorageDirectory() + "/task.xml";

        TaskModel task = taskService.readTaskFromTaskXMl(path);

        if (task == null) {

            Toast.makeText(this, "读取xml文件失败", 1).show();

        } else {

            String taskname = task.getName();

            String startDate = task.getStartDate();

            String endDate = task.getEndDate();

            Integer weeks = task.getWeek();

        }

        Display mDisplay = getWindowManager().getDefaultDisplay();

        int w = mDisplay.getWidth();

        int h = mDisplay.getHeight();

        // 1920 1080 1280 752 ;

        double widthScalPercent = 1920.0 / w;

        double heightScalePercent = 1080.0 / h;

        RelativeLayout global = (RelativeLayout) getLayoutInflater().inflate(

                R.layout.inquiry_main, null);

        // TextView mTextView = new TextView(this);

        //

        // mTextView.setText("测试--------------------------");

        ImageView view = new ImageView(this);

        view.setBackgroundColor(Color.RED);

        // android.widget.RelativeLayout.LayoutParams lineimageViewlayoutParams

        // = new RelativeLayout.LayoutParams(

        // 100, 100);// 也就是设置imgaeview 的宽高; 也就是设置要添加的控件的宽高;

        // lineimageViewlayoutParams.topMargin = 100.0;// 设置上边距;

        // global.addView(view, lineimageViewlayoutParams);

        // global.addView(view, 200, 200);// 也可以通过这种设置宽高; 放前面或者后面都可以;

        setContentView(global);

        // global.addView(view, lineimageViewlayoutParams);

        List<AreaModel> areaList = task.getProgram().getAreaList();

        Integer index = 0;

        List<Integer> areIndex = new ArrayList<Integer>();

        areIndex.add(Color.RED);

        areIndex.add(Color.BLUE);

        areIndex.add(Color.GRAY);

        areIndex.add(Color.YELLOW);

        List<Map<Integer, List<MediaModel>>> mapModelList = new ArrayList<Map<Integer, List<MediaModel>>>();

        boolean isFirst = true;

        for (AreaModel area : areaList) {

            Map<Integer, List<MediaModel>> map = new HashMap<Integer, List<MediaModel>>();

            List<MediaModel> mediaList = area.getMediaModelList();

            Double height = area.getHeight();

            Double width = area.getWidth();

            Double startX = area.getStartX();

            Double startY = area.getStartY();

            Integer newHeight = (int) (height / heightScalePercent);

            Integer newWidth = (int) (width / widthScalPercent);

            Integer newstartX = (int) (startX / widthScalPercent);

            Integer newstartY = (int) (startY / heightScalePercent);

            RelativeLayout perAreaLayout = new RelativeLayout(this);

            perAreaLayout.setBackgroundColor(areIndex.get(index));

            Integer layoutId = 1000 + index;

            perAreaLayout.setId(layoutId);

            map.put(layoutId, mediaList);

            mapModelList.add(map);

            android.widget.RelativeLayout.LayoutParams arealayoutParams = new RelativeLayout.LayoutParams(

                    newWidth, newHeight);

            arealayoutParams.topMargin = newstartY;// 设置上边距;

            arealayoutParams.leftMargin = newstartX;

            String palyIngType = "";// image 图片 2 video; 正在播放的类型;

            if (mediaList != null && mediaList.size() > 0

                    && mediaList.get(0).getName().endsWith(".jpg")) {

                // 设置默认的显示;

                ImageView imageView = new ImageView(this);

                // step1 让 图片充满控件; 不仅仅要设置模式为scaleType

                imageView.setScaleType(ScaleType.FIT_XY);//

                imageView.setBackgroundResource(R.drawable.icon);

                // 有些事情必须在 addView 之前做; 否则不显示;

                // step2让 图片充满控件; // 还需要设置图片宽高都是填充父元素; 如下

                perAreaLayout.addView(imageView, 0,

                        new RelativeLayout.LayoutParams(

                                RelativeLayout.LayoutParams.FILL_PARENT,

                                RelativeLayout.LayoutParams.FILL_PARENT));

                palyIngType = "image";

            } else if (mediaList != null && mediaList.size() > 0

                    && mediaList.get(0).getName().endsWith(".mp4")) {

                perAreaLayout.addView(videoviewlayout, 0,

                        new RelativeLayout.LayoutParams(

                                RelativeLayout.LayoutParams.FILL_PARENT,

                                RelativeLayout.LayoutParams.FILL_PARENT));

                // isPlayingVideo = true;

                showMp4();

                palyIngType = "video";

                videoIsEnd = false;

            }

            global.addView(perAreaLayout, arealayoutParams);

            // Thread.sleep(time)

            MyThread thread = new MyThread(layoutId, mediaList, palyIngType,

                    (UUID.randomUUID().toString()));

            threadList.add(thread);

            thread.start();

            index++;

        }

    }

    private boolean flag = true;

    private class MyThread extends Thread {

        private String threadId = null;

        private Integer layoutId = null;

        private String palyIngType = "";// 上一个是否是播放的类型;

        public String getThreadId() {

            return threadId;

        }

        public void setPalyIngType(String palyIngType) {

            this.palyIngType = palyIngType;

        }

        List<MediaModel> mediaList = null;

        private Integer currentIndex = null;

        private RelativeLayout layout = null;

        private String threadName = "";

        public MyThread(Integer layoutId, List<MediaModel> mediaList,

                String palyIngType, String threadId) {

            this.layoutId = layoutId;

            threadName = "ThreadName-" + layoutId;

            this.threadId = threadId;

            this.mediaList = mediaList;

            layout = (RelativeLayout) InquiryMainActivity.this

                    .findViewById(layoutId);

            this.palyIngType = palyIngType;

            if (mediaList != null && mediaList.size() > 0) {

                currentIndex = 0;

            }

            // Log.i(TAG, "创建的是" + threadName + " palyIngType:" + palyIngType);

        }

        @Override

        public void run() {

            // super.run();

            // 访问sd 卡 ;需要加上 路径;

            try {

                while (flag) {

                    try {

                        long sleepTime = 10000;

                        // 有可能判断完成了; 原来是已经判断完是image; 在这里睡呢;沉睡的时候改变成为video;

                        // 导致不能等待;

                        Thread.sleep(sleepTime);

                        /**

                         * 自己感觉尽量不要在 if 语句里面判断是否进行 sleep ; 因为有可能 判断 完成之后 在sleep的

                         * 时候 进行状态的改变; 导致 判断出现不准确的情况; 我是在最后发生给主线程的消息的时候进行状态的判断;

                         * 如果播放完毕; 就 发送消息 ; 如果没有播放完成的话; 就 继续播放; 继续while 循环 ;

                         *

                         *

                         */

                        // if (!"video".equals(palyIngType)) {// 图片的话一秒跳一次;

                        // if (threadName.indexOf("002") >= 0)

                        // Log.i(TAG, threadName

                        // + "切换图片三秒------palyIngType:"

                        // + palyIngType + "threadId:" + threadId);

                        // Thread.sleep(sleepTime);

                        //

                        // } else { // 原来播放的是视频;

                        // // 如果是视频的话 一直等待; 上一个 播放的是视频; 并且没有播放完; 就一直等待;

                        // if (threadName.indexOf("002") >= 0)

                        // Log.i(TAG, threadName + "----palyIngType:-----"

                        // + palyIngType + "threadId:" + threadId);

                        // while ("video".equals(palyIngType) && !videoIsEnd)

                        // {// 没有播放完成;

                        // if (threadName.indexOf("002") >= 0)

                        // Log.i(TAG, threadName

                        // + "播放的是视频---等待三秒------palyIngType:"

                        // + palyIngType + "threadId:"

                        // + threadId);

                        // Thread.sleep(sleepTime);

                        //

                        // }

                        //

                        // }

                    } catch (Exception e) {

                        e.printStackTrace();

                    }

                    currentIndex += 1;

                    if (currentIndex >= mediaList.size()) {

                        currentIndex = 0;

                    }

                    // 下一个要播放的媒体;

                    MediaModel toBePlayedMedia = mediaList.get(currentIndex);

                    String path = toBePlayedMedia.getName();

                    if (threadName.indexOf("002") >= 0)

                        Log.i(TAG, "  发送消息前 ---------------------path:" + path

                                + "playType:" + palyIngType + "videoIsEnd"

                                + videoIsEnd);

                    // if (path.endsWith(".jpg") &&

                    // !"video".equals(palyIngType)) {// 如果上次播放的不是

                    // 视频;

                    // 并且下次播放的也是图片

                    if (path.endsWith(".jpg") && "image".equals(palyIngType)) {// 如果上次播放的不是

                        Message msg = new Message();

                        msg.what = 1;

                        msg.getData().putString("path", path);

                        msg.getData().putInt("currentIndex", currentIndex);

                        msg.getData().putInt("layoutId", layoutId);

                        msg.getData().putString("threadId", threadId);

                        handler.sendMessage(msg);

                        if (threadName.indexOf("002") >= 0)

                            Log.i(TAG,

                                    "  发送消息---------------------------------1-----palyIngTypeold:"

                                            + palyIngType + "被改为image;");

                        // palyIngType = "image";// 正在播放的是图片; 在handler 进行控制就好了;

                    } else if ("video".equals(palyIngType)

                            && path.endsWith(".jpg")) {

                        // 如果上次播放的是 视频; 并且下次播放的也是图片

                        if (threadName.indexOf("002") >= 0)

                            Log.i(TAG,

                                    "  发送消息---------------------------------2-----palyIngTypeold:---"

                                            + palyIngType + "依旧;");

                        // if (videoIsEnd) {// 因为 前面的话 有可能判断成为 image 之后

                        // Log.i(TAG, threadName + "视频--------->图片 发送消息;");

                        if (videoIsEnd) {  // 控制是否切换界面

                            Message msg = new Message();

                            msg.what = 2;

                            msg.getData().putString("path", path);

                            msg.getData().putString("palyIngType", palyIngType);// 把之前的播放类型发过去;

                            msg.getData().putInt("currentIndex", currentIndex);

                            msg.getData().putInt("layoutId", layoutId);

                            msg.getData().putString("threadId", threadId);

                            handler.sendMessage(msg);

                        }

                        // }

                        // isPlayingVideo = false;// 发送消息并且这次播放的不是视频;

                        // palyIngType = "image";//

                    } else if ("image".equals(palyIngType)

                            && path.endsWith(".mp4")) {// 图片转视频ok;

                        if (threadName.indexOf("002") >= 0)

                            Log.i(TAG,

                                    "  发送消息---------------------------------3-----palyIngTypeold:"

                                            + palyIngType + "依旧;");

                        // if (!videoIsEnd) {//

                        // 正在播放的是 图片; 下次播放视频;

                        Message msg = new Message();

                        msg.what = 3;

                        msg.getData().putString("path", path);

                        msg.getData().putString("palyIngType", palyIngType);// 把之前的播放类型发过去;

                        msg.getData().putInt("currentIndex", currentIndex);

                        msg.getData().putInt("layoutId", layoutId);

                        msg.getData().putString("threadId", threadId);

                        handler.sendMessage(msg);

                        // }

                    }

                }

            } catch (Exception e) {

                e.printStackTrace();

            }

        }

    }

    /**

     * // 测试; 具体还没有细化; 还没有细化 控制线程变量 什么的 ;

     */

    @Override

    public boolean onKeyDown(int keyCode, KeyEvent event) {

        if (keyCode == KeyEvent.KEYCODE_BACK) { // 监控/拦截/屏蔽返回键

            // do something

            // 返回键; 执行了;可以再这里进行监听;

            Log.i(TAG, "back------被执行了; 线程要关闭了 ----");

            flag = false;

            // 如果返回false 那么阻止事件继续执行;

            // return false;

        } else if (keyCode == KeyEvent.KEYCODE_MENU) {

            // 点击未执行;

            Log.i(TAG, "MENU------被执行了; 线程要关闭了 ----");

            flag = false;

            // do something

        } else if (keyCode == KeyEvent.KEYCODE_HOME) {

            // 点击未执行;

            Log.i(TAG, "KEYCODE_HOME------被执行了; 线程要关闭了 ----");

            // 这里操作是没有返回结果的

        }

        return super.onKeyDown(keyCode, event);

    }

    /**

     * 加载本地图片

     *

     * @param url

     * @return

     */

    public static Bitmap getLoacalBitmap(String url) {

        try {

            FileInputStream fis = new FileInputStream(url);

            return BitmapFactory.decodeStream(fis); // /把流转化为Bitmap图片

        } catch (FileNotFoundException e) {

            e.printStackTrace();

            return null;

        }

    }

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: