• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            xiaoguozi's Blog
            Pay it forword - 我并不覺的自豪,我所嘗試的事情都失敗了······習(xí)慣原本生活的人不容易改變,就算現(xiàn)狀很糟,他們也很難改變,在過程中,他們還是放棄了······他們一放棄,大家就都是輸家······讓愛傳出去,很困難,也無法預(yù)料,人們需要更細(xì)心的觀察別人,要隨時注意才能保護(hù)別人,因?yàn)樗麄兾幢刂雷约阂裁础ぁぁぁぁ?/span>

            另外一個問題就是加載速度,如果應(yīng)用中圖片加載速度很慢的話,那么用戶同樣會等到崩潰。

            那么如何處理好圖片資源的獲取和管理呢?

            異步下載

            本地緩存

            異步下載

            大家都知道,在android應(yīng)用中UI線程5秒沒響應(yīng)的話就會拋出無響應(yīng)異常,對于遠(yuǎn)程獲取大的資源來說,這種異常還是很容易就會拋出來的,那么怎么避免這種問題的產(chǎn)生。在android中提供兩種方法來做這件事情:

            啟動一個新的線程來獲取資源,完成后通過Handler機(jī)制發(fā)送消息,并在UI線程中處理消息,從而達(dá)到在異步線程中獲取圖片,然后通過Handler Message來更新UI線程的過程。

            使用android中提供的AsyncTask來完成。

            具體的做法這里就不介紹了,查下API就可以了,或者是google、baidu下。這里主要來說本地緩存。

            本地緩存

            對于圖片資源來說,你不可能讓應(yīng)用每次獲取的時候都重新到遠(yuǎn)程去下載(ListView),這樣會浪費(fèi)資源,但是你又不能讓所有圖片資源都放到內(nèi)存 中去(雖然這樣加載會比較快),因?yàn)閳D片資源往往會占用很大的內(nèi)存空間,容易導(dǎo)致OOM。那么如果下載下來的圖片保存到SDCard中,下次直接從 SDCard上去獲取呢?這也是一種做法,我看了下,還是有不少應(yīng)用采用這種方式的。采用LRU等一些算法可以保證sdcard被占用的空間只有一小部 分,這樣既保證了圖片的加載、節(jié)省了流量、又使SDCard的空間只占用了一小部分。另外一種做法是資源直接保存在內(nèi)存中,然后設(shè)置過期時間和LRU規(guī) 則。

            sdcard保存:

            在sdcard上開辟一定的空間,需要先判斷sdcard上剩余空間是否足夠,如果足夠的話就可以開辟一些空間,比如10M

            當(dāng)需要獲取圖片時,就先從sdcard上的目錄中去找,如果找到的話,使用該圖片,并更新圖片最后被使用的時間。如果找不到,通過URL去download

            去服務(wù)器端下載圖片,如果下載成功了,放入到sdcard上,并使用,如果失敗了,應(yīng)該有重試機(jī)制。比如3次。

            下載成功后保存到sdcard上,需要先判斷10M空間是否已經(jīng)用完,如果沒有用完就保存,如果空間不足就根據(jù)LRU規(guī)則刪除一些最近沒有被用戶的資源。

            關(guān)鍵代碼:

            保存圖片到SD卡上

            1. private void saveBmpToSd(Bitmap bm, Stringurl) {
            2. if (bm == null) {
            3. Log.w(TAG, " trying to savenull bitmap");
            4. return;
            5. }
            6. //判斷sdcard上的空間
            7. if (FREE_SD_SPACE_NEEDED_TO_CACHE >freeSpaceOnSd()) {
            8. Log.w(TAG, "Low free space onsd, do not cache");
            9. return;
            10. }
            11. String filename =convertUrlToFileName(url);
            12. String dir = getDirectory(filename);
            13. File file = new File(dir +"/" + filename);
            14. try {
            15. file.createNewFile();
            16. OutputStream outStream = newFileOutputStream(file);
            17. bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
            18. outStream.flush();
            19. outStream.close();
            20. Log.i(TAG, "Image saved tosd");
            21. } catch (FileNotFoundException e) {
            22. Log.w(TAG,"FileNotFoundException");
            23. } catch (IOException e) {
            24. Log.w(TAG,"IOException");
            25. }
            26. }

            計算sdcard上的空間:

            1. /**
            2. * 計算sdcard上的剩余空間
            3. * @return
            4. */
            5. private int freeSpaceOnSd() {
            6. StatFs stat = newStatFs(Environment.getExternalStorageDirectory() .getPath());
            7. double sdFreeMB = ((double)stat.getAvailableBlocks() * (double) stat.getBlockSize()) / MB;
            8. return (int) sdFreeMB;
            9. }

            修改文件的最后修改時間

            1. /**
            2. * 修改文件的最后修改時間
            3. * @param dir
            4. * @param fileName
            5. */
            6. private void updateFileTime(String dir,String fileName) {
            7. File file = new File(dir,fileName);
            8. long newModifiedTime =System.currentTimeMillis();
            9. file.setLastModified(newModifiedTime);
            10. }

            本地緩存優(yōu)化

            1. /**
            2. *計算存儲目錄下的文件大小,當(dāng)文件總大小大于規(guī)定的CACHE_SIZE或者sdcard剩余空間小于FREE_SD_SPACE_NEEDED_TO_CACHE的規(guī)定
            3. * 那么刪除40%最近沒有被使用的文件
            4. * @param dirPath
            5. * @param filename
            6. */
            7. private void removeCache(String dirPath) {
            8. File dir = new File(dirPath);
            9. File[] files = dir.listFiles();
            10. if (files == null) {
            11. return;
            12. }
            13. int dirSize = 0;
            14. for (int i = 0; i < files.length;i++) {
            15. if(files[i].getName().contains(WHOLESALE_CONV)) {
            16. dirSize += files[i].length();
            17. }
            18. }
            19. if (dirSize > CACHE_SIZE * MB ||FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
            20. int removeFactor = (int) ((0.4 *files.length) + 1);
            21. Arrays.sort(files, newFileLastModifSort());
            22. Log.i(TAG, "Clear some expiredcache files ");
            23. for (int i = 0; i <removeFactor; i++) {
            24. if(files[i].getName().contains(WHOLESALE_CONV)) {
            25. files[i].delete();
            26. }
            27. }
            28. }
            29. }
            30. /**
            31. * 刪除過期文件
            32. * @param dirPath
            33. * @param filename
            34. */
            35. private void removeExpiredCache(StringdirPath, String filename) {
            36. File file = new File(dirPath,filename);
            37. if (System.currentTimeMillis() -file.lastModified() > mTimeDiff) {
            38. Log.i(TAG, "Clear some expiredcache files ");
            39. file.delete();
            40. }
            41. }

            文件使用時間排序

            1. /**
            2. * TODO 根據(jù)文件的最后修改時間進(jìn)行排序 *
            3. */
            4. classFileLastModifSort implements Comparator<File>{
            5. public int compare(File arg0, File arg1) {
            6. if (arg0.lastModified() >arg1.lastModified()) {
            7. return 1;
            8. } else if (arg0.lastModified() ==arg1.lastModified()) {
            9. return 0;
            10. } else {
            11. return -1;
            12. }
            13. }
            14. }

            內(nèi)存保存:

            在內(nèi)存中保存的話,只能保存一定的量,而不能一直往里面放,需要設(shè)置數(shù)據(jù)的過期時間、LRU等算法。這里有一個方法是把常用的數(shù)據(jù)放到一個緩存中 (A),不常用的放到另外一個緩存中(B)。當(dāng)要獲取數(shù)據(jù)時先從A中去獲取,如果A中不存在那么再去B中獲取。B中的數(shù)據(jù)主要是A中LRU出來的數(shù)據(jù),這 里的內(nèi)存回收主要針對B內(nèi)存,從而保持A中的數(shù)據(jù)可以有效的被命中。

            先定義A緩存:

            1. private final HashMap<String, Bitmap>mHardBitmapCache = new LinkedHashMap<String, Bitmap>(HARD_CACHE_CAPACITY/ 2, 0.75f, true) {
            2. @Override
            3. protected booleanremoveEldestEntry(LinkedHashMap.Entry<String, Bitmap> eldest) {
            4. if (size() >HARD_CACHE_CAPACITY) {
            5. //當(dāng)map的size大于30時,把最近不常用的key放到mSoftBitmapCache中,從而保證mHardBitmapCache的效率
            6. mSoftBitmapCache.put(eldest.getKey(), newSoftReference<Bitmap>(eldest.getValue()));
            7. return true;
            8. } else
            9. return false;
            10. }
            11. };

            再定于B緩存:

            1. /**
            2. *當(dāng)mHardBitmapCache的key大于30的時候,會根據(jù)LRU算法把最近沒有被使用的key放入到這個緩存中。
            3. *Bitmap使用了SoftReference,當(dāng)內(nèi)存空間不足時,此cache中的bitmap會被垃圾回收掉
            4. */
            5. private final staticConcurrentHashMap<String, SoftReference<Bitmap>> mSoftBitmapCache =new ConcurrentHashMap<String,SoftReference<Bitmap>>(HARD_CACHE_CAPACITY / 2);

            從緩存中獲取數(shù)據(jù):

            1. /**
            2. * 從緩存中獲取圖片
            3. */
            4. private Bitmap getBitmapFromCache(Stringurl) {
            5. // 先從mHardBitmapCache緩存中獲取
            6. synchronized (mHardBitmapCache) {
            7. final Bitmap bitmap =mHardBitmapCache.get(url);
            8. if (bitmap != null) {
            9. //如果找到的話,把元素移到linkedhashmap的最前面,從而保證在LRU算法中是最后被刪除
            10. mHardBitmapCache.remove(url);
            11. mHardBitmapCache.put(url,bitmap);
            12. return bitmap;
            13. }
            14. }
            15. //如果mHardBitmapCache中找不到,到mSoftBitmapCache中找
            16. SoftReference<Bitmap>bitmapReference = mSoftBitmapCache.get(url);
            17. if (bitmapReference != null) {
            18. final Bitmap bitmap =bitmapReference.get();
            19. if (bitmap != null) {
            20. return bitmap;
            21. } else {
            22. mSoftBitmapCache.remove(url);
            23. }
            24. }
            25. return null;
            26. }

            如果緩存中不存在,那么就只能去服務(wù)器端去下載:

            1. /**
            2. * 異步下載圖片
            3. */
            4. class ImageDownloaderTask extendsAsyncTask<String, Void, Bitmap> {
            5. private static final int IO_BUFFER_SIZE= 4 * 1024;
            6. private String url;
            7. private finalWeakReference<ImageView> imageViewReference;
            8. public ImageDownloaderTask(ImageViewimageView) {
            9. imageViewReference = newWeakReference<ImageView>(imageView);
            10. }
            11. @Override
            12. protected BitmapdoInBackground(String... params) {
            13. final AndroidHttpClient client =AndroidHttpClient.newInstance("Android");
            14. url = params[0];
            15. final HttpGet getRequest = newHttpGet(url);
            16. try {
            17. HttpResponse response =client.execute(getRequest);
            18. final int statusCode =response.getStatusLine().getStatusCode();
            19. if (statusCode !=HttpStatus.SC_OK) {
            20. Log.w(TAG, "從" +url + "中下載圖片時出錯!,錯誤碼:" + statusCode);
            21. return null;
            22. }
            23. final HttpEntity entity =response.getEntity();
            24. if (entity != null) {
            25. InputStream inputStream =null;
            26. OutputStream outputStream =null;
            27. try {
            28. inputStream =entity.getContent();
            29. finalByteArrayOutputStream dataStream = new ByteArrayOutputStream();
            30. outputStream = newBufferedOutputStream(dataStream, IO_BUFFER_SIZE);
            31. copy(inputStream,outputStream);
            32. outputStream.flush();
            33. final byte[] data =dataStream.toByteArray();
            34. final Bitmap bitmap =BitmapFactory.decodeByteArray(data, 0, data.length);
            35. return bitmap;
            36. } finally {
            37. if (inputStream !=null) {
            38. inputStream.close();
            39. }
            40. if (outputStream !=null) {
            41. outputStream.close();
            42. }
            43. entity.consumeContent();
            44. }
            45. }
            46. } catch (IOException e) {
            47. getRequest.abort();
            48. Log.w(TAG, "I/O errorwhile retrieving bitmap from " + url, e);
            49. } catch (IllegalStateException e) {
            50. getRequest.abort();
            51. Log.w(TAG, "Incorrect URL:" + url);
            52. } catch (Exception e) {
            53. getRequest.abort();
            54. Log.w(TAG, "Error whileretrieving bitmap from " + url, e);
            55. } finally {
            56. if (client != null) {
            57. client.close();
            58. }
            59. }
            60. return null;
            61. }

            這是兩種做法,還有一些應(yīng)用在下載的時候使用了線程池和消息隊列MQ,對于圖片下載的效率要更好一些。有興趣的同學(xué)可以看下。

            總結(jié)

            對于遠(yuǎn)程圖片等相對比較大的資源一定要在異步線程中去獲取本地做緩存

            posted @ 2012-04-16 11:43 小果子 閱讀(1298) | 評論 (2)編輯 收藏
              Java 5的泛型語法已經(jīng)有太多書講了,這里不再打字貼書。GP一定有用,不然Java和C#不會約好了似的同時開始支持GP。但大家也清楚,GP和Ruby式的 動態(tài)OO語言屬于不同的意識形態(tài),如果是一人一票,我想大部分的平民程序員更熱衷動態(tài)OO語言的平白自然。但如果不準(zhǔn)備跳槽到支持JSR223的動態(tài)語 言,那還是看看GP吧。

               胡亂總結(jié)泛型的四點(diǎn)作用:
               第一是泛化,可以拿個T代表任意類型。 但GP是被C++嚴(yán)苛的靜態(tài)性逼出來的,落到Java、C#這樣的花語平原里----所有對象除幾個原始類型外都派生于Object,再加上Java的反射功能,Java的Collection庫沒有范型一樣過得好好的。

               第二是泛型 + 反射,原本因?yàn)镴ava的泛型拿不到T.class而覺得泛型沒用,最近才剛剛學(xué)到通過反射的API來獲取T的Class,后述。

               第三是收斂,就是增加了類型安全,減少了強(qiáng)制類型轉(zhuǎn)換的代碼。這點(diǎn)倒是Java Collection歷來的弱項。

               第四是可以在編譯期搞很多東西,比如MetaProgramming。但除非能完全封閉于框架內(nèi)部,框架的使用者和擴(kuò)展者都不用學(xué)習(xí)這些東西的用法,否則 那就是自絕于人民的票房毒藥。C++的MetaProgramming好厲害吧,但對比一下Python拿Meta Programming生造一個Class出來的簡便語法,就明白什么才是真正的叫好又叫座。

               所以,作為一個架構(gòu)設(shè)計師,應(yīng)該使用上述的第2,3項用法,在框架類里配合使用反射和泛型,使得框架的能力更強(qiáng); 同時采用收斂特性,本著對人民負(fù)責(zé)的精神,用泛型使框架更加類型安全,更少強(qiáng)制類型轉(zhuǎn)換。
               
               擦拭法避免了Java的流血分裂 :
                大家經(jīng)常罵Java GP的擦拭法實(shí)現(xiàn),但我覺得多虧于它的中庸特性---如果你用就是范型,不用就是普通Object,避免了Java陣營又要經(jīng)歷一場to be or not to be的分裂。 
                最大的例子莫過Java 5的Collection 框架, 比如有些同學(xué)堅持認(rèn)為自己不會白癡到類型出錯,而且難以忍受每個定義的地方都要帶一個泛型定義List〈Book〉,不用強(qiáng)制類型轉(zhuǎn)換所省下的代碼還不夠N處定義花的(對了,java里面還沒有tyepdef.....),因此對范型十分不感冒,這時就要齊齊感謝這個搽拭法讓你依然可以對一個泛型框架保持非泛型的用法了...

               通過反射獲得 T.class:
               
                不知為何書上不怎么講這個,是差沙告訴我才知道的,最經(jīng)典的應(yīng)用見Hibernate wiki的Generic Data Access Objects, 代碼如下: 
            abstract public class BaseHibernateEntityDao<T> extends HibernateDaoSupport {
             
            private Class<T> entityClass;
             
            public BaseHibernateEntityDao() {
                    entityClass 
            =(Class<T>) ((ParameterizedType) getClass()
                                            .getGenericSuperclass()).getActualTypeArguments()[0];
                }
             
            public T get(Serializable id) {
                    T o 
            = (T) getHibernateTemplate().get(entityClass, id);
            }
            }

              精華就是這句了:
            Class<T> entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 

              泛型之后,所有BaseHibernateEntityDao的子類只要定義了泛型,就無需再重載getEnttityClass(),get()函數(shù)和find()函數(shù),銷益挺明顯的,所以SpringSide的Dao基類毫不猶豫就泛型了。

              不過擦拭法的大棒仍在,所以子類的泛型語法可不能亂寫,最正確的用法只有:
                public class BookDao extends BaseHibernateEntityDao<Book>

            轉(zhuǎn)自:
            http://www.blogjava.net/calvin/archive/2009/12/10/43830.html
            posted @ 2012-04-14 21:47 小果子 閱讀(540) | 評論 (0)編輯 收藏

            ?
            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            25
            26
            27
            28
            29
            30
            31
            32
            33
            34
            35
            36
            37
            38
            39
            40
            41
            42
            43
            44
            45
            46
            47
            48
            49
            50
            51
            52
            53
            54
            55
            56
            57
            58
            59
            60
            61
            62
            63
            64
            65
            66
            67
            68
            69
            70
            71
            72
            73
            74
            75
            76
            77
            78
            79
            80
            81
            82
            83
            84
            85
            86
            87
            88
            89
            90
            91
            92
            93
            94
            95
            96
            97
            98
            99
            100
            101
            102
            103
            NotificationManager 和Notification的使用總結(jié)(轉(zhuǎn))
            文章分類:移動開發(fā)
            這 幾天一直在修改twigee的源代碼,其中一個要加入的功能是常駐Notification欄,以前寫的時候只能出現(xiàn) 在“通知”這一組中,想把它放在“正在運(yùn)行”組中卻不知道怎么放,查了下官方文檔,找到了方法,在notification的flags字段中加一下 “FLAG_ONGOING_EVENT”就可以了。同時我也把Notification的使用方法給總結(jié)了一下。詳見下文:
            (1)、使用系統(tǒng)定義的Notification
            以下是使用示例代碼:
            //創(chuàng)建一個NotificationManager的引用
            String ns = Context.NOTIFICATION_SERVICE;
            NotificationManager mNotificationManager = (NotificationManager)getSystemService(ns);
            // 定義Notification的各種屬性
            int icon = R.drawable.icon; //通知圖標(biāo)
            CharSequence tickerText = "Hello"; //狀態(tài)欄顯示的通知文本提示
            long when = System.currentTimeMillis(); //通知產(chǎn)生的時間,會在通知信息里顯示
            //用上面的屬性初始化 Nofification
            Notification notification = new Notification(icon,tickerText,when);
            /*
            * 添加聲音
            * notification.defaults |=Notification.DEFAULT_SOUND;
            * 或者使用以下幾種方式
            * notification.sound = Uri.parse("file:///sdcard/notification/ringer.mp3");
            * notification.sound = Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "6");
            * 如果想要讓聲音持續(xù)重復(fù)直到用戶對通知做出反應(yīng),則可以在notification的flags字段增加"FLAG_INSISTENT"
            * 如果notification的defaults字段包括了"DEFAULT_SOUND"屬性,則這個屬性將覆蓋sound字段中定義的聲音
            */
            /*
            * 添加振動
            * notification.defaults |= Notification.DEFAULT_VIBRATE;
            * 或者可以定義自己的振動模式:
            * long[] vibrate = {0,100,200,300}; //0毫秒后開始振動,振動100毫秒后停止,再過200毫秒后再次振動300毫秒
            * notification.vibrate = vibrate;
            * long數(shù)組可以定義成想要的任何長度
            * 如果notification的defaults字段包括了"DEFAULT_VIBRATE",則這個屬性將覆蓋vibrate字段中定義的振動
            */
            /*
            * 添加LED燈提醒
            * notification.defaults |= Notification.DEFAULT_LIGHTS;
            * 或者可以自己的LED提醒模式:
            * notification.ledARGB = 0xff00ff00;
            * notification.ledOnMS = 300; //亮的時間
            * notification.ledOffMS = 1000; //滅的時間
            * notification.flags |= Notification.FLAG_SHOW_LIGHTS;
            */
            /*
            * 更多的特征屬性
            * notification.flags |= FLAG_AUTO_CANCEL; //在通知欄上點(diǎn)擊此通知后自動清除此通知
            * notification.flags |= FLAG_INSISTENT; //重復(fù)發(fā)出聲音,直到用戶響應(yīng)此通知
            * notification.flags |= FLAG_ONGOING_EVENT; //將此通知放到通知欄的"Ongoing"即"正在運(yùn)行"組中
            * notification.flags |= FLAG_NO_CLEAR; //表明在點(diǎn)擊了通知欄中的"清除通知"后,此通知不清除,
            * //經(jīng)常與FLAG_ONGOING_EVENT一起使用
            * notification.number = 1; //number字段表示此通知代表的當(dāng)前事件數(shù)量,它將覆蓋在狀態(tài)欄圖標(biāo)的頂部
            * //如果要使用此字段,必須從1開始
            * notification.iconLevel = ; //
            */
            //設(shè)置通知的事件消息
            Context context = getApplicationContext(); //上下文
            CharSequence contentTitle = "My Notification"; //通知欄標(biāo)題
            CharSequence contentText = "Hello World!"; //通知欄內(nèi)容
            Intent notificationIntent = new Intent(this,Main.class); //點(diǎn)擊該通知后要跳轉(zhuǎn)的Activity
            PendingIntent contentIntent = PendingIntent.getActivity(this,0,notificationIntent,0);
            notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
            //把Notification傳遞給 NotificationManager
            mNotificationManager.notify(0,notification);
            如果想要更新一個通知,只需要在設(shè)置好notification之后,再次調(diào)用 setLatestEventInfo(),然后重新發(fā)送一次通知即可,即再次調(diào)用notify()。
            (2)、使用自定義的 Notification
            要 創(chuàng)建一個自定義的Notification,可以使用RemoteViews。要定義自己的擴(kuò)展消息,首先 要初始化一個RemoteViews對象,然后將它傳遞給Notification的contentView字段,再把PendingIntent傳遞給 contentIntent字段。以下示例代碼是完整步驟:
            //1、創(chuàng)建一個自 定義的消息布局 view.xml
            <?xml version="1.0" encoding="utf-8"?>
            <LinearLayout xmlns:android="
            posted @ 2012-04-05 02:34 小果子 閱讀(610) | 評論 (0)編輯 收藏
                 摘要: 關(guān)于android軟鍵盤enter鍵的替換與事件監(jiān)聽 軟件盤的界面替換只有一個屬性android:imeOptions,這個屬性的可以取的值有 normal,actionUnspecified,actionNone,actionGo,actionSearch,actionSend,actionNext,actionDone, 例如當(dāng)值為actionNext時enter鍵外觀變成一個向下箭頭,而值為...  閱讀全文
            posted @ 2012-03-28 20:54 小果子 閱讀(9908) | 評論 (1)編輯 收藏

            今天學(xué)習(xí)android自定義組件:docs/guide/topics/ui/custom-components.html

            其中有兩個對布局界面影響很的方法,onDraw(),和onMeasure().

            onDraw()比較好理解.onMeasure()就比較難理解一些,也更復(fù)雜些 ,引用文檔中的說法就是:

            onMeasure() is a little more involved.
            其實(shí)還有另一個方面的原因就是我對這個單詞measure不是很知道,然后果了下詞典,就放了下心,確實(shí)是測量的意思.

            實(shí)現(xiàn)onMeasure()方法基本需要完成下面三個方面的事情(最終結(jié)果是你自己寫相應(yīng)代碼得出測量值并調(diào)用view的一個方法進(jìn)行設(shè)置,告訴給你的view安排位置大小的父容器你要多大的空間.):

            1.傳遞進(jìn)來的參數(shù),widthMeasureSpec,和heightMeasureSpec是你對你應(yīng)該得出來的測量值的限制.

             

            The overidden onMeasure() method is called with width and height measure specifications(widthMeasureSpec and heightMeasureSpec parameters,both are integer codes representing dimensions) which should be treated as requirements for the restrictions on the width and height measurements you should produce.

            2. 你在onMeasure計算出來設(shè)置的width和height將被用來渲染組件.應(yīng)當(dāng)盡量在傳遞進(jìn)來的width和height 聲明之間.

            雖然你也可以選擇你設(shè)置的尺寸超過傳遞進(jìn)來的聲明.但是這樣的話,父容器可以選擇,如clipping,scrolling,或者拋出異常,或者(也許是用新的聲明參數(shù))再次調(diào)用onMeasure()

            Your component's onMeasure() method should calculate a measurement width and height which will be required to render the component.it should try to stay within the specified passed in.although it can choose to exceed them(in this case,the parent can choose what to do,including clipping,scrolling,throwing an excption,or asking the onMeasure to try again,perhaps with different measurement specifications).

            3.一但width和height計算好了,就應(yīng)該調(diào)用View.setMeasuredDimension(int width,int height)方法,否則將導(dǎo)致拋出異常.
            Once the width and height are calculated,the setMeasureDimension(int width,int height) method must be called with the calculated measurements.Failure to do this will result in an exceptiion being thrown
               

            在Android提提供的一個自定義View示例中(在API demos 中的 view/LabelView)可以看到一個重寫onMeasure()方法的

            實(shí)例,也比較好理解.

            01/**
            02 * @see android.view.View#measure(int, int)
            03 */
            04@Override
            05protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            06    setMeasuredDimension(measureWidth(widthMeasureSpec),
            07            measureHeight(heightMeasureSpec));
            08}
            09 
            10/**
            11 * Determines the width of this view
            12 * @param measureSpec A measureSpec packed into an int
            13 * @return The width of the view, honoring constraints from measureSpec
            14 */
            15private int measureWidth(int measureSpec) {
            16    int result = 0;
            17    int specMode = MeasureSpec.getMode(measureSpec);
            18    int specSize = MeasureSpec.getSize(measureSpec);
            19 
            20    if (specMode == MeasureSpec.EXACTLY) {
            21        // We were told how big to be
            22        result = specSize;
            23    } else {
            24        // Measure the text
            25        result = (int) mTextPaint.measureText(mText) + getPaddingLeft()
            26                + getPaddingRight();
            27        if (specMode == MeasureSpec.AT_MOST) {
            28            // Respect AT_MOST value if that was what is called for by measureSpec
            29            result = Math.min(result, specSize);
            30        }
            31    }
            32 
            33    return result;
            34}

             

            直接看measureWidth()

            首先看到的是參數(shù),分別代表寬度和高度的MeasureSpec

            android2.2文檔中對于MeasureSpec中的說明是:

            一個MeasureSpec封裝了從父容器傳遞給子容器的布局需求.

            每一個MeasureSpec代表了一個寬度,或者高度的說明.

            一個MeasureSpec是一個大小跟模式的組合值.一共有三種模式.

            A MeasureSpec encapsulates the layout requirements passed from parent to child Each MeasureSpec represents a requirement for either the width or the height.A MeasureSpec is compsized of a size and a mode.There are three possible modes:

             (1)UPSPECIFIED :父容器對于子容器沒有任何限制,子容器想要多大就多大.
            UNSPECIFIED The parent has not imposed any constraint on the child.It can be whatever size it wants

             (2) EXACTLY

             父容器已經(jīng)為子容器設(shè)置了尺寸,子容器應(yīng)當(dāng)服從這些邊界,不論子容器想要多大的空間.

            EXACTLY The parent has determined and exact size for the child.The child is going to be given those bounds regardless of how big it wants to be.

            (3) AT_MOST

             子容器可以是聲明大小內(nèi)的任意大小.

            AT_MOST The child can be as large as it wants up to the specified size

            MeasureSpec是View類下的靜態(tài)公開類,MeasureSpec中的值作為一個整型是為了減少對象的分配開支.此類用于

            將size和mode打包或者解包為一個整型.

            MeasureSpecs are implemented as ints to reduce object allocation.This class is provided to pack and unpack the size,mode tuple into the int

            我比較好奇的是怎么樣將兩個值打包到一個int中,又如何解包.

            MeasureSpec類代碼如下 :(注釋已經(jīng)被我刪除了,因?yàn)樵谏厦嬲f明了.)

            01public static class MeasureSpec {
            02    private static final int MODE_SHIFT = 30;
            03    private static final int MODE_MASK  = 0x3 << MODE_SHIFT;
            04 
            05    public static final int UNSPECIFIED = 0 << MODE_SHIFT;
            06    public static final int EXACTLY     = 1 << MODE_SHIFT;
            07    public static final int AT_MOST     = 2 << MODE_SHIFT;
            08 
            09    public static int makeMeasureSpec(int size, int mode) {
            10        return size + mode;
            11    }
            12    public static int getMode(int measureSpec) {
            13        return (measureSpec & MODE_MASK);
            14    }
            15    public static int getSize(int measureSpec) {
            16        return (measureSpec & ~MODE_MASK);
            17    }  }

            我無聊的將他們的十進(jìn)制值打印出來了:

            mode_shift=30,mode_mask=-1073741824,UNSPECIFIED=0,EXACTLY=1073741824,AT_MOST=-2147483648

            然后覺得也應(yīng)該將他們的二進(jìn)制值打印出來,如下:

            mode_shift=11110, // 30

            mode_mask=11000000000000000000000000000000,

            UNSPECIFIED=0, 

            EXACTLY=1000000000000000000000000000000, 

            AT_MOST=10000000000000000000000000000000

             

            1MODE_MASK  = 0x3 << MODE_SHIFT //也就是說MODE_MASK是由11左移30位得到的.因?yàn)镴ava用補(bǔ)碼表示數(shù)值.最后得到的值最高位是1所以就是負(fù)數(shù)了
            1 
            對于上面的數(shù)值我們應(yīng)該這樣想,不要把0x3看成3而要看成二進(jìn)制的11,

            而把MODE_SHIFF就看成30.那為什么是二進(jìn)制 的11呢?

            呢,因?yàn)橹挥腥髂J?如果有四種模式就是111了因?yàn)?11三個位才可以有四種組合對吧.

            我們這樣來看,

            UNSPECIFIED=00000000000000000000000000000000, 

                  EXACTLY=01000000000000000000000000000000, 

                AT_MOST=10000000000000000000000000000000

            也就是說,0,1,2

            對應(yīng)   00,01,10

            當(dāng)跟11想與時  00 &11 還是得到 00,11&01 -> 01,10&

            我覺得到了這個份上相信,看我博客的也都理解了.

             return (measureSpec & ~MODE_MASK);應(yīng)該是 return (measureSpec & (~MODE_MASK));

            posted @ 2012-03-27 23:59 小果子 閱讀(19810) | 評論 (4)編輯 收藏
            僅列出標(biāo)題
            共58頁: First 14 15 16 17 18 19 20 21 22 Last 
            性做久久久久久久久久久| 国产成人精品三上悠亚久久| 久久精品国产99国产精品澳门| 精品久久久久久综合日本| 99久久精品免费国产大片| 久久夜色精品国产亚洲| 久久精品国产亚洲AV高清热| 久久精品国产99久久久香蕉| 亚洲色欲久久久综合网东京热| 久久精品国产影库免费看 | 思思久久99热只有频精品66| 久久久久亚洲AV片无码下载蜜桃 | 久久最近最新中文字幕大全| 亚洲欧美日韩精品久久亚洲区 | 国产精品熟女福利久久AV| 一个色综合久久| 99国内精品久久久久久久| 久久精品中文字幕无码绿巨人| 亚洲国产精品嫩草影院久久| 精品久久久久久| 精品蜜臀久久久久99网站| 久久国产精品无| 欧美成a人片免费看久久| 情人伊人久久综合亚洲| 99久久国产热无码精品免费| 亚洲成色WWW久久网站| 99精品国产免费久久久久久下载 | 色综合久久综精品| 2021精品国产综合久久| 久久人爽人人爽人人片AV| 亚洲国产一成人久久精品| 狠狠色婷婷久久一区二区| 色妞色综合久久夜夜| 久久只有这精品99| 久久91精品国产91| 亚洲AV无码久久精品狠狠爱浪潮| 国产精品久久久久久久久久影院| 热久久视久久精品18| 成人综合久久精品色婷婷| 色诱久久久久综合网ywww | 欧美性大战久久久久久|