首頁(yè) 收藏 QQ群
 網(wǎng)站導(dǎo)航

ZNDS智能電視網(wǎng) 推薦當(dāng)貝市場(chǎng)

TV應(yīng)用下載 / 資源分享區(qū)

軟件下載 | 游戲 | 討論 | 電視計(jì)算器

綜合交流 / 評(píng)測(cè) / 活動(dòng)區(qū)

交流區(qū) | 測(cè)硬件 | 網(wǎng)站活動(dòng) | Z幣中心

新手入門(mén) / 進(jìn)階 / 社區(qū)互助

新手 | 你問(wèn)我答 | 免費(fèi)刷機(jī)救磚 | ROM固件

查看: 11659|回復(fù): 0
上一主題 下一主題
[教程]

Android游戲開(kāi)發(fā)之多線(xiàn)程的操作方式(二十六)

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2013-8-28 16:26 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
Android游戲開(kāi)發(fā)之多線(xiàn)程的操作方式   
     
游戲開(kāi)發(fā)與軟件開(kāi)發(fā)多線(xiàn)程的重要性   
   
      如果程序主線(xiàn)程被阻塞超過(guò)5秒,系統(tǒng)會(huì)提示“應(yīng)用程序無(wú)響應(yīng)” 這就是ANR 。 ANR的全稱(chēng)是Application Not Responding,使用多線(xiàn)程可以避免ANR。但是這里要注意一下不要為了避免ANR而過(guò)多的使用多線(xiàn)程,除非萬(wàn)不得已的情況。 比如訪(fǎng)問(wèn)網(wǎng)絡(luò)服務(wù)端返回的過(guò)慢、數(shù)據(jù)過(guò)多導(dǎo)致滑動(dòng)屏幕不流暢、或者I/O讀取過(guò)大的資源等等。這里可以開(kāi)啟一個(gè)新線(xiàn)程來(lái)處理這些耗時(shí)的操作。 如果過(guò)多使用多線(xiàn)程會(huì)出現(xiàn)數(shù)據(jù)同步的問(wèn)題須要程序員去處理,所以使用多線(xiàn)程的時(shí)候盡量保持它的獨(dú)立不會(huì)被其它線(xiàn)程干預(yù)。java語(yǔ)言提供了一個(gè)線(xiàn)程鎖的概念 synchronized 可以添加對(duì)象鎖與方法鎖專(zhuān)門(mén)避免多線(xiàn)程同時(shí)訪(fǎng)問(wèn)一個(gè)方法或者一個(gè)對(duì)象導(dǎo)致的問(wèn)題,有興趣的朋友可以去看看這里我不羅嗦啦 。   
   
   
