android 多線程 切換視頻圖片使用心得

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;
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章