1.Thread與Handler執(zhí)行多線(xiàn)程   
     
   
Handler主要用于程序主線(xiàn)程與我們自己創(chuàng)建的線(xiàn)程進(jìn)行通信。在這個(gè)例子中點(diǎn)擊按鈕后創(chuàng)建一個(gè)新的線(xiàn)程去循環(huán)的加載100張圖片每加載完一張圖片在Thread中使用Handler發(fā)送消息通知UI線(xiàn)程更新顯示,直到加在完畢通知UI顯示加載完成一共耗時(shí)多少秒。可見(jiàn)Handler的重要性它就是主線(xiàn)程與我們自己創(chuàng)建的線(xiàn)程的橋梁啊~~~   
  1. import java.io.InputStream;   
       
    import android.app.Activity;   
    import android.content.Context;   
    import android.graphics.Bitmap;   
    import android.graphics.BitmapFactory;   
    import android.os.Bundle;   
    import android.os.Handler;   
    import android.os.Message;   
    import android.view.View;   
    import android.view.View.OnClickListener;   
    import android.widget.Button;   
    import android.widget.TextView;   
       
    public class SingleActivity extends Activity {   
       
        /**讀取進(jìn)度**/   
        public final static int LOAD_PROGRESS = 0;   
          
        /**標(biāo)志讀取進(jìn)度結(jié)束**/   
        public final static int LOAD_COMPLETE = 1;   
          
          
        /** 開(kāi)始加載100張圖片按鈕 **/   
        Button mButton = null;   
        /** 顯示內(nèi)容 **/   
        TextView mTextView = null;   
        /** 加載圖片前的時(shí)間 **/   
        Long mLoadStatr = 0L;   
        /** 加載圖片后的時(shí)間 **/   
        Long mLoadEnd = 0L;   
       
        Context mContext = null;   
       
        //接收傳遞過(guò)來(lái)的信息   
        Handler handler = new Handler() {   
            @Override   
            public void handleMessage(Message msg) {   
                switch (msg.what) {   
                case LOAD_PROGRESS:   
                    mTextView.setText("當(dāng)前讀取到第" + msg.arg1 + "張圖片");   
                    break;   
                case LOAD_COMPLETE:   
                    mTextView.setText("讀取結(jié)束一共耗時(shí)" + msg.arg1 + "毫秒");   
                    break;   
                }   
                super.handleMessage(msg);   
            }   
        };   
       
        @Override   
        protected void onCreate(Bundle savedInstanceState) {   
            setContentView(R.layout.single);   
            mContext = this;   
       
            /** 拿到button 與 TextView 對(duì)象 **/   
            mButton = (Button) findViewById(R.id.button0);   
            mTextView = (TextView) findViewById(R.id.textView0);   
            mTextView.setText("點(diǎn)擊按鈕開(kāi)始更新時(shí)間");   
            mButton.setOnClickListener(new OnClickListener() {   
                @Override   
                public void onClick(View arg0) {   
                    //開(kāi)始讀取圖片   
                    LoadImage();   
                }   
            });   
       
               
            super.onCreate(savedInstanceState);   
        }   
       
        public void LoadImage() {   
            new Thread() {   
                @Override   
                public void run() {   
                    //得到加載圖片開(kāi)始的時(shí)間   
                    mLoadStatr = System.currentTimeMillis();   
                      
                    for (int i = 0; i < 100; i++) {   
                        // 這里循環(huán)加載圖片100遍   
                        ReadBitMap(mContext, R.drawable.bg);   
       
                        // 每讀取完一張圖片將進(jìn)度甩給handler   
                        Message msg = new Message();   
                        msg.what = LOAD_PROGRESS;   
                        msg.arg1 = i + 1;   
                        handler.sendMessage(msg);   
                    }   
                      
                    //得到加載圖片結(jié)束的時(shí)間   
                    mLoadEnd = System.currentTimeMillis();   
                      
                    //100張圖片加載完成   
                    Message msg = new Message();   
                    msg.what = LOAD_COMPLETE;   
                    msg.arg1 = (int) (mLoadEnd - mLoadStatr);   
                    handler.sendMessage(msg);   
                }   
            }.start();   
       
        }   
       
        /**   
         * 讀取本地資源的圖片   
         *   
         * @param context   
         * @param resId   
         * @return   
         */   
        public Bitmap ReadBitMap(Context context, int resId) {   
            BitmapFactory.Options opt = new BitmapFactory.Options();   
            opt.inPreferredConfig = Bitmap.Config.RGB_565;   
            opt.inPurgeable = true;   
            opt.inInputShareable = true;   
            // 獲取資源圖片   
            InputStream is = context.getResources().openRawResource(resId);   
            return BitmapFactory.decodeStream(is, null, opt);   
        }   
    }
復(fù)制代碼
2.TimerTask與Handler延遲多線(xiàn)程   
     
Timer與TimerTask可以構(gòu)建一個(gè)延遲器 就好比開(kāi)啟一個(gè)線(xiàn)程每隔一段規(guī)定的時(shí)間訪(fǎng)問(wèn)一次。可以在這個(gè)線(xiàn)程中去關(guān)閉這個(gè)Timer 與TimerTask ,舉個(gè)例子比如現(xiàn)在我要做一個(gè)網(wǎng)游帳號(hào)登錄超時(shí)客戶(hù)端的檢測(cè) 用戶(hù)輸入完帳號(hào)密碼點(diǎn)擊登錄這時(shí)候我開(kāi)啟一個(gè)TimerTask每過(guò)1秒檢查一下用戶(hù)是否登錄成功,過(guò)了10秒如果還沒(méi)有登錄成功提示他登陸超時(shí)。這個(gè)時(shí)候我就須要在這個(gè)檢測(cè)線(xiàn)程中去關(guān)閉Timer 與TimerTask  因?yàn)椴恍枰谘h(huán)檢測(cè)了。 調(diào)用cancel()就可以關(guān)閉,請(qǐng)同學(xué)們閱讀下面這個(gè)例子。   
  1. import java.util.Timer;   
    import java.util.TimerTask;   
    import android.app.Activity;   
    import android.content.Context;   
    import android.os.Bundle;   
    import android.os.Handler;   
    import android.os.Message;   
    import android.view.View;   
    import android.view.View.OnClickListener;   
    import android.widget.Button;   
    import android.widget.TextView;   
       
    public class TimerTaskActivity extends Activity {   
       
        /**執(zhí)行Timer進(jìn)度**/   
        public final static int LOAD_PROGRESS = 0;   
          
        /**關(guān)閉Timer進(jìn)度**/   
        public final static int CLOSE_PROGRESS = 1;   
          
        /** 開(kāi)始TimerTask按鈕 **/   
        Button mButton0 = null;   
          
        /** 關(guān)閉TimerTask按鈕 **/   
        Button mButton1 = null;   
          
        /** 顯示內(nèi)容 **/   
        TextView mTextView = null;   
       
        Context mContext = null;   
       
        /**Timer對(duì)象**/   
        Timer mTimer = null;   
          
        /**TimerTask對(duì)象**/   
        TimerTask mTimerTask = null;   
          
        /**記錄TimerID**/   
        int mTimerID = 0;   
          
          
        /**接收傳遞過(guò)來(lái)的信息**/   
        Handler handler = new Handler() {   
            @Override   
            public void handleMessage(Message msg) {   
                switch (msg.what) {   
                case LOAD_PROGRESS:   
                    mTextView.setText("當(dāng)前TimerID為" + msg.arg1 );   
                    break;   
                case CLOSE_PROGRESS:   
                    mTextView.setText("當(dāng)前Timer已經(jīng)關(guān)閉請(qǐng)重新開(kāi)啟" );   
                    break;   
                   
                }   
                super.handleMessage(msg);   
            }   
        };   
       
        @Override   
        protected void onCreate(Bundle savedInstanceState) {   
            setContentView(R.layout.timer);   
            mContext = this;   
       
            /** 拿到button 與 TextView 對(duì)象 **/   
            mButton0 = (Button) findViewById(R.id.button0);   
            mButton1 = (Button) findViewById(R.id.button1);   
            mTextView = (TextView) findViewById(R.id.textView0);   
            mTextView.setText("點(diǎn)擊按鈕開(kāi)始更新時(shí)間");   
               
            //開(kāi)始   
            mButton0.setOnClickListener(new OnClickListener() {   
                @Override   
                public void onClick(View arg0) {   
                    //開(kāi)始執(zhí)行timer   
                    StartTimer();   
                }   
            });   
       
            //關(guān)閉   
            mButton1.setOnClickListener(new OnClickListener() {   
                @Override   
                public void onClick(View arg0) {   
                    //停止執(zhí)行timer   
                    CloseTimer();   
                }   
            });   
               
            super.onCreate(savedInstanceState);   
        }   
       
        public void StartTimer() {   
       
            if (mTimer == null) {   
                mTimerTask = new TimerTask() {   
                    public void run() {   
                        //mTimerTask與mTimer執(zhí)行的前提下每過(guò)1秒進(jìn)一次這里   
                        mTimerID ++;   
                        Message msg = new Message();   
                        msg.what = LOAD_PROGRESS;   
                        msg.arg1 = (int) (mTimerID);   
                        handler.sendMessage(msg);   
                    }   
                };   
                mTimer = new Timer();   
                
                //第一個(gè)參數(shù)為執(zhí)行的mTimerTask   
                //第二個(gè)參數(shù)為延遲的時(shí)間 這里寫(xiě)1000的意思是mTimerTask將延遲1秒執(zhí)行   
                //第三個(gè)參數(shù)為多久執(zhí)行一次 這里寫(xiě)1000表示每1秒執(zhí)行一次mTimerTask的Run方法   
                mTimer.schedule(mTimerTask, 1000, 1000);   
            }   
       
        }   
       
        public void CloseTimer() {   
       
            //在這里關(guān)閉mTimer 與 mTimerTask   
            if (mTimer != null) {   
                mTimer.cancel();   
                mTimer = null;   
            }   
            if (mTimerTask != null) {   
                mTimerTask = null;   
            }   
               
            /**ID重置**/   
            mTimerID = 0;   
               
            //這里發(fā)送一條只帶what空的消息   
            handler.sendEmptyMessage(CLOSE_PROGRESS);   
        }   
    }
復(fù)制代碼
3.AsyncTask執(zhí)行多線(xiàn)程   
   
     
   
   
執(zhí)行AsyncTask   
onPreExecute()///首先執(zhí)行這個(gè)方法,它在UI線(xiàn)程中 可以執(zhí)行一些異步操作 比如初始化一些東西   
doInBackground(Object... arg0) //異步后臺(tái)執(zhí)行 ,執(zhí)行完畢可以返回出去一個(gè)結(jié)果object對(duì)象   
onPostExecute(Object result) //可以拿到執(zhí)行中的進(jìn)度 當(dāng)然進(jìn)度須要在doInBackground中手動(dòng)調(diào)用publishProgress()方法返回   
   
通過(guò)例子可以清楚的看到計(jì)算出讀取100張圖片的時(shí)間,執(zhí)行的效率上來(lái)說(shuō)AsyncTask 沒(méi)有Thread效率塊,但是AsyncTask 比Thread更規(guī)整,它可是時(shí)時(shí)的拿到異步線(xiàn)程中進(jìn)度以及最后的結(jié)果集,可以讓我們的代碼更佳規(guī)范。這里說(shuō)一下 Thread能做到的事AsyncTask 都可以做到 但是AsyncTask  能做到的事Thread 不一定能做到就算勉強(qiáng)做到也很麻煩 。我給大家的建議是如果處理大量的異步操作就用AsyncTask 如果少部分的則使用Thread   
  1. import java.io.InputStream;   
    import java.util.Timer;   
    import java.util.TimerTask;   
    import android.app.Activity;   
    import android.content.Context;   
    import android.graphics.Bitmap;   
    import android.graphics.BitmapFactory;   
    import android.os.AsyncTask;   
    import android.os.Bundle;   
    import android.view.View;   
    import android.view.View.OnClickListener;   
    import android.widget.Button;   
    import android.widget.TextView;   
       
    public class AsyncTaskActivity extends Activity {   
       
        /**執(zhí)行Timer進(jìn)度**/   
        public final static int LOAD_PROGRESS = 0;   
          
        /**關(guān)閉Timer進(jìn)度**/   
        public final static int CLOSE_PROGRESS = 1;   
          
        /** 開(kāi)始StartAsync按鈕 **/   
        Button mButton0 = null;   
          
          
        /** 顯示內(nèi)容 **/   
        TextView mTextView = null;   
       
        Context mContext = null;   
       
        /**Timer對(duì)象**/   
        Timer mTimer = null;   
          
        /**TimerTask對(duì)象**/   
        TimerTask mTimerTask = null;   
          
        /**記錄TimerID**/   
        int mTimerID = 0;   
       
        @Override   
        protected void onCreate(Bundle savedInstanceState) {   
            setContentView(R.layout.async);   
            mContext = this;   
       
            /** 拿到button 與 TextView 對(duì)象 **/   
            mButton0 = (Button) findViewById(R.id.button0);   
            mTextView = (TextView) findViewById(R.id.textView0);   
            //開(kāi)始   
            mButton0.setOnClickListener(new OnClickListener() {   
                @Override   
                public void onClick(View arg0) {   
                    //開(kāi)始執(zhí)行StartAsync   
                    StartAsync();   
                }   
            });   
       
               
            super.onCreate(savedInstanceState);   
        }   
       
        public void StartAsync() {   
            new AsyncTask<Object, Object, Object>() {   
                  
                @Override   
                protected void onPreExecute() {   
                    //首先執(zhí)行這個(gè)方法,它在UI線(xiàn)程中 可以執(zhí)行一些異步操作   
                    mTextView.setText("開(kāi)始加載進(jìn)度");   
                    super.onPreExecute();   
                }   
       
                @Override   
                protected Object doInBackground(Object... arg0) {   
                    //異步后臺(tái)執(zhí)行 ,執(zhí)行完畢可以返回出去一個(gè)結(jié)果object對(duì)象   
                      
                    //得到開(kāi)始加載的時(shí)間   
                    Long startTime = System.currentTimeMillis();   
                    for (int i = 0; i < 100; i++) {   
                        // 這里循環(huán)加載圖片100遍   
                        ReadBitMap(mContext, R.drawable.bg);   
                        //執(zhí)行這個(gè)方法會(huì)異步調(diào)用onProgressUpdate方法,可以用來(lái)更新UI   
                        publishProgress(i);   
                    }   
                    //得到結(jié)束加載的時(shí)間   
                    Long endTime = System.currentTimeMillis();   
                      
                    //將讀取時(shí)間返回   
                    return endTime - startTime;   
                }   
       
                @Override   
                protected void onPostExecute(Object result) {   
                    //doInBackground之行結(jié)束以后在這里可以接收到返回的結(jié)果對(duì)象   
                      
                    mTextView.setText("讀取100張圖片一共耗時(shí)" + result+ "毫秒");   
                      
                    super.onPostExecute(result);   
                }   
                   
                   
                @Override   
                protected void onProgressUpdate(Object... values) {   
                    //時(shí)時(shí)拿到當(dāng)前的進(jìn)度更新UI   
                      
                    mTextView.setText("當(dāng)前加載進(jìn)度" + values[0]);   
                    super.onProgressUpdate(values);   
                }   
            }.execute();//可以理解為執(zhí)行 這個(gè)AsyncTask   
       
        }   
        /**   
         * 讀取本地資源的圖片   
         *   
         * @param context   
         * @param resId   
         * @return   
         */   
        public Bitmap ReadBitMap(Context context, int resId) {   
            BitmapFactory.Options opt = new BitmapFactory.Options();   
            opt.inPreferredConfig = Bitmap.Config.RGB_565;   
            opt.inPurgeable = true;   
            opt.inInputShareable = true;   
            // 獲取資源圖片   
            InputStream is = context.getResources().openRawResource(resId);   
            return BitmapFactory.decodeStream(is, null, opt);   
        }   
    }
復(fù)制代碼
4.多線(xiàn)程Looper的使用   
     
Looper用來(lái)管理線(xiàn)程的消息隊(duì)列與循環(huán)隊(duì)列,在handler中默認(rèn)為mainlooper來(lái)進(jìn)行消息循環(huán),如果在handler中開(kāi)啟一個(gè)新的線(xiàn)程那么在這個(gè)新的線(xiàn)程中就沒(méi)有Looper循環(huán),如果想讓這個(gè)新的線(xiàn)程具有消息隊(duì)列與消息循環(huán)我們須要調(diào)用 Looper.prepare();拿到它的loop ,這樣就好比在Thread中創(chuàng)建了消息隊(duì)列與循環(huán)  需要調(diào)用   Looper.loop(); 它的意思就是執(zhí)行這個(gè)消息循環(huán),下面我給出一個(gè)例子希望大家好好閱讀。   
  1. import java.io.InputStream;   
       
    import android.app.Activity;   
    import android.content.Context;   
    import android.graphics.Bitmap;   
    import android.graphics.BitmapFactory;   
    import android.os.Bundle;   
    import android.os.Handler;   
    import android.os.Looper;   
    import android.os.Message;   
    import android.view.View;   
    import android.view.View.OnClickListener;   
    import android.widget.Button;   
    import android.widget.Toast;   
       
    public class LooperActivity extends Activity {   
        /** 發(fā)送消息按鈕 **/   
        Button mButton = null;   
        /** 加載圖片前的時(shí)間 **/   
        Long mLoadStatr = 0L;   
        /** 加載圖片后的時(shí)間 **/   
        Long mLoadEnd = 0L;   
       
        Context mContext = null;   
       
        private Handler handler = new Handler() {   
            public void handleMessage(Message msg) {   
                new Thread() {   
                    @Override   
                    public void run() {   
                         
                        //如果handler不指定looper的話(huà)   
                        //默認(rèn)為mainlooper來(lái)進(jìn)行消息循環(huán),   
                        //而當(dāng)前是在一個(gè)新的線(xiàn)程中它沒(méi)有默認(rèn)的looper   
                        //所以我們須要手動(dòng)調(diào)用prepare()拿到他的loop   
                        //可以理解為在Thread創(chuàng)建Looper的消息隊(duì)列   
                        Looper.prepare();   
                           
                           
                        Toast.makeText(LooperActivity.this, "收到消息",Toast.LENGTH_LONG).show();   
                         
                           
                        //在這里執(zhí)行這個(gè)消息循環(huán)如果沒(méi)有這句   
                        //就好比只創(chuàng)建了Looper的消息隊(duì)列而   
                        //沒(méi)有執(zhí)行這個(gè)隊(duì)列那么上面Toast的內(nèi)容是不會(huì)顯示出來(lái)的   
                        Looper.loop();   
                      
                      
                      
                      
                    //如果沒(méi)有   Looper.prepare();  與 Looper.loop();   
                    //會(huì)拋出異常Cant create handler inside thread that has not called Looper.prepare()      
                    //原因是我們新起的線(xiàn)程中是沒(méi)有默認(rèn)的looper所以須要手動(dòng)調(diào)用prepare()拿到他的loop   
                      
                    }   
                }.start();   
            }   
            };   
               
        @Override   
        protected void onCreate(Bundle savedInstanceState) {   
            setContentView(R.layout.loop);   
            mContext = this;   
       
            /** 拿到button 與 TextView 對(duì)象 **/   
            mButton = (Button) findViewById(R.id.button0);   
            mButton.setOnClickListener(new OnClickListener() {   
                @Override   
                public void onClick(View arg0) {   
                    new Thread() {   
                        @Override   
                        public void run() {   
                      
                                //發(fā)送一條空的消息   
                                //空消息中必需帶一個(gè)what字段   
                                //用于在handler中接收   
                                //這里暫時(shí)我先寫(xiě)成0   
                                handler.sendEmptyMessage(0);   
                      
                        }   
                    }.start();   
                }   
            });   
       
               
            super.onCreate(savedInstanceState);   
        }   
        /**   
         * 讀取本地資源的圖片   
         *   
         * @param context   
         * @param resId   
         * @return   
         */   
        public Bitmap ReadBitMap(Context context, int resId) {   
            BitmapFactory.Options opt = new BitmapFactory.Options();   
            opt.inPreferredConfig = Bitmap.Config.RGB_565;   
            opt.inPurgeable = true;   
            opt.inInputShareable = true;   
            // 獲取資源圖片   
            InputStream is = context.getResources().openRawResource(resId);   
            return BitmapFactory.decodeStream(is, null, opt);   
        }   
    }
復(fù)制代碼
老規(guī)矩每篇文章都會(huì)附帶源代碼,最后如果你還是覺(jué)得我寫(xiě)的不夠詳細(xì) 看的不夠爽 不要緊我把源代碼的下載地址貼出來(lái) 歡迎大家一起討論學(xué)習(xí)   
第十六講多線(xiàn)程的操作方式.rar(375.16 KB, 下載次數(shù): 453)[/I]2011-9-3 01:03 上傳點(diǎn)擊文件名   下載積分: 下載豆 -2

上一篇:android讀取excel的數(shù)據(jù)
下一篇:Android 軟件開(kāi)發(fā)之?dāng)?shù)據(jù)的 新建 儲(chǔ)存 讀取 刪除 詳解(十四)

本版積分規(guī)則

Archiver|新帖|標(biāo)簽|軟件|Sitemap|ZNDS智能電視網(wǎng) ( 蘇ICP備2023012627號(hào) )

網(wǎng)絡(luò)信息服務(wù)信用承諾書(shū) | 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證:蘇B2-20221768 丨 蘇公網(wǎng)安備 32011402011373號(hào)

GMT+8, 2024-10-21 09:41 , Processed in 0.086266 second(s), 17 queries , Redis On.

Powered by Discuz!

監(jiān)督舉報(bào):report#znds.com (請(qǐng)將#替換為@)

© 2007-2024 ZNDS.Com

快速回復(fù) 返回頂部 返回列表