<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    amp@java

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      99 隨筆 :: 0 文章 :: 228 評論 :: 0 Trackbacks

    2008年2月1日 #

    當年是從CSDN博客遷過來的,因為那里很不穩定,那時候這里很火的;
    前段時間發現,Blogjava的登錄頁面居然沒有驗證碼了,圖片顯示錯誤,無法登錄,預感這個地方要涼,只好到處找替代,但沒找到好用的博客,github是一個選項,但似乎不是很適合做博客。
    現在終于又可以登錄了,不過首頁居然只剩一篇文章,我以為數據都沒了,登錄發現還是有的,不過太讓人不放心了。
    posted @ 2018-08-18 22:14 amp@java 閱讀(149) | 評論 (0)編輯 收藏

     昨天下午開始,之前用得好好的USB鼠標,突然不能用了,找到個PS/2鼠標,卻發現主板沒有鼠標的PS/2口,只有鍵盤的PS/2口,真是奇葩,幸好在用的鍵盤是PS/2口的,費了九牛二虎之力,用鍵盤操作,Win+R,compmgmt.msc進入計算機管理,上下箭頭移到設備管理器,發現右邊的USB控制器前全是黃色嘆號,嘗試卸載再安裝,卻怎么也裝不上,重新啟動發現鼠標在啟動Windows前還是亮燈的,但到了顯示Windows徽標的時候燈就滅了,應該不是硬件問題,而是驅動問題。
    為了進一步證實硬件沒問題,找了個安裝系統的U盤,插進去啟動,能夠正常使用鼠標,于是目標就聚焦在找回驅動上。
    開始折騰:
    1、首先是找官方驅動啊,我這電腦是老機,AMD7系列主板,找了半天,這個主板驅動并沒有包含USB控制器,因為USB控制器都是Windows自帶的驅動,下載了一個南橋驅動,安裝后并沒有效果;
    2、Windows自帶的驅動原來都是放在C:\Windows\System32\DriverStore\FileRepository下,USB控制器相關的驅動,就在usbport.inf_amd64_xxxxxxxxxx文件夾里,xxxxxxxxx是一串16進制數字,悲催的是,安裝這個驅動時要不提示找不到指定文件,要不說第三方INF沒有簽名;
    3、自己折騰搞不定,找個軟件吧,第一個想到的是驅動之家官方的驅動精靈,下載下來發現是個全家桶啊,什么騰訊管家,金山毒霸,瀏覽器首頁修改一應俱全,而且沒有鼠標點擊,用TAB鍵根本移動不到取消框,只好默認全部安裝了,裝完啟動,檢測,提示系統自帶驅動缺失,于是回車修復,但每次修復完,重新檢測還是那樣,而且沒有提示USB控制器驅動安裝有問題,有些功能用鍵盤無法操作,不知道是不是還有哪里可以操作一下,于是又搜了一下,如何用鍵盤代替鼠標,居然真的找到了!
    4、按WIN鍵,輸入設置,回車,打開設置主頁:

    移到“輕松使用”,進去后左邊選擇“鼠標”,在右邊啟用“使用數字小鍵盤在屏幕上移動鼠標”(按空格鍵開關),最好把三個開關都打開,如果沒有啟用CTRL鍵加速功能,鼠標移動非常慢:

    好了,現在可以用小鍵盤移動鼠標了;
    5、繼續回到驅動精靈,再次修復,還是不行啊,這個東西除了帶來一堆垃圾,什么作用都沒有!于是把它帶來的垃圾以及它自己卸載了。
    6、似乎360也有一個驅動大師,于是就下載了一個,這個倒是很純潔,但是功能太弱,完全沒發現問題;
    7、剛才搜索“安裝驅動 找不到指定的文件”時,發現一個論壇提到了這個,是驅動人生的論壇,好像還有解決方案,但要注冊才能下載,難道驅動人生可以解決?于是就下載了一個驅動人生,安裝的時候還是附帶全家桶,不過現在可以用鍵盤移動鼠標取消了,只安裝了驅動人生自己,跟剛才兩個軟件不同的是,它提示USB外設驅動沒有安裝,于是點修復,結果反反復復出現等待光標,就是無法完成;
    8、之前又搜索到,驅動安裝的日志在C:\Windows\INF\setupapi.dev.log文件里,于是打開這個文件,發現Driver package failed signature verification. Error = 0xE000022F,驅動程序簽名有問題,所以不能安裝成功;
    9、Windows10有個高級啟動選項是禁用強制驅動簽名,如何進入高級啟動選項呢?以前是按F8,現在不行了,要在設置里面,更新和安全,恢復,高級啟動,立即重啟,然后設置疑難解答,高級啟動,再重啟,就可以進入高級啟動菜單,按7進入禁止強制驅動簽名模式,重啟后再用驅動人生修復,果然成功了;
    10、打開驅動人生下載目錄,DTLFolder\DriversDownLoad,發現它下載了USB驅動目錄是USB_10.0.10240.16384_WHQL_107049,里面文件如下:

    除了第一個xml文件是程序自己用的外,其他都是USB驅動用到的文件,點右鍵發現那幾個sys文件,除了usbohci.sys和usbuhci.sys外,其他都有數字簽名,而usbuhci.sys我這里沒用到,問題就出在usbohci.sys上:


    11、難道是驅動人生替換了未簽名的文件?圖謀不軌?為了驗證一下,我又下載了一個Windows10安裝光盤(版本是當前使用的1703版):
    cn_windows_10_multiple_editions_version_1703_updated_march_2017_x64_dvd_10194190.iso
    12、怎么提取安裝光盤中的內置驅動?找了一下,原來Windows的安裝盤從VISTA起,不再使用XP以前的I386目錄和Drivers.cab文件存放驅動,而是打包在一個Install.wim鏡像文件中,要找到驅動文件,必須用工具提取,這個工具就是Imagex.exe,微軟自己做的命令行工具,但是我的電腦上沒有,于是下載了一個64位的,放在C盤根目錄,通過如下命令即可提取:
    c:\IMAGEX_x64 /mount f:\sources\install.wim 5 i:\1703
    其中F盤是在iso文件上點右鍵,打開方式選“Windows資源管理器”打開后虛擬出來的盤符,其實就相當于系統自帶的虛擬光驅,I盤是硬盤,用來存放掛載的鏡像文件,5是選擇掛載哪一個版本的Windows(多合一版),如果不知道要掛哪個,把這個數字改成100,會顯示xml文件內容,并提示找不到這個索引號,從xml文件內容就能找到各版本的信息,然后再重新掛載正確的即可。這個掛載其實是個解壓縮過程,時間很長,提取完之后就跟安裝好了Windows一樣,目錄都列好了。
    今天又發現另一個圖形化的工具,Dism++,比這個操作更簡單。Dism是PowerShell內置的命令,也是與鏡像有關,也能掛載提取,但用了一下似乎提示權限有問題,Dism++是國內開源愛好者自己開發的圖形化工具,與Dism沒有關系。
    13、好了,原版的Windows已經準備好,進入Windows\System32\DriverStore\FileRepository目錄,搜索usbohci.sys,在usbport.inf_amd64_8e5f608c0111283d目錄下,點右鍵一看,也是沒簽名的:
    這不是坑爹嗎?你自己帶的東西都沒簽名,然后又不給用!!!!
    14、有點懷疑是Windows自己更新的時候修改了一些策略,導致之前可以用的不能用了,為了再次驗證,又繼續下載了兩個版本的Windows10安裝光盤,分別是早期的1607和最新的1709,找到usbohci.sys,如下所示:
    從左到右依次為1607,1703,1709,均未簽名,基本可以判斷是Windows自己抽風了。
    15、昨天晚上搞到12點多,搞定鼠標后沒有重啟測試,今天早上開機,果然發現鼠標又不能用了,因為我沒有選擇禁用強制簽名選項來啟動,系統發現那個沒簽名的驅動,就把它停了,嘗試卸載,結果再裝也裝不上,于是只好又設置高級啟動,重新禁止強制簽名,進入系統,裝上驅動,恰好這時Windows又在后臺偷偷摸摸地更新,不知道更新了啥,讓我重啟。
    16、重啟之后,奇跡出現,剛才明明提示沒有簽名強制安裝的驅動,現在居然正常啟動也沒問題了,而且查看驅動詳情的時候出現了矛盾的一幕:
    外面顯示數字簽名者:未經數字簽名,里面的sys文件又顯示數字簽名者是Microsoft Windows,然而進入C:\Windows\System32\drivers目錄,找到usbohci.sys,點右鍵,卻發現并沒有數字簽名:
    好吧,你開心就好,反正不要再禁我的鼠標就行……
    感謝這次蛋疼的折騰之旅,讓我知道了驅動程序來自哪里,安裝日志在哪里,哪個軟件坑爹又沒用,怎么玩安裝盤,怎么用鍵盤操作鼠標,怎么進入高級啟動界面……
    我為什么要知道這些??????????????為微軟的疏忽買單啊!!!!!
    啥都不說了,它又提示我重啟了,不知道又有什么奇跡會發生……
    posted @ 2017-11-19 12:43 amp@java 閱讀(1157) | 評論 (0)編輯 收藏

     每次換手機,把舊手機的數據遷移到新手機就是個很麻煩的事情,幸好最近華為的“手機克隆”APP越來越強大,居然能夠把微信的聊天記錄包括圖片原封不動地遷移到新手機上,以前用微信自帶的聊天記錄轉移功能只能轉移文字信息,圖片視頻全部丟失,不知道現在的怎么樣。手機克隆還能把SD卡的內容也轉移過來,基本滿足了需要。
    但是要把手機上的東西傳到電腦就沒那么簡單了,現在已經沒有了以前的大容量存儲模式,只能選擇MTP模式,這種模式其實不是一個完整的文件系統,有很多限制,所以一些傳統的軟件讀取不到,例如FastCopy是用不了的,用Windows自帶的文件管理器來復制,開始計算時間就要等很久,中間出了個錯就前功盡棄;還有通過手機上的APP訪問電腦共享的方式,在手機上復制也可以,但是同樣會莫名其妙卡死,FTP同理,折騰了好久,還是覺得自己動手比較好。
    MTP協議在維基百科里解釋得比較清楚:https://en.wikipedia.org/wiki/Media_Transfer_Protocol ,簡單點說就是:
    1、不是以塊設備的形式訪問,跟U盤不同;
    2、只能單線程訪問,不能同時進行多個操作,只能一個接一個;
    3、控制權在設備上,對外展示的內容由設備決定;
    4、默認不能直接對文件進行部分修改,只能復制過來修改完再復制回去,但Android對協議做了擴展,能夠修改部分文件內容;
    5、在Linux上有些軟件能夠把它掛載為文件系統,這樣其他軟件就能像訪問普通文件系統一樣訪問了,但是Windows下似乎沒有。

    不過有人開發了一個在Windows下通過JNI實現的Java庫jmtp,項目托管在Google Code,被墻了,但是GitHub有人fork了一個,可以下載下來,我下載的是https://github.com/reindahl/jmtp
    里面包含了C++的代碼和Java的代碼,以及兩個已經編譯好的dll文件,分別用于Win32和Win64,把其中一個dll文件放在工程目錄下,再把Java源代碼加入工程中即可使用,文檔比較簡陋,但是看test目錄下的MtpTest.java,基本可以摸到如何使用了,這個協議比較簡單,其實沒什么功能,我要的只是把文件復制到電腦上。
    根據MtpTest.java,稍微修改一下,做個遞歸復制即可把手機上的所有文件復制到電腦上:
    package test;

    import java.io.File;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.math.BigInteger;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.rmi.server.SocketSecurityException;
    import java.util.ArrayList;


    import jmtp.PortableDevice;
    import jmtp.PortableDeviceFolderObject;
    import jmtp.PortableDeviceManager;
    import jmtp.PortableDeviceObject;
    import jmtp.PortableDeviceStorageObject;


    public class TestApp {

       

        
    public static void main(String[] args) {
            
    // TODO Auto-generated method stub
            
            ArrayList
    <PortableDeviceStorageObject> devices = new ArrayList<>();

            PortableDeviceManager manager 
    = new PortableDeviceManager();

            
    for (PortableDevice device : manager) {
                System.out.println(device);
                device.open();
                
                
    // Iterate over deviceObjects
                for (PortableDeviceObject object : device.getRootObjects()) {
                    String storageName
    =object.getName();
                    System.out.println(storageName);

                    
    // If the object is a storage object
                    if (object instanceof PortableDeviceStorageObject) {
                        PortableDeviceStorageObject storage 
    = (PortableDeviceStorageObject) object;
                        System.out.println(storage.getChildObjects().length);
                        
    for (PortableDeviceObject child : storage.getChildObjects()) {
                                copyall(child,
    "E:\\手機備份\\"+object.getName());
                        }
                    }
                }

                device.close();
                System.out.println(size);
            }

      
      
        }
        
        
    public static void copyall(PortableDeviceObject obj,String path) {

            if(obj instanceof PortableDeviceFolderObject) {
              

                String objName=obj.getName();
                
    if(objName.contains(":")) {
                    objName
    =objName.replace(':''');
                }
                String newPath 
    = path+"\\"+objName;
                System.out.println(
    "創建文件夾:"+newPath);
                
                File file = new File(newPath);
                if(!file.exists()) {
                    file.mkdirs();
                }
                for(PortableDeviceObject subObj:((PortableDeviceFolderObject) obj).getChildObjects()) {             
                    copyall(subObj,newPath);
                }
            }
            
    else {      
                
    if(obj.getName().contains(":"))
                    
    return;
                System.out.println(
    "開始復制文件到:"+path+"\\"+obj.getName());
                File file 
    = new File(path);
                obj.copy(file.toPath());                     
                System.out.println(
    "文件復制完成!");
            }
        }

    }
    其中發現有點問題:
    1、Android設備文件名里是可以包含冒號(:)的,但Windows是不可以的,所以復制到這些文件的時候會有問題,于是遇到目錄名這樣就把它改為中文的冒號(:),但是遇到文件名這樣就不行了,因為這個庫的copy函數只需要指定目標目錄,不需要指定目標文件名,所以這些文件只能放棄;
    2、Android手機的MTP協議是由“媒體存儲”這個系統APP控制的,有時候手機上可以看到的文件,通過MTP訪問卻怎么也看不到,重啟手機也不行,應該就是這個APP沒有更新數據,需要把它的系統數據清除掉,等它重建完重新訪問就可以看到了,不過這個重建時間非常長,可以查看它數據占用的空間,剛清除之后會發現它占用的空間會不斷增長,到了不增長的時候就是重建完了,就可以正常訪問了;
    3、這個庫有時候還有點bug,有一次發現它讀取到的文件和文件夾都沒有了最后一個.后面的部分,所以總是卡住,重新插拔一下手機數據線又沒問題了;
    4、為了避免復制了半天結果發現不完整,又要重來,最好在復制前先統計一下文件大小,看看跟手機上看到的占用存儲空間是不是一致,對于MTP設備上的文件,可以通過getSize函數得到大小,把上面復制操作改為大小累加即可,速度比復制快一些,不過由于小文件太多,也不會快很多。

    把手機里的文件復制到電腦后,通過一些簡單的分析,發現有很多其實是垃圾來的,也可以為手機空間清理提供參考,因為在電腦上分析起來比在手機上方便一些。例如一些視頻APP的緩存,居然超過1G,占用了寶貴的內部存儲空間,之前一直都沒發現,通過電腦里的按文件大小搜索才發現。
    posted @ 2017-11-17 14:54 amp@java 閱讀(2256) | 評論 (0)編輯 收藏

    09款老速騰,不支持USB和AUX,要聽歌除了CD以外,就是刻錄在CD上的MP3了,以前不知道用什么軟件刻錄了一張碟,能夠完美地顯示中文文件名和ID3信息,前幾天用ImgBurn刻了一張,發現中文是亂碼,開始以為是ID3信息顯示亂碼,于是下載了一個Mp3Tag,把所有ID3信息都清除,結果顯示文件名依然亂碼,重新寫入ID3信息,發現ID3可以正常顯示,但文件名還是亂碼。
    于是就把原來那張可以正常顯示中文的碟拿來研究一下,發現它的ID3標簽只是ID3v1,而后來重新寫入的ID3是ID3v2.3,兩個都可以正常顯示中文,說明ID3信息是正常的,文件名亂碼不是這個問題。
    但是不知道用什么軟件來顯示光盤的文件系統,只能一次次摸索。
    幸好有一張CD-RW可以反復嘗試。
    ImgBurn默認是使用ISO9660+UDF,而ISO 9660則使用最老的ISO 9660文件系統,也就是1988版本,文件名默認是不支持中文的,不知道是不是這個原因,于是就把文件系統改為ISO 9660+Joliet,如下圖:

    并且把ISO 9660標準改為1999:

    可能是因為字符編碼那里改為了ASCII,所以就好了。
    后來又嘗試只使用UDF文件系統,結果認不出碟。



    所以,目前能夠使用中文的環境其實就是:
    ImgBurn使用ISO 9660 1999標準;
    ID3使用v1或v2.3都可以。

    posted @ 2017-02-10 09:17 amp@java 閱讀(404) | 評論 (0)編輯 收藏

    最近新部署了一個信息系統,廠家居然沒有升級方案,所有數據都要重新輸入,包括用戶、角色等都要重新配置,真是操蛋。要是一個個錄入簡直是日狗了,這些用戶在其他信息系統早已存在,但是每個都復制粘貼提交一遍也不是辦法,于是就想用程序自動完成這些操作。步驟如下:
    1、從其他信息系統的數據庫導出用戶信息,也可以直接從其他信息系統的界面把所有用戶信息復制下來放在一個文本文件里,反正就是準備好數據源;
    2、在需要錄入用戶信息的系統中,用人工操作的方式登錄系統,并錄入一個用戶,同時用Wireshark抓包,查看整個過程要提交一些什么樣的表單數據;
    3、在程序中用httpclient提交同樣的數據,完成登錄,并從第1步的數據源中讀取用戶信息,然后循環提交錄入用戶所需的數據,完成用戶的錄入;
    4、新系統沒有默認的用戶角色,是需要一個個修改的,是根據用戶的ID來確定當前修改的用戶,并且提交一個角色ID來進行設定,因此需要首先獲取用戶的ID,然后根據該ID來提交角色ID,而用戶ID是通過用戶列表頁面獲取到的,因此還需要通過正則表達式來獲取所有用戶的ID,然后循環提交角色ID,完成角色設定。

    花了不少時間才搞定,有幾個地方需要注意:
    1、如果表單數據不包含中文,直接把表單的Name和Value加在HttpPost的URL的?后面即可,不需要專門建立NameValuePair,如下所示:
    HttpPost httppost = new HttpPost("http://1.1.1.1/test/adduser?userid=abc&username=efg");
    httpclient.execute(httppost);

    但是,如果表單數據包含中文,例如姓名,用這種方式提交的表單數據會出現亂碼,即使通過URLEncoder進行編碼后再發也不行,必須建立NameValuePair,再加到HttpPost的Entity里面,如下所示:
    HttpPost httppost = new HttpPost("http://1.1.1.1/test/adduser?userid=abc");
    List
    <NameValuePair> nvps = new ArrayList<NameValuePair>();
    nvps.add(
    new BasicNameValuePair("username","張三"));
    httppost.setEntity(
    new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
    httpclient.execute(httppost);

    2、用于網頁內容查找的正則表達式的使用方式一般為:
    Pattern p = Pattern.compile(".*?abc(whattoget)123.*?");
    Matcher m = p.matcher(line);
    if(m.matches()){
         String whattoget 
    = m.group(1);
    }
    ".*?abc(whattoget)123.*?"就是一個正則表達式,如果用于匹配一行的時候,由于要查找的內容是在行中間,所以前后需要加上.*?,表示前后可以是任意字符,也可以什么都沒有,而表達式中間的(whattoget)就表示一個group,編號為1,編號為0的group是整個匹配的字符串,找到之后提取group(1)即可得到想要的內容。
    測試正則表達式是一項很麻煩的工作,不過有個很好的軟件可以完成此工作:RegexBuddy,支持各種語言的正則表達式的調試。
    學習正則表達式的寶典是《Mastering Regular Expression》。
    posted @ 2016-01-12 15:54 amp@java 閱讀(3575) | 評論 (1)編輯 收藏

    今天遇到一個非常奇怪的問題,有臺裝XP的電腦,插上USB鍵盤沒反應,還以為是鍵盤壞了,又找來兩個不同型號的鍵盤,依然不行,又以為是USB接口壞了,結果在電腦啟動的時候又可以按F2進入BIOS,這樣就只有一個原因,Windows的驅動沒裝上了。
    幸好這電腦還有傳統的PS/2口,而且插上就能識別,否則連Windows都進不去,因為按Ctrl+Alt+Del沒反應。
    進去之后提示安裝USB鍵盤驅動,到最后一步提示安裝失敗,原因是拒絕訪問。
    上網搜了一下,安裝驅動拒絕訪問的其中一個原因是注冊表有個鍵的權限設置有問題,改過來即可,但是我打開注冊表,連那個鍵都沒找到,不是這個原因。
    不過從這個解決方案中也知道了驅動安裝的日志是在Windows目錄下的setupapi.log文件里面,于是打開那個文件,發現每次安裝都有兩個拒絕訪問的錯誤,但并沒有說是注冊表拒絕訪問,在拒絕訪問之前,還提到一個叫MlCoInst.dll的文件沒有簽名。
    上網搜MlCoInst.dll,沒有找到任何結果,在System32目錄下找到它,看屬性,果然沒有簽名,是個三無文件,不知道為什么每次安裝驅動都要調用它。
    日志里面還提到了“共同安裝程序”,似乎和CoInst有點關聯,于是又查了一下,原來安裝驅動的時候可以通過調用“共同安裝程序”來實現某些目的,例如修改驅動程序的簽名狀態,欺騙操作系統,這樣就可以只安裝一次驅動即可,不用每次插入都安裝一次。
    于是嘗試把MlCoInst.dll刪除,提示刪除失敗。
    在注冊表里面搜索MlCoInst.dll,把所有找到的鍵值都刪除,再次插拔鍵盤,順利安裝完畢,刪除MlCoInst.dll,也成功了,果然是它的問題。

    這個應該是某個USB設備的驅動引進來的,而且修改了usb.inf,每次安裝任何USB設備都要調用它,但它可能與Windows的簽名機制有沖突,所以導致安裝失敗,真是坑爹!
    posted @ 2015-04-02 17:04 amp@java 閱讀(3605) | 評論 (0)編輯 收藏

    做GUI程序的時候,通常有個后臺工作線程在努力工作,但是中間又需要一些暫停,而關閉程序的時候,必須立即結束那個線程,退出程序,也有的時候需要停止后臺線程,但不關閉程序。例如,做一個目錄監控程序,發現目錄中有文件的時候,執行一定的操作,執行完之后沒有文件了,就要暫停一下,過幾秒或幾分鐘再次檢測,這時候就要對線程進行暫停操作,如果在暫停的時候,用戶要關閉程序,就必須馬上停止線程,如果用戶需要暫停檢測,按下某個按鈕后,需要讓線程馬上停止,但再次按下某個按鈕,線程又必須馬上開始。

    以前我都是通過檢測停止標記和用Thread.sleep(time)來完成的,后臺線程的每次循環都要檢查停止標記,如果發現停止標記已設定,就不再循環,退出線程,在線程內部,如果需要暫停,就執行Thread.sleep(time)。通過把線程的setDaemon(true)方法,還可以讓線程作為后臺線程,當圖形界面關閉后,線程也自動退出。

    但是,這種方式有個問題,如果我需要在圖形界面上點擊按鈕來停止線程,但并不退出程序,而點擊按鈕的時候線程正處于sleep狀態,就對它沒有任何辦法,只能讓它醒過來再操作,如果sleep的時間比較長,例如1分鐘,那么點擊按鈕之后,用戶最多要等1分鐘才能把線程停下來。當然,Thread對象有個interrupt方法,但是已經被標記為過期,一般不建議使用了。感謝評論中watchzerg的提醒,Thread的interrupt()并沒有標記為過期,可以按照他的說法來操作,更為簡單。

    怎么讓線程能暫停,又能隨時叫醒呢?原來Java里最原始的對象Object就自帶此功能。

    每個Object都有wait(time)和notify()方法,前者就是讓擁有該Obejct的線程處于暫停狀態,后者則讓線程馬上喚醒,通過這兩個方法,就能夠滿足上述的所有要求。

    首先,建立一個同步對象:
    Object syncObj = new Object();

    然后在線程中需要暫停的地方,調用該對象的wait(time)方法:
    synchronized (syncObj) {
           syncObj.wait(60*1000);
    }

    在圖形界面的按鈕監聽事件中,對該對象執行notify()方法:
            button_1.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {

                    thread.setStop(true);
                    synchronized (syncObj) {
                            syncObj.notify();
                     }
                    //為了等待線程退出,還可以加上以下語句:
                    thread.join();

                }
            });

    posted @ 2015-03-10 16:52 amp@java 閱讀(7692) | 評論 (2)編輯 收藏

    Eclipse有個功能就是把整個項目打包成一個可執行的Jar文件,里面包含了所有項目引用了的庫,如果電腦上安裝了JRE,直接雙擊就可以啟動,看起來很方便,如下圖所示:

    可以選擇把所有類庫打包進去,也就是Jar里面還包含一堆Jar:

    還可以生成ant腳本:


    生成的jar文件,可以直接通過java -jar xx.jar啟動,簡單快捷。


    然而,這樣導出來的可執行jar,啟動速度卻非常慢,這跟包的大小有關。有個項目導出來的包有40MB,結果啟動需要近一分鐘,在性能差的電腦上,甚至要幾分鐘,就是你執行完命令后,沒有任何界面顯示,但是查看任務管理器發現java進程的CPU占用率在浮動,說明正在努力啟動,過了一段時間之后界面突然顯示出來,簡直讓人崩潰。可是在Eclipse里面運行,卻是一點就開。

    我開始嘗試縮小導出的包。但是Eclipse的導出對話框并沒有提供需要打包哪些庫的選項,都是默認把所有庫都打包進去,但是它可以生成ant腳本,可以通過編輯ant腳本的方式來減少不必要的庫。經過多次嘗試,終于把40MB的包縮成了17MB,啟動速度快了一些,但是依然需要半分鐘以上。

    后來覺得,能不能不打包直接運行呢?于是把導出來的包用壓縮軟件解壓,再把里面包含的jar包繼續解壓,最后得到一堆沒有壓縮的class文件,再通過指定classpath的方式,直接運行程序入口class,發現啟動速度和在Eclipse里面一樣,一點就開。

    打包的好處是部署簡單,只需要一個文件,但帶來的缺點實在不能忍,打散的方式部署起來稍微難一點,但是啟動速度夠快,對普通用戶來說,這個才是最重要的。

    當然,還有一種方式是像Eclipse那樣,啟動時顯示一個圖片,底下一個進度條顯示啟動進度,不過這樣也加大了工作量,而且每次都要等那進度條,實際上也很煩。
    posted @ 2015-03-10 15:07 amp@java 閱讀(5143) | 評論 (0)編輯 收藏

         摘要: JMF太老了,各種問題得不到解決,Oracle也沒再升級過,如果能找到新東西,最好能把它扔掉。最近OpenCV比較火,還有人用Java封裝了OpenCV,成立了JavaCV項目,通過改造VideoInput這個基于C語言的項目,能夠用Java來調用攝像頭,JMF可以扔掉了。如果想測試,非常簡單,把那些編譯好的jar文件放入Build Path即可,如果是在Windows X86環境下,則只需要把帶...  閱讀全文
    posted @ 2015-02-15 11:41 amp@java 閱讀(10432) | 評論 (7)編輯 收藏

    其實我覺得用java結合SQL來做同樣的事情更簡單,但是EXCEL的好處是不用編程,雖然里面有好多陷阱,但是掌握之后能夠熟練運用還是比每次都編個程序更簡單。VLOOKUP函數的使用比較復雜,搞了好久都不明白,終于找到了下面這篇文章,解決了很多問題。

    以下是轉載文章,原來的出處不知道是哪里,應該是來自

    http://www.excelpx.com
    但具體的地址不詳。



    VLOOKUP函數是Excel中幾個最重函數之一,為了方便大家學習,蘭色幻想特針對VLOOKUP函數的使用和擴展應用,進行一次全面綜合的說明。本文為入門部分

         一、入門級

          VLOOKUP是一個查找函數,給定一個查找的目標,它就能從指定的查找區域中查找返回想要查找到的值。它的基本語法為:

          VLOOKUP(查找目標查找范圍返回值的列數精確OR模糊查找)

    下面以一個實例來介紹一下這四個參數的使用

         例1:如下圖所示,要求根據表二中的姓名,查找姓名所對應的年齡。  

       公式:B13 =VLOOKUP(A13,$B$2:$D$8,3,0)  

       參數說明:

           1 查找目標:就是你指定的查找的內容或單元格引用。本例中表二A列的姓名就是查找目標。我們要根據表二的“姓名”在表一中A列進行查找。

            公式:B13 =VLOOKUP(A13,$B$2:$D$8,3,0)   

           2 查找范圍(VLOOKUP(A13,$B$2:$D$8,3,0) : 指定了查找目標,如果沒有說從哪里查找,EXCEL肯定會很為難。所以下一步我們就要指定從哪個范圍中進行查找。VLOOKUP的這第二個參數可以從一個 單元格區域中查找,也可以從一個常量數組或內存數組中查找。本例中要從表一中進行查找,那么范圍我們要怎么指定呢?這里也是極易出錯的地方。大家一定要注 意,給定的第二個參數查找范圍要符合以下條件才不會出錯:

            A 查找目標一定要在該區域的第一列。本例中查找表二的姓名,那么姓名所對應的表一的姓名列,那么表一的姓名列(列)一定要是查找區域的第一列。象本例中,給定的區域要從第二列開始,即$B$2:$D$8,而不能是$A$2:$D$8。因為查找的“姓名”不在$A$2:$D$8區域的第一列。

            B 該區域中一定要包含要返回值所在的列,本例中要返回的值是年齡。年齡列(表一的D列)一定要包括在這個范圍內,即:$B$2:$D$8,如果寫成$B$2:$C$8就是錯的。

           3 返回值的列數(B13 =VLOOKUP(A13,$B$2:$D$8,3,0))。這是VLOOKUP第3個參數。它是一個整數值。它怎么得來的呢。它是“返回值”在第二個參數給定的區域中的列數。本例中我們要返回的是“年齡”,它是第二個參數查找范圍$B$2:$D$8的第3列。這里一定要注意,列數不是在工作表中的列數(不是第4列),而是在查找范圍區域的第幾列。如果本例中要是查找姓名所對應的性別,第3個參數的值應該設置為多少呢。答案是2。因為性別在$B$2:$D$8的第2列中。

           4 精確OR模糊查找(VLOOKUP(A13,$B$2:$D$8,3,0)  ),最后一個參數是決定函數精確和模糊查找的關鍵。精確即完全一樣,模糊即包含的意思。第4個參數如果指定值是0或FALSE就表示精確查找,而值為1 或TRUE時則表示模糊。這里蘭色提醒大家切記切記,在使用VLOOKUP時千萬不要把這個參數給漏掉了,如果缺少這個參數默為值為模糊查找,我們就無法精確查找到結果了。  

          好了,關于VLOOKUP函數的入門級應用就說到這里,VLOOKUP函數可不只是這么簡單的查找,我們講的還只是1/10的用法。其他的沒法在一篇文章中說明。敬請期待“VLOOKUP的使用方法-進階篇”吧。

     

    上一講咱們學習了VLOOKUP的基本用法和示例,本講將介紹VLOOKUP在使用中的一些小技巧。

    Excel函數速成教程全系列(包括VLOOKUP函數,IF函數,offset函數,sumif函數等66個函數)預計6月初全部錄制完成,現已在淘寶開始預訂(8折優惠),地址:http://item.taobao.com/item.htm?id=17500884347

    一、VLOOKUP多行查找時復制公式的問題

        VLOOKUP函數的第三個參數是查找返回值所在的列數,如果我們需要查找返回多列時,這個列數值需要一個個的更改,比如返回第2列的,參數設置為2,如 果需要返回第3列的,就需要把值改為3。。。如果有十幾列會很麻煩的。那么能不能讓第3個參數自動變呢?向后復制時自動變為2,3,4,5。。。   

        在EXCEL中有一個函數COLUMN,它可以返回指定單元格的列數,比如

             =COLUMNS(A1) 返回值1

             =COLUMNS(B1) 返回值2

       而單元格引用復制時會自動發生變化,即A1隨公式向右復制時會變成B1,C1,D1。。這樣我們用COLUMN函數就可以轉換成數字1,2,3,4。。。 

        例:下例中需要同時查找性別,年齡,身高,體重。

       

         公式:=VLOOKUP($A13,$B$2:$F$8,COLUMN(B1),0)

      公式說明:這里就是使用COLUMN(B1)轉化成可以自動遞增的數字。

    二、VLOOKUP查找出現錯誤值的問題。

        1、如何避免出現錯誤值。

         EXCEL2003 在VLOOKUP查找不到,就#N/A的錯誤值,我們可以利用錯誤處理函數把錯誤值轉換成0或空值。

          即:=IF(ISERROR(VLOOKUP(參數略)),"",VLOOKUP(參數略)

         EXCEL2007,EXCEL2010中提供了一個新函數IFERROR,處理起來比EXCEL2003簡單多了。

         IFERROR(VLOOKUP(),"") 

        2、VLOOKUP函數查找時出現錯誤值的幾個原因

          A、實在是沒有所要查找到的值

          B、查找的字符串或被查找的字符中含有空格或看不見的空字符,驗證方法是用=號對比一下,如果結果是FALSE,就表示兩個單元格看上去相同,其實結果不同。

          C、參數設置錯誤。VLOOKUP的最后一個參數沒有設置成1或者是沒有設置掉。第二個參數數據源區域,查找的值不是區域的第一列,或者需要反回的字段不在區域里,參數設置在入門講里已注明,請參閱。

         D、數值格式不同,如果查找值是文本,被查找的是數字類型,就會查找不到。解決方法是把查找的轉換成文本或數值,轉換方法如下:

         文本轉換成數值:*1或--或/1

         數值轉抱成文本:&""  

         VLOOKUP函數的初級篇就說到這里了,咱們下一講將介紹VLOOKUP的模糊查找有、反向查找等。

     

     在學習了VLOOKUP的入門和初級篇后,本文將帶將大家學習VLOOKUP的進階篇:VLOOKUP的模糊查找。

        一、字符的模糊查找    

            在A列我們知道如何查找型號為“AAA”的產品所對應的B列價格,即:

        =VLOOKUP(C1,A:B,2,0)

           如果我們需要查找包含“AAA”的產品名稱怎么表示呢?如下圖表中所示。

         公式=VLOOKUP("*"&A10&"*",A2:B6,2,0)  

        公式說明:VLOOKUP的第一個參數允許使用通配符“*”來表示包含的意思,把*放在字符的兩邊,即"*" & 字符 & "*"。

       二、數字的區間查找

          數字的區間查找即給定多個區間,指定一個數就可以查找出它在哪個區間并返回這個區間所對應的值。

        在VLOOKUP入門中我們提示VLOOKUP的第4個參數,如果為0或FALSE是精確查找,如果是1或TRUE或省略則為模糊查找,那么實現區間查找正是第4個參數的模糊查找應用。

        首先我們需要了解一下VLOOKUP函數模糊查找的兩個重要規則:

        1、引用的數字區域一定要從小到大排序。雜亂的數字是無法準確查找到的。如下面A列符合模糊查找的前題,B列則不符合 

        

        2、模糊查找的原理是給一定個數,它會找到和它最接近,但比它小的那個數。詳見下圖說明。

        

       最后看一個實例: 

        例:如下圖所示,要求根據上面的提成比率表,在提成表計算表中計算每個銷售額的提成比率和提成額。

        

       公式:=VLOOKUP(A11,$A$3:$B$7,2)

       公式說明:

        1、上述公式省略了VLOOKUP最后一個參數,相當于把第四個參數設置成1或TRUE。這表示VLOOKUP要進行數字的區間查找。

        2、圖中公式中在查找5000時返回比率表0所對應的比率1%,原因是0和10000與5000最接近,但VLOOKUP只選比查找值小的那一個,所以公式會返回0所對應的比率1%。

     

     前言:前面我們分別學習了VLOOKUP函數的入門、初級和進階篇。今天我們學習VLOOKUP函數的高級應用部分-VLOOKUP函數的數組應用。(本文由蘭色幻想原創,轉載請注明轉自excel精英培訓

     一、VLOOKUP的反向查找。

        一般情況下,VLOOKUP函數只能從左向右查找。但如果需要從右向右查找,則需要把區域進行“乾坤大挪移”,把列的位置用數組互換一下。

        例1:要求在如下圖所示表中的姓名反查工號。

         

        公式:=VLOOKUP(A9,IF({1,0},B2:B5,A2:A5),2,0)

        公式剖析:

            1、這里其實不是VLOOKUP可以實現從右至右的查找,而是利用IF函數的數組效應把兩列換位重新組合后,再按正常的從左至右查找。

            2、IF({1,0},B2:B5,A2:A5)這是本公式中最重要的組成部分。在EXCEL函數中使用數組時(前提時該函數的參數支持數組),返回的結 果也會是一個數組。這里1和0不是實際意義上的數字,而是1相關于TRUE,0相當于FALSE,當為1時,它會返回IF的第二個參數(B列),為0時返 回第二個參數(A列)。根據數組運算返回數組,所以使用IF后的結果返回一個數組(非單元格區域):{"張一","A001";"趙 三","A002";"楊五","A003";"孫二","A004"}

     二、VLOOKUP函數的多條件查找。

          VLOOKUP函數需要借用數組才能實現多條件查找。

         例2:要求根據部門和姓名查找C列的加班時間。

         分析:我們可以延用例1的思路,我們的努力方向不是讓VLOOKUP本身實現多條件查找,而是想辦法重構一個數組。多個條件我們可以用&連接在一起,同樣兩列我們也可以連接成一列數據,然后用IF函數進行組合。

        公式:{=VLOOKUP(A9&B9,IF({1,0},A2:A5&B2:B5,C2:C5),2,0)}

        公式剖析:

           1、A9&B9 把兩個條件連接在一起。把他們做為一個整體進行查找。

           2、A2:A5&B2:B5,和條件連接相對應,把部分和姓名列也連接在一起,作為一個待查找的整體。

           3、IF({1,0},A2:A5&B2:B5,C2:C5) 用IF({1,0}把連接后的兩列與C列數據合并成一個兩列的內存數組。按F9后可以查看的結果為:

           {"銷售張一",1;"銷售趙三",5;"人事楊五",3;"銷售趙三",6}

           4、完成了數組的重構后,接下來就是VLOOKUP的基本查找功能了,另外公式中含有多個數據與多個數據運算(A2:A5&B2:B5),,所以必須以數組形式輸入,即按ctrl+shift后按ENTER結束輸入。

         三、VLOOKUP函數的批量查找。

         VLOOKUP一般情況下只能查找一個,那么多項該怎么查找呢?

         例3 要求把如圖表中所有張一的消費金額全列出來

         分析:經過前面的學習,我們也有這樣一個思路,我們在實現復雜的查找時,努力的方向是怎么重構一個查找內容和查找的區域。要想實現多項查找,我們可以對查找的內容進行編號,第一個出現的是后面連接1,第二個出現的連接2。。。

         公式:{=VLOOKUP(B$9&ROW(A1),IF({1,0},$B$2:$B$6&COUNTIF(INDIRECT("b2:b"&ROW($2:$6)),B$9),$C$2:$C$6),2,)}

         公式剖析:

            1、B$9&ROW(A1) 連接序號,公式向下復制時會變成B$9連接1,2,3

            2、給所有的張一進行編號。要想生成編號,就需要生成一個不斷擴充的區域(INDIRECT("b2:b"&ROW($2:$6)),然后在這個逐行擴充的區域內統計“張一”的個數,在連接上$B$2:$B$6后就可以對所有的張一進行編號了。

           3、IF({1,0}把編號后的B列和C組重構成一個兩列數組

         通過以上的講解,我們需要知道,VLOOKUP函數的基本用法是固定的,要實現高級查找,就需要借助其他函數來重構查找內容和查找數組。

         至此VLOOKUP函數從入門到高級的四篇VLOOKUP函數使用教程全部結束了,VLOOKUP函數在數組運算中還有著其他應用,但只是配角了,所以本系列不再介紹。由于筆者水平有限,不免有錯漏之處,請大家多多指點。

    posted @ 2014-12-16 09:10 amp@java 閱讀(519) | 評論 (0)編輯 收藏

    JMF(Java Media Framework)是Java平臺使用攝像頭、麥克風等媒體設備的應用程序框架,但到了2.1.1e就不再更新,在Windows 7 X64上還能正常運行,只是安裝的界面讓你感覺回到了Windows98的時代。


    不過年代久遠的東西,雖然還能用,但可能會遇到一些奇怪的問題,折騰了兩個月,發現了兩個比較大的問題:

    第一個是在Windows 7 x64上提示攝像頭初始化失敗的問題。這個問題很奇怪,電腦剛開機的時候可以順利找到一次攝像頭并正常操作,但是第二次就會提示攝像頭初始化失敗。有人提出的解決方法是安裝一個叫ManyCamera的程序,這個程序可以把一個攝像頭供多個程序同時使用,其實就等于中間加了一層轉換,效果會有點差別,免費版還會加上水印,要求比較高的人可能會不爽,但是目前找不到其他辦法。

    第二個是在程序中找不到攝像頭,不光找不到攝像頭,其他媒體設備通通找不到,使用以下語句:
    vector = CaptureDeviceManager.getDeviceList ( null )
    按照文檔說明是返回所有媒體設備,但每次vector都是null。
    在Eclipse中運行又能正常,導出成jar之后運行就會找不到攝像頭。
    原因在于找不到jmf.properities文件,該文件包含所有檢測到的媒體設備的信息,最簡單的解決方法就是把JMF安裝目錄下lib子目錄中的jmf.properties文件復制到最后運行的jar所在的目錄,不過如果攝像頭改過的話,重新檢測后要把新的文件復制到jar目錄,因為檢測到的媒體設備信息都會存放在JMF安裝目錄里面的jmf.properties文件里。

    StackOverflow里面有個人對這個問題解釋得比較清楚:
    http://stackoverflow.com/questions/8768142/java-capturedevicemanagergetdevicelist-is-empty


    雖然問題解決了,但是還是不明白為何在Eclipse中可以正常運行,導出jar后運行卻找不到攝像頭,即使把JMF所有jar和lib目錄都加入系統的CLASSPATH環境變量里還是不行。


    另外,JMF安裝程序會自動把它的jar和lib目錄加入系統的%CLASSPATH%環境變量,但是如果你卸載了再重新安裝到其他目錄,并不會改變%CLASSPATH%的值,需要手動修改。不過這個環境變量似乎沒啥用處。
    最好不要把JMF安裝到默認的Program Files目錄,可能會運行不了,安裝到短目錄會比較保險,它似乎還是只認Dos時代的8.3目錄結構,但偏偏又默認安裝到Program Files里面。
    posted @ 2014-07-01 10:33 amp@java 閱讀(7275) | 評論 (0)編輯 收藏

    其實我也搞不懂Windows的域,反正能用就行了。
    但是最近有一臺客戶端的時間改不了,總是提示特權級不夠,按理說應該是組策略限制了,但是我把那臺計算機從包含該組策略的OU中移出來,還是不行,這就奇怪了,難道組策略不是指針對OU里面的成員的嗎?百思不得其解啊,最后只能在BIOS里面把時間改了。
    今天發現我自己的電腦設置不了屏幕保護,也是組策略限制了,然后把我的用戶和計算機都移出了組策略應用的OU,結果發現還是設置不了,這下肯定是組策略的應用上有問題了。
    搜索了半天發現有個叫rsop.msc的管理工具,可以看到某用戶在某計算機上應用的組策略,結果發現我還是應用之前的組策略,但是計算機配置和用戶配置前面都有個紅叉,右鍵-屬性-錯誤信息里面顯示:
    Title
    由于下面列出的錯誤,組策略結構 失敗。

    系統找不到指定的路徑。

    注意: 由于 GP Core 失敗,其它組策略組件沒有一個處理了它們的策略。因此,其它組件的狀態信息不可用。
    好像是有某個組策略找不到,所以不能應用的意思。
    然后想起來在域名下面有個“新建組策略”,但是沒有做過任何配置,應該是有人手賤點了一下新建按鈕加進去的,于是把它刪除,還是不行。
    重啟了一下客戶端,居然好了,時間也可以改了,屏幕保護也可以改了,一切都按計劃進行。


    莫名其妙~~
    posted @ 2014-06-23 16:11 amp@java 閱讀(1347) | 評論 (0)編輯 收藏

    現在的手機攝像頭動輒幾百萬上千萬像素,如果電腦需要用到攝像頭又沒有的話,不妨用手機的攝像頭代替。

    我是在做一個電腦二維碼識別器的時候,因為原來的攝像頭太差,從而想到用一臺淘汰的Android手機來代替。

    這類應用應該不少,我首先找到的是一個叫DraoidCam的應用,裝好之后發現免費版沒法調整分辨率,于是放棄之。

    然后又找到了一個國內做的免費軟件,叫魅色,非常簡單,支持USB和WiFi連接方式,如果是USB連接的話,打開USB調試模式之后,運行電腦的客戶端,手機上就自動裝上了App并且自動運行,可以調整分辨率,不過最高只有640*480,幀率不到10,不過已經能夠滿足我的需求了。

    然后就可以像普通PC攝像頭一樣使用了,在JMF里面也能找到,于是就可以被Java調用了。經測試,效果比原來的PC攝像頭好多了。

    軟件主頁:http://www.libfetion.org/meise/
    posted @ 2014-06-05 15:35 amp@java 閱讀(1722) | 評論 (4)編輯 收藏

         摘要: TabActivity在API 13(Android 3.2)被標記為過期,需要使用Fragment來實現,Fragment是Android 3.0引入的一個概念,主要就是為了適應各種不同的屏幕大小(手機、平板電腦)。Android 4.1發布時,google還發布了一個Android Support v4的包,用于Android 1.6以上的系統兼容新的特性,其中包括Fragment。為了在低于...  閱讀全文
    posted @ 2012-12-27 19:07 amp@java 閱讀(15645) | 評論 (0)編輯 收藏

    SQL Server 2000的導入導出功能還是不錯的,支持各種各樣的數據庫,但是卻有好多奇怪的bug,不能直接操作,幾乎每一步都要上網搜索,最后搞定了,一定要記下來:
    1、在同一臺電腦上裝好SQL Server 2000的客戶端和Oracle 10g的客戶端,并分別設置好到源數據庫(SQL Server 2000數據庫)和目標數據庫(Oracle 數據庫)的連接,兩個數據庫都有圖形界面的企業管理器,很容易設置好;
    2、在控制面板-管理工具-數據源里添加一個DSN,驅動程序選擇類似“Oracle in OraClient10g_home1”的,確定之后輸入Data Source Name(隨意),Description(隨意),TNS Service Name(在企業管理器里設置好的連接名),User ID(用戶名),然后按Test Connection測試是否連接成功,成功之后點OK;
    3、在SQL Server 2000的企業管理器里,在任意一個表上點右鍵,所有任務,導出數據,在目的里選擇“Oracle in OraClient10g_home1”,用戶/系統DSN里面就會出現剛才設置好的DSN名字,選中,然后輸入用戶名密碼,點兩次下一步就會出現選擇源表和視圖對話框
    4、這里要注意的是,勾上源中的某個表,在目的里面就會出現"用戶名"."表名"的默認選項,如果你剛才使用的Oracle用戶名是小寫的話,這里也會是小寫,一定要改成大寫,否則會提示該用戶名不存在

    目的也可以使用Microsoft OLE DB Provider for Oracle,在屬性里面設置服務器名稱為Oracle的TNS名稱,用戶名和密碼輸入Oracle用戶名和密碼,測試連接通過即可,后面的步驟都一樣。

    如果出現以下錯誤:

    OLE DB 提供程序 'MSDAORA' 報錯。

    [OLE/DB provider returned message: 未找到 Oracle 客戶端和網絡組件。這些組件是由 Oracle 公司提供的,是 Oracle 8i (或更高) 客戶軟件安裝的一部分。

     

    在安裝這些組件之前,將無法使用此提供程序。]

    OLE DB 錯誤跟蹤[OLE/DB Provider 'MSDAORA' IDBInitialize::Initialize returned 0x80004005:  


    就要修改注冊表,有人已經作出了詳細的修改說明,在這里可以看到:
    http://www.cnblogs.com/autumn/articles/splinkedserver.html

    我把那個表也貼在這里:
    Oracle Client  Microsoft Windows NT、
    Oracle Microsoft Windows 95、
    Client Windows 98 和 Windows 98 SE
    Microsoft Windows 2000/XP/2003
    7.x [HKEY_LOCAL_MACHINE\SOFTWARE
    \Microsoft\TransactionServer\Local Computer\My Computer]
    "OracleXaLib"="xa73.dll"
    "OracleSqlLib"="SQLLib18.dll"
    "OracleOciLib"="ociw32.dll

     

    [HKEY_LOCAL_MACHINE\SOFTWARE
    Microsoft\MSDTC\MTxOCI]
    "OracleXaLib"="xa73.dll"
     "OracleSqlLib"="SQLLib18.dll"
     "OracleOciLib"="ociw32.dll"
     
    8.0 [HKEY_LOCAL_MACHINE\SOFTWARE
    \Microsoft\Transaction Server
    \Local Computer\My Computer]
    "OracleXaLib"="xa80.dll"
    "OracleSqlLib"="sqllib80.dll"
    "OracleOciLib"="oci.dll"
     
    [HKEY_LOCAL_MACHINE\SOFTWARE
     \Microsoft\MSDTC\MTxOCI]
     "OracleXaLib"="xa80.dll"
     "OracleSqlLib"="sqllib80.dll"
    "OracleOciLib"="oci.dll"
    8.1 [HKEY_LOCAL_MACHINE\SOFTWARE
    \Microsoft\Transaction Server
    \Local Computer\My Computer]
    "OracleXaLib"="oraclient8.dll"
    "OracleSqlLib"="orasql8.dll"
    "OracleOciLib"="oci.dll"
     
    [HKEY_LOCAL_MACHINE\SOFTWARE
     \Microsoft\MSDTC\MTxOCI]
    "OracleXaLib"="oraclient8.dll"
    "OracleSqlLib"="orasql8.dll"
    "OracleOciLib"="oci.dll"
     
    9.0 [HKEY_LOCAL_MACHINE\SOFTWARE
    \Microsoft\Transaction Server
    \Local Computer\My Computer]
    "OracleXaLib"="oraclient9.dll"
    "OracleSqlLib"="orasql9.dll"
    "OracleOciLib"="oci.dll"
    [HKEY_LOCAL_MACHINE\SOFTWARE
     \Microsoft\MSDTC\MTxOCI]
    "OracleXaLib"="oraclient9.dll"
    "OracleSqlLib"="orasql9.dll"
    "OracleOciLib"="oci.dll"
     
    10.0 [HKEY_LOCAL_MACHINE\SOFTWARE
    \Microsoft\Transaction Server
    \Local Computer\My Computer]
    "OracleXaLib"="oraclient10.dll"
    "OracleSqlLib"="orasql10.dll"
    "OracleOciLib"="oci.dll"
    [HKEY_LOCAL_MACHINE\SOFTWARE
     \Microsoft\MSDTC\MTxOCI]
    "OracleXaLib"="oraclient10.dll"
    "OracleSqlLib"="orasql10.dll"
    "OracleOciLib"="oci.dll"
     
    posted @ 2012-04-28 10:22 amp@java 閱讀(2565) | 評論 (0)編輯 收藏

    當讀寫二進制文件,或者要把非標準長度的整數與標準長度的整數互相轉換時,就要用到大量的位操作,雖然看起來很簡單,實際上里面卻有很多細節很容易出錯。

    首先,Java有些標準跟C/C++是不同的:

    1、Java采用高字節在前的方式讀寫數據,例如要把一個4字節的int數值寫入文件時,它是按照從高字節到低字節的順序寫入的,讀取的時候也是這樣讀出來。
    而C/C++則采用平臺相關的方式,在Windows平臺采用低字節在前的方式,在Linux/Unix平臺則采用高字節在前的方式。
    如果Java要讀取C/C++創建的二進制文件,就要注意這個問題,最好先搞清楚原來的文件是采用哪種方式創建的。網絡通信也要注意。

    2、Java沒有無符號數,無論byte,short,int,long都是有符號整數,而C/C++有個unsigned關鍵字可以設置一個數值為無符號數。

    3、Java的整數基本數據類型就是byte,short,int,long這幾個,長度分別為1,2,4,8字節,C/C++可以用typedef定義各種數據類型。

    第二,Java是采用補碼來存放整數的。
    有時候覺得補碼的定義有些奇怪,實際上可以這樣理解:

    把一個整數從0一直往上加1,加到溢出就變成了負數的最小值,然后再繼續加1,最后又能回到0,實際上就是一個輪回。
    例如一個byte類型的整數,一共有8位,能表示256個數值,采用補碼的話數值范圍就是-128~127,表示方法如下:
    0        0000 0000
    1        0000 0001
    .
    .
    126    0111 1110
    127    0111 1111
    -128   1000 0000
    -127   1000 0001
    .
    .
    -1       1111 1111
    0         0000 0000

    第三、不同長度的整數轉換。
    如果是從較短的數轉成較長的數,很簡單,如果是正數就在高字節補0,如果是負數就在高字節補1。
    例如byte的127轉為short的127:
    byte:0111 1111
    short:0000 0000 0111 0111
    byte的-127轉為short的-127
    byte:1000 0001
    short:1111 1111 1000 0001
    如果是從較長的數轉成較短的數,實際上就是把高位都截斷了,所以轉出來的數值可能完全不是一回事了。
    例如short的256轉為byte:
    short:0000 0001 0000 0000
    byte: 0000 0000
    把256變成了0
    short的-255轉成byte:
    short:1111 1111 0000 0001
    byte:0000 0001
    把-255變成了1

    第四、位運算操作符及它們的優先級
    Java的位運算操作符包括:~非,|按位或,&按位與,^按位異或,<<左移,>>右移,>>>右移左側補0
    各種運算符的優先級如下表所示:
    優先級
    運算符
    結合性
    1
    () [] .
    從左到右
    2
    ! +(正) -(負) ~ ++ --
    從右向左
    3
    * / %
    從左向右
    4
    +(加) -(減)
    從左向右
    5
    << >> >>>
    從左向右
    6
    < <= > >= instanceof
    從左向右
    7
    == !=
    從左向右
    8
    &(按位與)
    從左向右
    9
    ^
    從左向右
    10
    |
    從左向右
    11
    &&
    從左向右
    12
    ||
    從左向右
    13
    ?:
    從右向左
    14
    = += -= *= /= %= &= |= ^= ~= <<= >>= >>>=
    從右向左
    根據該表可以看到,位運算操作符的優先級各有不同,分別為:
    1、~
    2、>> << >>>
    3、&
    4、^
    5、|
    另外需要特別注意的是,除了~,其他位運算操作的優先級都低于加減,所以要記得以下語句是返回32而不是7!
    1<<2+3
    還有就是&、^、|的優先級都是低于邏輯操作符的,因此下面的語句會編譯出錯,幸好Java不像C那樣對所有大于1的值都認為是真,否則下面的語句也能編譯通過,但可能與你的意圖不太一樣,可能調試半天才發現。
    if(3&1>0)
    如果記不清楚,還是按照你的意圖加上括號最保險。

    第五、字節數組與整數之間的轉換
    為了把一個整數存入文件,或者從文件中讀取一個整數,需要經常在字節數組和整數之間轉換,這個過程要用到大量的位運算。
    首先需要記住的是,在參與所有運算前,Java都會把byte、short類型的值都轉換成int,然后再對轉換后的int進行操作。例如下面的語句會編譯出錯:
    byte a=10,b=20,c;
    c=a+b;

    因為a和b在相加前都被轉成了int,最后得到的結果是個int類型的值,如果要賦給byte類型的c,必須顯式地進行類型轉換,即把第二句改為:
    c=(byte)(a+b)

    這一點很關鍵,因為對于一個最高位為1的byte類型的整數(負數),在運算之前它會被強制轉換成int類型,根據上面所說的第三點,其實就是往前面的三個高字節補上1,這樣一來,它在參與位運算的過程中,就不僅僅是它本身的8個bit參與了,實際上連前3個字節的24個bit(均為1)也參與了。例如有一個整數i=1082163328,它的二進制表示為:
    01000000 10000000 10000000 10000000
    分為4個字節存儲,除了第一個字節是正數外,其余3個字節均為負數。假如用a代表最高字節的值,用b代表其他三個字節的值,如果按照通常的理解,你可能會這樣得到i的值:
    i=(a<<24)+(b<<16)+(b<<8)+b

    如果a和b都是正數,上面的等式是成立的,但是在這個例子里,卻是錯的,因為上式中的a和b都已經被強制轉換成了int類型再參加運算,實際上
    a=00000000 00000000 00000000 01000000
    b=11111111 11111111 11111111 10000000
    i=01000000 00000000 00000000 00000000+11111111 10000000 00000000 00000000+11111111 11111111 10000000 00000000+11111111 11111111 11111111 10000000
    最后得到的結果是1065320320,不是原來的值了。
    為了不讓byte在強制轉換成int的過程加入了我們不想要的高位1,我們需要把它跟0xff進行與操作,i的值應該這樣運算:
    = ( ( a& 0xff ) << 24 ) +( ( b & 0xff ) << 16 ) + ( ( b & 0xff ) << 8 ) + ( b & 0xff )

    注意,因為&和<<的優先級都低于+,所以上面的括號是不能少的。不過由于跟0xff與操作之后,其余24位都變成了0,因此可以把+改為|操作,因為任何值與0進行或操作都得到本身:
    = ( a & 0xff ) << 24 | ( b & 0xff ) << 16 | ( b & 0xff ) << 8 | ( b & 0xff )

    由于<<的優先級高于|,所以省了一些括號。最高字節可以不與0xff進行與操作,因為它轉換成int后左邊增加的3個字節都在左移24位時被去掉了:
    = a << 24 | ( b & 0xff ) << 16 | ( b & 0xff ) << 8 | ( b & 0xff )


    把int轉為字節數組的時候比較簡單,直接右移截斷即可:
    byte[] b = new byte[4];
    b[0= (byte) (i >> 24);
    b[1= (byte) (i >> 16);
    b[2= (byte) (i >> 8);
    b[3= (byte) i;


    第六、非標準長度整數的存儲和讀取
    假如有兩個變量,他們的值可以用12個bit來表示,如果我們用16bit的short類型來表示一個變量,那么兩個變量就需要4個字節,而實際上它們只需要3個字節就能表示出來,如果存儲空間比較有限,寫入文件時可以把它們存放在3個字節里面,但是讀寫過程就需要進行轉換。
    在內存里,它們都是標準的數據類型:
    short a,b;

    寫入文件時,我們用第一個字節和第二個字節的前半部分來表示a,把第二個字節的后半部分和第三個字節來表示b,即:
    1:xxxx xxxx
    2:xxxx yyyy
    3:yyyy yyyy
    x和y都表示一個bit,分別用來存放a和b。寫入時先把a和b轉為字節數組:
    byte[] out = new byte[3];
    out[
    0= (byte) ( a >> 4 );//把a的高8位放在第一個字節
    out[1= (byte) ( a << 4 );//先把a左移四位,在右邊補上4個0,第二個字節的高4位就是a的低4位了,第二個字節的高4位已經生成,低4位還是0
    out[1|= (byte) ( b >> 8 & 0x0f );//b右移8位,并與0x0f進行與操作,實際上就只保留了b的高4位,并且是在字節的低4位上,跟第二步得到的字節進行或操作,就生成了第二個字節
    out[2= (byte) b;//把b的高4位截斷就得到了低8位
    然后再把這個字節數組寫入文件,就可以用3個字節表示兩個整數了。
    讀取:
    =(short)( (out[0& 0xff<< 4 | ( out[1& 0xf0 )>>4);
    = (short)((out[1& 0x0f<< 8 | ( out[2& 0xff));
    posted @ 2012-04-08 16:56 amp@java 閱讀(1840) | 評論 (2)編輯 收藏

    AdMob是往手機應用程序里添加廣告的最流行的方式,Android程序基本都是靠這個賺錢。看文檔似乎很簡單,但是操作起來卻不是那么回事,今天搞了一上午才弄明白怎么正確添加,網上搜索到的資料都不適合最新的SDK。

    按照AdMob的官方文檔,很簡單,只要把AdMob的開發包jar放到Build Path的Libraries里面就行了,這樣做編譯是沒問題的,但是一運行就會出錯,提示
    java.lang.NoClassDefFoundError:com.google.ads.AdView
    這是因為Google最近更新了ADT到17.0,改變了項目依賴的檢測方式,官方的說明在這里,不過看得不是很懂。有人用圖形的方式標了出來,容易理解一些,看這里。如果不求甚解,就把剛才放到Build Path里面的jar移除,直接在項目目錄下建立一個libs目錄,然后把那個jar文件放進去就行了。

    AdMob SDK也更新到了4.3.1,網上搜索到的在XML文件里面設置AdView屬性的方法也已過時,現在不需要建立attrs.xml文件,直接增加一個
    xmlns:ads="http://schemas.android.com/apk/lib/com.google.ads"
    就可以在AdView標簽里面設置ads開頭的屬性了,關于xml設置AdView屬性的官方文檔隱藏得比較深,沒有在目錄中列出來,只能在其他文檔里面的鏈接里進去,在這里
    另外,按照官方說明,要在AndroidManifest.xml里面添加一個Activity的聲明:
        <activity android:name="com.google.ads.AdActivity"
                  android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"/>
    后面那個屬性android:configChanges的最后兩個值screenSize|smallestScreenSize是在Android 3.2后面才增加的,這兩個值必須填上去,否則運行的時候會報錯。如果你使用的SDK是3.2以下的,識別不了這兩個值,編譯也不會報錯。因此你的項目必須使用Android 3.2以上的SDK,也就是項目根目錄下的project.properties文件里面的屬性target的值必須是android-13以上,例如
    target=android-15
    但是可以在AndroidManifest.xml里面設置android:minSdkVersion和android:targetSdkVersion為比13低的值,這樣就不需要安裝Android 3.2以上的手機或平板來運行這個程序,實際上AdMob支持Android 1.5以上的系統,只是開發需要更高版本的SDK而已。


    這次折騰讓我真正體會到Android更新得實在太快了,連官方的文檔都來不及更新,開發人員只能自己摸索總結,幸好有強大的搜索工具,只要你遇到的問題不是第一個,就會有人找到解決方案。



    posted @ 2012-03-25 19:23 amp@java 閱讀(3705) | 評論 (7)編輯 收藏

    SWT里TableEditor的作用是可以在表格里面顯示一些控件,例如列表、按鈕等,有時候是根據表格的內容在控件上顯示不同內容的,如果更新了表格內容,就要同時更新控件,但是表格內容可以通過Table控件的removeAll()來清除,而表格中的控件則無法用這個方法清除,你調用Table的removeAll()方法,往表格里填入新內容后,控件還是上次的控件,但是你一操作那些控件就會出異常,提示那些控件已經disposed。

    解決方法是顯式地調用控件及TableEditor的dispose()方法,在你建立TableEditor的時候,把它的引用保存起來,把里面的控件的引用也保存起來,到整個表格需要的清除的時候,通過引用先把控件dispose掉,再把TableEditor也dispose掉,這樣整個表格的內容就真正清除了。

    例如有一個表格名為table,里面的每一行都有3列,第一列是文本,第二列是Combo,第三列是Button,繪制表格的時候是這樣的:

    TableItem ti = new TableItem(table,SWT.NONE);
    ti.setText(
    0,"some string");
    te 
    = new TableEditor(table);
    Combo combo 
    = new Combo(table,SWT.NONE);
    controls.add(combo);
    te.setEditor(combo,ti,
    1);
    Button button 
    = new Button(table,SWT.NONE);
    controls.add(button);
    te.setEditor(button,ti,
    2);

    其中te和controls都是成員變量,te的類型是TableEditor,controls的類型是ArrayList<Control>。
    當整個table要清除內容時,可以這樣:
    //刪除控件
    for(Control control:controls){
    control.dispose();
    }
    //刪除TableEditor
    te.dispose();
    //刪除文本
    table.removeAll();
    posted @ 2012-03-09 11:09 amp@java 閱讀(3850) | 評論 (0)編輯 收藏

    mars課程里關于Socket通信那一課說那些程序只能在真機上運行,模擬器模擬不了,實際上是可以的。
    Android模擬器是通過一個類似路由器的虛擬網絡層與電腦相連,可以看作模擬器是處于“內網”當中,每個模擬器都有自己的虛擬路由器,而且虛擬路由器的地址總是10.0.2.1,在模擬器看來,電腦的地址是10.0.2.2,模擬器自己的地址是10.0.2.15,無論你啟動多少個模擬器,對于模擬器來說都是這樣的地址,模擬器之間不能直接通信。
    啟動模擬器的時候,電腦會給模擬器分配兩個端口,通過這兩個端口,電腦就能操作模擬器。第一個啟動的模擬器的端口是5554和5555,第二個是5556和5557,以此類推,最多可以同時啟動32個模擬器。第一個端口(偶數端口)可以接受telnet連接,對模擬器進行設置,第二個端口(奇數端口)則接受adb連接,可以用來調試。第一個端口可以在模擬器窗口的標題欄看到,如下圖所示:

    5554表示端口號,t表示模擬器名稱。
    實際上,這些端口也是電腦監聽的端口,在電腦上通過netstat可以看到本機正在監聽這些端口,因此通過telnet localhost 5554就能連上第一臺模擬器,連上之后通過help命令可以查看操作幫助。
    為了實現電腦和模擬器上的android程序進行socket通信,需要把程序開啟的端口通過端口映射設置到電腦上,這跟家里的路由器端口映射概念是一樣的。telnet到模擬器之后,通過
    redir add tcp:1234:1234
    就能把模擬器上的1234端口映射到電腦上,第一個表示電腦端口,第二個表示模擬器程序要使用端口,這兩個數字可以相同也可以不同,要映射udp端口就把tcp改為udp即可
    redir add udp:1234:1234
    這樣一來,當模擬器的程序打開1234端口時,在電腦上也打開了對應的端口,只要通過電腦連接127.0.0.1的對應端口,就連上了模擬器的程序端口,就可以通過電腦上的client向模擬器的server發送數據,不需要通過真機運行。
    如果要讓第一個模擬器向第二個模擬器發送數據,也可以把第二個模擬器的端口映射到電腦上,然后在第一個模擬器程序中向10.0.2.2的對應端口發送數據即可。


    模擬器還有一個很有意思的功能,每個模擬器默認的電話號碼就是它的第一個端口號,例如開了兩個模擬器,第一個撥打5556,第二個就會顯示5554來電,還能接通,發短信也可以,這樣就能模擬電話和短信功能。

    詳細的信息可以看Dev Guide的模擬器部分:http://developer.android.com/guide/developing/devices/emulator.html
    posted @ 2012-02-24 10:37 amp@java 閱讀(2413) | 評論 (0)編輯 收藏

    前天是情人節,雖然結婚好多年了,但是老婆一直都喜歡驚喜的浪漫,可惜我卻是個木訥的呆子,做不出那些轟動的事情。那天下午馬上就要下班回家了,突然在微博上看到有人談到geek的情人節禮物,雖然我不是geek,但是最近在學Android,老婆的手機也是Android系統的,何不專門做個程序給她?

    想法可嘉,但是動起手來卻不是那么回事。學了那么多天,真正派上用場的還沒學到。時間只剩下不到一個小時了,我會的只是在屏幕上顯示幾個大字:XXX,我愛你!

    后來想想似乎太單調,如果能夠加上點背景音樂可能好點,但是還沒學會怎么使用,上網搜了一下,幸好很簡單,用MediaPlayer就可以了,幾條語句就能搞定。音樂文件怎么來呢?通過網絡在線播放是最簡單的,于是就到百度MP3搜了一下“情人節快樂”,我記得有一首歌里面一直在喊“情人節快樂”的,結果最后發現那首歌名字叫《沒有情人的情人節》……

    算了,管它呢,有老婆就行了,沒有情人照樣過情人節,打開發現鏈接居然是百度的,以前百度不是說它只負責搜索,不負責存放嗎,怎么現在的MP3都放在百度的服務器了?把鏈接復制下來,在模擬器上運行還是挺好的,因為它用的是電腦的寬帶,呵呵。不過過了一會提示下載失敗,把那個地址往瀏覽器一貼,果然打不開了,原來百度這種下載鏈接是有有效期的,只能讓你試聽一下,然后下載,不是長期有效的。這就麻煩了,到時候裝在手機上沒聲音豈不是很糗?

    再搜索一下,還好,可以把MP3文件放在assets里面,發布程序的時候把它包含在apk里面就行了,不用聯網了。

    現在可以在顯示大字的同時播放《沒有情人的情人節》了。看了一下效果,還是有點怪異,手機的狀態欄和程序的標題跟黑色的背景,紅色的大字似乎不太搭配,于是繼續搜索全屏代碼,哈哈,兩句搞定,這樣炫多了。

    不過一直看著那幾個字沒任何反應,似乎太單調了,于是就想讓它們不斷變色,或者動一下也好,但是無論怎么弄都搞不定,下班時間到了,要去接老婆了,就這樣吧。

    之前都是在模擬器上運行,或者接個USB在手機上運行,還不知道怎么打包成apk呢,這下居然沒搜索到,可能太簡單了,大家都沒說。于是在項目上點右鍵,果然看到導出apk的菜單,我選擇了unsigned方式導出,在手機上居然安裝不了。再搜索一下,哦,原來是要導出成signed apk才能裝的,但是我沒有證書,怎么signed呢?沒想到ADT還可以生成證書,一下就搞定了,這比Symbian那種簽名簡單多了,但是可能也是導致Android惡意軟件泛濫的原因之一。

    去接老婆的時候通過藍牙把apk發到她手機上,裝上,運行,從她表情上看出,我的努力沒有白費。不過最后還是發現了個嚴重的bug,那首歌還沒放完,另外一個聲音已經重新開始了,形成了“二重唱”的效果,而且程序退出之后還在唱,趕工造成的悲劇啊。

    下面是代碼:
    public class LoveActivity extends Activity {
        TextView text;
        
    /** Called when the activity is first created. */
        @Override
        
    public void onCreate(Bundle savedInstanceState) {
            
    super.onCreate(savedInstanceState);
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,   
            WindowManager.LayoutParams.FLAG_FULLSCREEN);  
            requestWindowFeature(Window.FEATURE_NO_TITLE);  
            setContentView(R.layout.main); 
            MediaPlayer mp 
    = new MediaPlayer();
            
    try{
                AssetManager assetManager 
    = getAssets();
                AssetFileDescriptor afd 
    = assetManager.openFd("a.mp3");
                mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
                mp.prepare();
                mp.start();
            }
            
    catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    main.xml:
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation
    ="vertical"
        android:layout_width
    ="fill_parent"
        android:layout_height
    ="fill_parent"
        
    >
        
    <TextView 
        
    android:id="@+id/textView1" 
        android:text
    ="@string/loveyou" 
        android:layout_width
    ="match_parent" 
        android:layout_height
    ="match_parent" 
        android:gravity
    ="center" 
        android:textColor
    ="#ff0000"
        android:textStyle
    ="bold"
        android:textSize
    ="50dip"
        
    />
        
       
    </LinearLayout>
    strings.xml:
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        
    <string name="hello">Hello World, LoveActivity!</string>
        
    <string name="app_name">Love</string>
        
    <string name="loveyou">XXX\n我愛你</string>
    </resources>
    再把那首mp3放到assets里,改名為a.mp3即可。




    希望明年能做出個更好的。
    posted @ 2012-02-16 11:06 amp@java 閱讀(2295) | 評論 (2)編輯 收藏

    昨天在調試一段Android程序的時候發現總是出現NullPointerException,是來自一句System.out.println(),但是把里面的內容分拆了幾次都找不到哪里有null,最后發現居然是因為最終輸出的字符串是null!

    一直以來,在JavaSE里,如果字符串本身是null,System.out.println()打印該字符串,會在終端輸出“null”,而在Android里卻是直接拋出NullPointerException,整個程序都會被終止。

    大家可以測試一下下面的語句在兩種環境下的運行結果:
    1 String s = null;
    2 System.out.println(s);
    posted @ 2012-02-13 14:49 amp@java 閱讀(1378) | 評論 (1)編輯 收藏

    這是mars課程里面關于handler和線程的一個例子:
    package mars.handler;

    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;

    public class HandlerTest extends Activity {
        Handler handler 
    = new Handler();
        
    /** Called when the activity is first created. */
        @Override
        
    public void onCreate(Bundle savedInstanceState) {
            
    super.onCreate(savedInstanceState);
            System.out.println(
    "1");
            handler.post(r);
            System.out.println(
    "2");
            setContentView(R.layout.main);
            System.out.println(
    "activity---->"+Thread.currentThread().getId());
            System.out.println(
    "activity name--->"+Thread.currentThread().getName());
        }
        
        Runnable r 
    = new Runnable() {
            
            @Override
            
    public void run() {
                
    // TODO Auto-generated method stub
                System.out.println("handler---->"+Thread.currentThread().getId());
                System.out.println(
    "handlername---->"+Thread.currentThread().getName());
                
    try {
                    Thread.sleep(
    10000);
                } 
    catch (InterruptedException e) {
                    
    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(
    "3");
            }
        };
    }

    根據mars的解釋,handler所在的線程跟Activity的線程是同一個線程,所以在
    handler.post(r);
    語句后,執行的是Runnable里面的run函數,這個函數沒有在新開的線程中執行,只是簡單地調用了run函數,所以這個app在模擬器運行時要過10秒才會顯示界面,因為run函數里面睡眠了10秒,等它返回后才執行setContentView函數設置界面元素。
    根據實際運行結果,的確是過了10秒才能顯示界面。

    但是奇怪的是System.out語句似乎沒有受到影響,下面是日志:
    log
    02-09 11:12:43.553: INFO/System.out(591): 1
    02-09 11:12:43.553: INFO/System.out(591): 2
    02-09 11:12:43.674: INFO/System.out(591): activity---->1
    02-09 11:12:43.674: INFO/System.out(591): activity name--->main
    02-09 11:12:43.713: INFO/System.out(591): handler---->1
    02-09 11:12:43.713: INFO/System.out(591): handlername---->main
    02-09 11:12:53.775: INFO/System.out(591): 3

    從日志可以看出,除了run函數里面睡眠后才執行的打印函數推遲了10秒才執行之外,其他都是沒有受到任何延時,順序執行的,在
    handler.post(r);
    語句前后的打印函數都被按順序執行了,唯獨
    setContentView(R.layout.main);
    需要在run函數返回后才執行,這是什么道理?難道打印函數的優先級更高,不會堵塞?如果是這樣的話為什么在run函數里面還是要等睡眠結束才執行呢?
    posted @ 2012-02-09 19:25 amp@java 閱讀(1837) | 評論 (6)編輯 收藏

    很想搞點Android的小程序玩玩,但是卻萬事開頭難,不知道從哪里開始,看了官方的文檔,結果一天都看不了幾段,還是英文的,比較痛苦。找了些電子書,也是看過目錄就不知道放哪里了。這種編程的入門沒有強大的決心真的很難靜下心來學習。
    前幾天又心血來潮,搜索了一下android開發的網站,發現了一些視頻,看起來還挺有意思,連續看了幾個,慢慢地也摸著一點門路了,以前沒有試過用這種方法學習,都是看書,現在發現看視頻似乎更高效,起碼眼睛沒那么累,有人在念,很多時候只要用耳朵聽就行了,而且所有軟件的界面、步驟都很清楚,這些東西通過書是沒法表現出來的。
    現在學會了讓一個Activity顯示出來,放上點控件,處理一下點擊,頁面布局等,算是入門了,但很多東西還要繼續看,那些視頻還有好多。
    入門系列視頻地址:
    http://www.marsdroid.org/
    還有一個深入淺出系列:
    http://www.eoeandroid.com/thread-109361-1-1.html
    由于沒有入門,所以還在看第一個系列,第二個系列只看了兩個。
    到現在發現android界面的構建很像web界面,android是通過layout來排布控件,而web是通過css,android可以通過java來操縱控件,而web則是通過javascript操縱控件,回調函數則跟JavaSE一樣。



    不過有時候很容易忘記了一個步驟導致程序運行出錯,一般來說,要讓一個Activity成功運行,需要做以下步驟:
    1、有一個繼承與Activity的類
    2、有一個layout文件,里面是各種控件的布局,在Activity里面應該用setContentView加載這個layout
    3、有一個strings文件,里面是界面的各種字符串,用于國際化
    4、在AndroidManifest里面加入這個Activity
    第4步很容易忘記。
    posted @ 2012-02-08 14:55 amp@java 閱讀(261) | 評論 (0)編輯 收藏

    前段時間聽了一家公司介紹分布式存儲產品,號稱性能超過傳統的磁盤陣列+小型機,但價格卻比這種組合低,而且具有維護簡單、數據安全等優點,其核心就是把一些PC服務器通過網絡連接起來,把數據分散存儲在這些服務器上,查找的時候把任務分配到這些服務器上,讓它們分別完成各自的小任務,最后再匯合出結果,核心就是:每個節點都是一個數據存儲單元和運算單元的結合,這些節點性能要求不高,可以是各種各樣的配置,只要在上面運行集群要求的軟件即可,一臺掛了不要緊,換上去一臺就能自動恢復,增加一臺就能提高性能,減少一臺也不會有很大影響,只是性能稍微下降,每份數據都有多個備份,能夠平衡分布在各服務器上。這種架構的缺點是,只要用上了這套東西,所有的軟件就必須從這家公司購買,因為整個集群的控制和訪問接口都是他們提供的。
    該公司也坦言這其實就是google的服務器應用技術,實際上就是google提出來的云計算。

    今天看了一些文章介紹,發現上面介紹的東西實際上已經通過Apache的一個項目Hadoop實現,不知道那家公司是不是就是簡單包裝了一下這個項目。

    Hadoop包含兩個主要的模塊,分別是HDFS分布式文件系統和MapReduce集群計算機制。剛剛發布了1.0.0版本。

    主頁: http://hadoop.apache.org/

    blogjava有位高手已經翻譯了HDFS的架構說明:http://m.tkk7.com/killme2008/archive/2008/06/05/206043.html,但對應的是上一個版本0.20的,里面說到了很多沒有實現的東西,不知道是否已經在1.0版本實現,目前官方網站上該文章的版本還是0.20的。

    這里有三篇文章介紹Hadoop在單機環境、多機環境下的安裝和配置,還有應用程序的開發:http://www.ibm.com/developerworks/cn/linux/l-hadoop-1/index.html

    看起來還是挺有意思的,以前就曾經有過想法,把單位淘汰下來的那一大堆臺式電腦組成一個存儲或者計算的小集群,也許能夠代替一兩臺PC服務器,現在看來可以試試,以后的趨勢就是云計算了,先自己搞點小云看看效果如何。
    posted @ 2012-01-19 14:47 amp@java 閱讀(224) | 評論 (0)編輯 收藏

    這個不僅僅是IE6的錯,而是所有IE的錯!!
    IE有一個特別隨意的功能,就是能夠通過Element的name來操作一個Element,有些人覺得這個功能很方便,實際它不僅不符合標準,還會導致IE自己變得莫名其妙。
    假如你的Form有一個提交按鈕的name="submit",那么,很遺憾,你這個form無論如何都不能通過Javascript來提交,只要你一調用了這個form的submit()方法,IE就會告訴你它不支持這個方法!這不是搞笑嗎?哪個瀏覽器會不支持form的submit()方法?雖然IE不標準,也不至于這樣吧?對不起,就是這樣。

    因為當你調用form的方法submit(),它首先想到的是你的提交按鈕!
    theForm.submit()
    這個語句在IE看來并不是調用theForm的submit方法,而是調用了名字為submit的提交按鈕!如果你在某個元素對象后面加個括號,會有什么效果?當然就是出錯。在IE的獨特視角下,上面這個語句與下面這個語句的效果一樣:
    (theForm.submit)();
    前一個括號代表了名稱為submit的按鈕對象,后面那個括號就無法理解了,所以IE告訴你不支持這個方法。

    IE整個家族都是如此的丑陋!

    posted @ 2010-12-09 15:02 amp@java 閱讀(292) | 評論 (0)編輯 收藏

    一直都看到很多人說,IE6是Web開發人員的惡夢,以前我單位的內部網絡,所有電腦裝的都是IE6,我只針對IE6開發,似乎沒什么感覺,反正在我的電腦上看到什么樣的,其他電腦上看到也是一樣的。
    后來因為某公司給我們做的一個系統運行速度實在太慢,我把自己的電腦更新到IE8,發現速度快了很多,但是有些東西不兼容,我對那些不兼容的功能使用得比較少,就不管了。
    終于,我自己又要開發一個小項目,用了一個網上下載的CSS模板,發現里面很多針對IE的注釋,從IE 5到IE 8都有,反正我電腦上看著效果不錯,于是就用了。
    辛苦了好幾天,我那項目基本完工了,想在IE6上看看效果,Shit,本來顯示在頁面右方主要區域的表格掉在了左邊導航欄的下面,表格里面一些DIV的下劃線莫名其妙地不見了,這些東西在我的電腦上顯示得好好的,也沒用到什么特別的東西,怎么差別會這么大呢?
    一個個問題排查:
    表格問題,在IE6上表現得有些詭異,顯示完之后表格是在下面的,但是鼠標晃過導航欄里面的鏈接,表格又會自動跳到右方區域,真見鬼。改了一下布局的padding,一個表格好了。另外一個卻還是掉下去,仔細研究了一下,把表格的寬度減少10px,好了。
    下劃線問題,我用的是:
    border-bottom:1px solid grey
    結果IE6不會顯示出這條下劃線。搜索一下才知道這是IE6的bug,它理解不了這么長的句子!必須寫成這樣:
    border-bottom-width:1px;
    border-bottom-style:solid;
    border-bottom-color:grey;
    還有比這更傻逼的嗎?有!
    它顯示出的線是黑色的,不是grey的!而且根據DIV里面內容的顏色不同,它還會變色!如果里面是紅色的字,那么它下面的線也是紅色,如果是綠色的字,下面的線也是綠色,如果沒有指定顏色,它就是黑色,非常智能,但就是不顯示你要的顏色!
    后來知道原來它根本不知道grey的意思,必須指定顏色代碼才能解決。


    這就是IE6,沒想到微軟這么大一個公司還出了這么一個垃圾,而且出了那么多年,至今還占據中國瀏覽器市場的半壁江山!



    posted @ 2010-12-08 20:51 amp@java 閱讀(545) | 評論 (4)編輯 收藏

    有一臺WIN2003的服務器,在單位的局域網內,與互聯網是物理隔離的,最近上面運行的一個WEB服務器經常出錯,查看日志發現是因為數據庫不能連接,因為系統的所有端口都已經被占用完。使用netstat -abn查看發現svchost.exe開啟了大量狀態為SYN_SENT的連接,目標端口都是445,但是連接的IP各種各樣的都有,由于機器不能建立Internet連接,所以狀態都是SYN_SENT,重啟一下這些連接都沒有了,但是過一會又會迅速建立起來,很快就把系統的所有端口都占用了。
    根據端口找出哪個服務真不容易,通過netstat -abn只能查到是svchost.exe,最多還能得到一個PID,確定是哪個svchost.exe,然后通過tasklist /svc可以查到那個svchost對應了哪些服務,但是一看,很多服務都是使用那個svchost,包括Server,Workstation等等,根本不知道是哪個產生的連接。
    找了半天發現有人和我一樣:http://www.petri.co.il/forums/showthread.php?t=36427,討論了半天最后也找到了解決方法:http://www.symantec.com/security_response/writeup.jsp?docid=2009-011316-0247-99,原來是W32.Downadup這個病毒惹的禍,下載了專殺工具回來查了一下,果然找到了兩個被感染的文件,一個是jpg文件,在IE的緩存里,一個是dll文件,在system32里。
    根據dll文件名在注冊表里查到了它注冊的服務,原來又是之前處理過的那種,服務名隨機、服務描述為空、啟動類型為自動、狀態為未啟動、dll名隨機,但是我記得這臺服務器已經打過補丁,也沒有出現svchost錯誤,所以就忽略了服務的檢查,沒想到這種東西還有不同的癥狀。
    這個病毒利用的是KB958644的漏洞,到微軟下載了補丁回來,一看才發現原來那臺服務器以前已經裝過這個補丁。補丁的作用也許就是只能防止再出問題,但不能解決已有的問題,所以那臺服務器雖然裝了補丁,但是可能已經被感染了,于是就沒治好。

    posted @ 2010-06-30 11:33 amp@java 閱讀(11964) | 評論 (1)編輯 收藏

    把APE、FLAC等無損壓縮音頻文件刻錄成CD的軟件有很多,搜索一把,出現頻率最多的是用NERO+插件,但是現在的NERO體積實在龐大,我嘗試下載一個NERO 10,大小不過200多M,結果安裝的時候解壓到臨時文件夾,我的C盤1G多的空間都不夠它解壓,根本就安裝不了,為了這么一點事情用這么大一個軟件實在沒必要,仔細搜索一下,刻錄的軟件其實有很多,都能自動地把APE刻錄到CD上,方法遠比NERO簡單。
    第一個軟件是Burrrn
    Burrrn是個專門干這事的軟件,它支持的文件包括ape、flac、mp3、ogg等,實際上也是通過插件來完成編碼解碼工作的,不過這些插件都是內置在程序包里,不用再逐個下載。它的界面非常簡單,使用也非常簡單,基本一打開就會使用。
    第二個軟件是ImgBurn
    這個軟件比較強大,不但能夠刻錄APE,還可以把光盤提取成鏡像、把文件或文件夾生成鏡像、把文件或文件夾刻錄到光盤上、把鏡像刻錄到光盤上,基本上NERO常用的功能都有了,軟件只有幾MB,十分環保。我下載這個軟件的時候只是想使用它的生成鏡像功能,因為下載下來一些藍光原盤需要制作成ISO文件才能用POWERDVD播放。后來發現有人說這個軟件還可以刻錄APE,不過也需要使用相關的解碼器,只是這些解碼器在安裝常用的播放器的時候一般都已經安裝過了,例如我以前裝過終極解碼,其中包含APE解碼器,就不需要另外安裝了。
    使用的時候只需要選擇刻錄鏡像到光盤功能,選中與APE相關的cue文件,然后就可以分軌刻錄了。

    這兩個軟件的體積都很小,而且都是免費軟件,不但環保還合法。

    第一次使用Burrrn刻錄APE的時候,用KMPlayer播放,發現直接播放APE的效果跟播放刻錄出來的CD效果不一樣,CD的效果動態范圍明顯不如直接播放APE,我以為是刻錄軟件的問題,后來使用ImgBurn刻錄,也是一樣的效果。仔細對比之后發現KMP播放的時候是使用不同的濾鏡,可能是這個原因導致效果不同,但是播放APE和播放CD又不可能使用相同的濾鏡,所以到底是什么原因也很難說得清楚,不過CD機上不認APE,也只能這樣了。


    posted @ 2010-06-22 15:30 amp@java 閱讀(584) | 評論 (0)編輯 收藏

    1、服務命名。Oracle的服務命名就跟計算機的名稱一樣。一般來說,在局域網里面,計算機名稱是與IP一一對應的,通信的時候需要使用IP,所以就有了DNS,把計算機名翻譯成IP。同樣的道理,在Oracle體系里,服務命名對應計算機名,服務名(SID)+IP+端口+協議(TCP/IP)就對應了計算機的IP,Oracle體系里的DNS其實就是一個配置文件,把服務命名翻譯成可以用于通信的服務名(SID)+IP+端口+協議(TCP/IP)。有趣的是,與計算機里的ping命令一樣,Oracle里面也有個TNSPing命令,通過“TNSPing 服務命名”,就會得到像ping命令相似的結果,驗證該命名對應的數據庫是否有效。

    2、主機身份驗證。Oracle的一些維護工作往往需要輸入主機身份驗證信息,但是默認情況下,即使輸入了正確的用戶名和密碼,系統也會提示“用戶口令錯誤”,讓人十分困惑。其實真實的原因是,你輸入的用戶必須在“作為批處理作業登錄”里面,否則就會出現上述錯誤。操作方法如下:運行-gpedit.msc-計算機配置-Windows設置-安全設置-本地策略-用戶權利指派-作為批處理作業登錄-添加用戶或組...-加入要登錄的用戶。
    執行數據庫遷移操作的時候,可能需要在源數據庫主機和目標數據庫主機都進行上述操作才能成功。

    更多問題待續
    posted @ 2009-11-12 10:23 amp@java 閱讀(280) | 評論 (0)編輯 收藏

    9月10號,CHDBits開放了注冊權限,趕緊注冊了一個帳戶,這是我第一次登錄PT站。每個文件都有幾個甚至幾十個種子在等待下載者,真是“僧多粥少”。下載速度果然很猛,下了幾個文件,基本上可以達到ADSL的上限,甚至遇到了前所未有的極速,不過持續時間較短,但是平均速度都接近上限。
    然而,ADSL小水管終究不是玩PT的料,嚴格的分享率要求和ADSL龜速的上傳帶寬使得我兩天之后就變成了冰人,如果20天之內再不提高分享率,我的帳戶將會被封禁。仔細考慮了一下,我還是“過把癮就死”算了,因為以我這8:1的上傳和下載帶寬,要長期達到要求基本上是不可能的事情,如果要我的分享率達到1:1,那我4M的下載帶寬就等于縮水成和上傳帶寬一樣,只有512K了,我裝這4M的寬帶還有什么意義?
    其實在PT站外下載,速度也是不錯的,無論是emule還是BT都能達到上限的80%以上,當然,是在種子剛剛放出的一段時間,只要熱度一過,速度馬上下降,這是與PT沒法比的。
    還是等到哪一天光纖到戶再玩PT吧,現在的任務就是趁著20天沒過,趕緊“過癮”,嘿嘿!
    posted @ 2009-09-14 19:44 amp@java 閱讀(294) | 評論 (2)編輯 收藏

    VISTA和WIN7都有一種OEM激活法,該激活方式需要以下三個條件:
    1、BIOS中有相應廠商的SLIC,VISTA要求SLIC 2.0,WIN7則要求SLIC 2.1。一般來說,品牌機的BIOS里面本來都帶有SLIC,不過有的沒打開(例如DELL的OPTIPLEX系列),需要用一些小工具打開(例如Asset);有的版本是2.0的,只能用來激活VISTA,如果要激活WIN7,需要更新SLIC,但更新官方的BIOS并不會更新SLIC,因此還需要找到專門的修改過的BIOS文件來更新。
    2、安裝的VISTA或者WIN7導入了相應的OEM廠商的證書,如果安裝的系統是OEM版的,安裝完之后證書就在里面了;如果安裝的是普通版本的,還需要手動導入,命令為:
    slmgr.vbs -ilc <證書路徑>
    一般每個廠商都只有一個證書,而且VISTA和WIN7的證書是相同的,也就是說相同的證書可同時用于VISTA或者WIN7。
    3、所安裝的VISTA或WIN7的key,與證書不同,key是每個版本的Windows一個,HomeBasic,HomePremium,Business,Ultimate等版本分別有各自的key,VISTA和WIN7的key也是不同的。導入key的方式是運行以下命令:
    slmgr.vbs -ipk <key>
    如果安裝的時候輸入了相應的key就不用這一步了。

    同時具備了上述條件的VISTA和WIN7就被激活了,這些條件不需要按順序來準備,只要具備即可,也就是說系統安裝后再刷BIOS,或者系統安裝前刷BIOS都是可以的。
     關于BIOS的信息,可瀏覽: 
    http://www.bios.net.cn

    關于Windows的信息,可瀏覽:
    http://www.pcbeta.com
    posted @ 2009-08-17 21:22 amp@java 閱讀(356) | 評論 (0)編輯 收藏

    jQuery UI里面只有一個DatePicker,只能選擇日期,不能選擇時間,有人做了一個可以選擇時間的DateTimePicker,在這里(http://razum.si/jQuery-calendar/TimeCalendar.html)可以看到,把jquery.js,jquery-calendar.js,jquery-calendar.css下回來之后就可以用了。
    但是有幾個Bug需要自己修改:
    1、當輸入框里面的時間是0點時,控件顯示不完整,這是因為有個函數有bug,如下所示:

    ???? /* ?Ensure?numbers?are?not?treated?as?octal.? */
    ????trimNumber:?
    function (value)?{
    ????????
    if ?(value? == ?'')
    ????????????
    return ?'';
    ????????
    while ?(value.charAt( 0 )? == ?' 0 '? )?{
    ????????????value?
    = ?value.substring( 1 );
    ????????}
    ????????
    return ?value;
    ????},

    ???????? while ?(value.charAt( 0 )? == ?' 0 '? )?{
    ????????????value?
    = ?value.substring( 1 );
    ????????}

    這一句,如果是0點的話,最終會出錯,因為它的長度最后是1,不能執行substring(1),改成下面就好了:

    ???? /* ?Ensure?numbers?are?not?treated?as?octal.? */
    ????trimNumber:?
    function (value)?{
    ????????
    if ?(value? == ?'')
    ????????????
    return ?'';
    ????????
    while ?(value.charAt( 0 )? == ?' 0 '? && ?value.length >1 )?{
    ????????????value?
    = ?value.substring( 1 );
    ????????}
    ????????
    return ?value;
    ????},

    2、作者是在jQuery 1.1.2版本下實現的,現在最新版本是1.3.2,這個控件在1.3.2下會出現異常,不能選擇日期,這是因為有幾個選擇器有問題:
    ?1?????????$('.calendar_daysRow?td[a]').hover(?//?highlight?current?day
    ?2?????????????function()?{
    ?3?????????????????$(this).addClass('calendar_daysCellOver');
    ?4?????????????},?function()?{
    ?5?????????????????$(this).removeClass('calendar_daysCellOver');
    ?6?????????});
    ?7?????????$('.calendar_daysRow?td[a]').click(function()?{?//?select?day
    ?8?????????????popUpCal.selectedDay?=?$("a",this).html();
    ?9?????????????popUpCal.selectDate();
    10?????????});
    上面的$('.calendar_daysRow?td[a]')在jQuery 1.3.2中不能使用,$("a",this)也是有問題的,同時,在FireFox中,<a>的不能設置背景顏色,所以hover函數不起作用,把它設在<td>也能達到相同的效果,改成以下代碼即可:
    ?1?????????//$('.calendar_daysRow?td?a').hover(?//?highlight?current?day
    ?2?????????$('.calendar_daysRow?td').hover(?//?highlight?current?day
    ?3?????????????function()?{
    ?4?????????????????$(this).addClass('calendar_daysCellOver');
    ?5?????????????},?function()?{
    ?6?????????????????$(this).removeClass('calendar_daysCellOver');
    ?7?????????});
    ?8?????????//$('.calendar_daysRow?td[a]').click(function()?{?//?select?day
    ?9?????????$('.calendar_daysRow?td?a').click(function()?{?//?select?day
    10?????????????//alert("click");
    11?????????????//popUpCal.selectedDay?=?$("a",this).html();
    12?????????????popUpCal.selectedDay?=?$(this).html();
    13?????????????popUpCal.selectDate();
    14?????????});

    經過修改之后在IE7和FireFox3都能在jQuery 1.3.2環境下正常運行。
    posted @ 2009-05-22 19:37 amp@java 閱讀(41555) | 評論 (19)編輯 收藏

    初次使用jQuery,發現真是個好東西,把很多東西都簡化了,循環基本上都去掉了,可以說是開創了JS的一種新模式,雖然開始覺得有點不習慣,但是很容易學習也很容易看懂。一個神奇的$原來有那么多的功能,很強大,呵呵。
    最讓人欣慰的是它屏蔽了所有瀏覽器的差別,可以在各種瀏覽器上用相同的代碼實現相同的效果。

    posted @ 2009-05-21 18:42 amp@java 閱讀(263) | 評論 (0)編輯 收藏

    二維條形碼比普通的條形碼能保存更多的信息,已經應用到很多領域里面。例如手機電影票,就是一個嵌在彩信里面的二維碼圖像。南航也推出了網上辦理登機牌業務,辦理完成之后往手機發送一條包含二維碼的彩信,到了機場就可以通過自助設備掃描二維碼,打印登機牌。
    然而,專業的二維碼掃描設備價格十分昂貴,最便宜的都在1000元以上,到淘寶上搜搜就知道了。借助Java和一個開源的庫,我們卻可以通過普通的網絡攝像頭實現相同的效果,成本只需要幾十塊。
    Open Source QR Code Library是一個開源的QR Code(二維條形碼的一種)生成和讀取的庫,官方網站為:http://qrcode.sourceforge.jp/,里面包含了生成和讀取QR Code的所有代碼,其中有個jmfexample就能實現通過攝像頭讀取QR Code,經過本人嘗試,幾十塊的普通攝像頭效果已經不錯了,一次讀取幾百字節都沒問題。
    使用這個庫的步驟如下:
    1、到其官方網站下載回來;
    2、到sun的網站下載JMF包并安裝;
    3、插上攝像頭,打開我的電腦,查看是否出現“USB視頻設備”,然后打開,看攝像頭工作是否正常
    4、運行JMF里面的JMF Registry程序,點擊“Detect Capture Devices”,查找視頻設備,查找到之后會在左邊的列表里出現“vfw:Microsoft WDM Image Capture (Win32):0”類似的設備,點擊就會在右邊出現其詳細信息,我的攝像頭是這樣的:
    Name = vfw:Microsoft WDM Image Capture (Win32):0

    Locator = vfw://0

    Output Formats---->

    0. javax.media.format.YUVFormat
    ? YUV Video Format: Size = java.awt.Dimension[width=640,height=480] MaxDataLength = 614400 DataType = class [B yuvType = 32 StrideY = 1280 StrideUV = 1280 OffsetY = 0 OffsetU = 1 OffsetV = 3

    1. javax.media.format.YUVFormat
    ? YUV Video Format: Size = java.awt.Dimension[width=160,height=120] MaxDataLength = 38400 DataType = class [B yuvType = 32 StrideY = 320 StrideUV = 320 OffsetY = 0 OffsetU = 1 OffsetV = 3

    2. javax.media.format.YUVFormat
    ? YUV Video Format: Size = java.awt.Dimension[width=176,height=144] MaxDataLength = 50688 DataType = class [B yuvType = 32 StrideY = 352 StrideUV = 352 OffsetY = 0 OffsetU = 1 OffsetV = 3

    3. javax.media.format.YUVFormat
    ? YUV Video Format: Size = java.awt.Dimension[width=320,height=240] MaxDataLength = 153600 DataType = class [B yuvType = 32 StrideY = 640 StrideUV = 640 OffsetY = 0 OffsetU = 1 OffsetV = 3

    4. javax.media.format.YUVFormat
    ? YUV Video Format: Size = java.awt.Dimension[width=352,height=288] MaxDataLength = 202752 DataType = class [B yuvType = 32 StrideY = 704 StrideUV = 704 OffsetY = 0 OffsetU = 1 OffsetV = 3

    注意,其中Output Formats都是javax.media.format.YUVFormat,而QR Code Library里默認的設備不是這種格式的,所以需要對源碼作一定的修改。

    5、用Eclipse打開QR Code Library的源碼,作出一些適當的修改:
    如果攝像頭是上面所說的只支持YUV格式,則需要修改jp.sourceforge.qrcode.example.jmf.camDataSource.java,把setMainSource函數里的
    VideoFormat vidformat = new VideoFormat(VideoFormat.RGB);
    修改為
    VideoFormat vidformat = new VideoFormat(VideoFormat.YUV);
    否則永遠也找不到攝像頭。

    6、把JMF包里的jmf.jar放到Classpath里
    7、執行jp.sourceforge.qrcode.example.jmf.jmfexample,搞定

    當然,由于源碼開放的,只要符合許可,你想怎么改都行,可以把它嵌入到某個應用程序里面,這個程序就具有了掃描QR Code的功能了。

    posted @ 2009-04-02 16:22 amp@java 閱讀(5936) | 評論 (13)編輯 收藏

    今天早上回到單位發現好幾部服務器都出現了與svchost.exe有關的錯誤,有一臺svchost.exe進程占用CPU達到100%,慢如蝸牛。普通PC機上則出現網絡時斷時續,重啟后能打開網頁,但很快就所有網頁打不開,某些網絡程序運行時則出現緩沖區已滿等錯誤。更新病毒庫查毒后發現整個局域網的所有電腦都出現Hack.Exploit.Win32.MS08-067.k病毒,殺毒軟件顯示svchost.exe里的病毒已清除,但是重啟又出現。
    搜索得知這是MS08-067漏洞導致,于是下載補丁,打上,但是病毒并沒有清除。無奈只能求助高人,在高人指點下找到了病毒位置并清之,過程如下:
    1、運行,輸入services.msc,打開服務管理器,按照“描述”排序,在“描述”欄為空的那幾項服務中查找一個名字很奇怪、由幾個隨機字符組成、沒有任何意義的服務,它的狀態一般是停止,但是啟動模式是自動,這里要把它改成已禁用;
    2、重啟電腦;
    3、運行,輸入regedit,打開注冊表編輯器,輸入那個奇怪服務的名字進行查找,找到以那個名字命名的鍵值,在其下面有個名為Parameters的子鍵,該子鍵內有個ServiceDll的字符串值,就是病毒文件所在,找到那個病毒文件并刪之;
    4、到微軟網站下載MS08-067補丁,打上,搞定!

    這是我第一次碰到這種迅速感染整個局域網的病毒,似乎跟當年的沖擊波有得比,搞起來煩得要命,幾十臺機啊……
    posted @ 2009-01-08 23:05 amp@java 閱讀(5098) | 評論 (2)編輯 收藏

    現在的手機大多具有藍牙功能,手機上的JavaME程序也能訪問藍牙端口,藍牙的協議有多種,但最簡單的可能就是虛擬串口(rfcomm)協議了,在該協議中,藍牙端口被虛擬成一個串口,只要獲取其InputStream和OutputStream后,就可以進行讀寫操作了,與socket差不多。 待續…
    posted @ 2008-11-27 19:16 amp@java 閱讀(871) | 評論 (0)編輯 收藏

    為了充分利用晚上的帶寬,我搞了一部專門的破機用于BT/EMULE下載,上班時間為了不影響大家上網,必須停止下載任務。有的下載工具本身帶有計劃任務功能,但是有些只能控制速度,不能控制連接,例如eMule,雖然可以停止下載,但是連接還是很多的,脆弱的ADSL路由/Modem經不起大量的連接,很容易就死翹翹了。這種情況下,最痛快的解決辦法是拔線,但是每天插拔也不是辦法,軟一點的辦法是禁用網卡,但是每次手動操作也不是辦法。更直接的辦法就是計劃任務自動啟用/禁用網卡了。要實現這種目的必須要有能夠自動運行的工具,devcon就是一個命令行工具,能夠在命令行中實現“設備管理器”的功能,我這里只要“啟用/禁用”功能即可。
    devcon的下載地址:
    http://support.microsoft.com/kb/311272/zh-cn
    微軟出品,權威產品。

    使用的時候還是有點小問題,搜索了一下找不到答案,只有自己解決了:
    1、禁用設備的命令是:
    devcon disable 設備ID
    這個設備ID怎么得到呢?通過設備管理器,在設備上點擊“屬性”,在“詳細信息”標簽里面有個下拉列表,選擇“設備范例Id”,下面顯示出來的就是設備ID,
    怎么把這個ID復制出來呢?右鍵是沒辦法的,但是直接CTRL+C就OK了。
    2、設備ID不能直接輸入,否則會把ID開頭相同的一大堆設備都操作一遍,最后還會出幾個錯誤提示;加上雙引號也不行,會提示沒有設備被禁用/啟用;必須這樣寫:@"設備ID",所以最后的命令格式是:
    devcon disable @"設備ID"
    不知道是什么道理。

    在計劃任務里面添加兩個任務:“啟用網卡”,“禁用網卡”,分別用devcon enable,devcon disable命令即可,例如早上8點半禁用,晚上23:30啟用(有部分好筒子晚上加班)。這樣一來,就可以24小時開著那幾個下載程序也不會有影響了,在網卡禁用的時候,無論它們怎么嘗試連接,都跳不出如來佛的掌心。

    posted @ 2008-08-28 17:19 amp@java 閱讀(3283) | 評論 (3)編輯 收藏

    說來慚愧,雖然工作學習都離不開計算機,但直到兩個星期以前,我還沒有為自己買過一臺新電腦,倒是給人家裝了快10臺。近段時間終于下定決心買臺電腦了。我不玩游戲,買電腦只是為了上網,看片,寫點小程序。現在流行高清電影,上了一下相關論壇,發現要流暢“軟解”H264編碼的1080P電影,至少需要4核的CPU,Intel的Q6600盒裝1500左右,AMD 羿龍9550 1100左右,前者的性能好于后者,但是Intel的集成主板又貴又爛,AMD 的780G芯片組是目前最強的整合芯片組,價格便宜量又足,于是就把架構定在AMD上。技嘉的GA-MA78GM-S2H 是論壇上討論最多的主板,應該也是用的人最多的780G主板之一,憑借技嘉優秀的做工,充足的用料,豐富的接口,贏得了廣泛的好評,但是這個是小板,由于面積的局限,南北橋芯片發熱比較厲害。后來技嘉推出了標準ATX板型的GA-MA78G-DS3H ,采用了全固態電容(小板是供電部分全固態),減少了一個ESATA接口,增加了一個1394接口,增加了三條PCI-E插槽,散熱效果應該比小板好,于是就定下了這塊主板。由于高清電影動輒10G以上,所以買了個希捷500G 7200.11硬盤,以后降價的話再加一個做RAID 0就爽了。內存選用kingston 1G * 2 DDR2-800組成雙通道。光驅是明基DW2000 DVD刻錄機。這些都很快定下來了,倒是機箱和電源費了不少腦筋。看了不少評論和測評,最后才定下了航嘉的“時光之門”機箱,看中的就是它的用料和4個前置USB+一個1394口。電源要選主動PFC,效率更高,同時也要額定400W以上,因為那個CPU的TDP就有95W,挑了半天,定在TT的KK500A,額定功率400W,主動PFC,14CM大風扇。顯示器22寸液晶就可以了,我對它的要求不高,因為看片的話也是通過HDMI接到液晶電視上看,初步決定三星2243BW。
    這一切準備好之后,找了個時間殺到電腦城。報價如下:
    CPU     Phenom X4 9550 盒裝 1120
    主板 技嘉GA-MA78G-DS3H  680
    內存 Kingston DDR2-800 1G*2 140*2=280
    硬盤 希捷7200.11 500GB 585
    光驅 BenQ DW2000 DVD刻錄機 225
    機箱 航嘉時光之門H301 265
    電源 TT KK500P (KK500A的升級版) 470
    顯示器 三星 2243BW 1850
    鍵盤鼠標 雜牌套裝 30
    合計 5505

    挑好之后我讓JS備貨,然后就回去了。過了沒多久,JS打電話來說AMD的那個CPU沒貨,問我要不要9750,我說算了,等有貨再裝吧,那個CPU的TDP 125W,太恐怖。結果過了兩天,還是沒貨,我打電話問了本市的其他電腦店,也是沒貨,說是奧運影響了物流(不得不說奧運真是勞民傷財,個人觀點,不要上綱上線)。JS出了個主意說讓我先用雙核的4800+,有貨的時候再換成9550。開始的時候我不同意,考慮到淘寶自己買,問了一下真的有賣的,還比JS那里便宜20塊,但是又怕出現問題不知道找誰,雖然盒裝全國聯保,但是我這個小地方好像沒有AMD的代理。最后還是同意了JS的辦法,再奔電腦城,把裝了4800+的主機扛了回來。顯示器我問過三星的代理,只要1790,JS說他賣不了這個價,于是就不要顯示器,鍵盤鼠標看了一下,也很爛,不要。回來打開電腦,我靠,居然一點聲音都沒有,真的,從來沒見過這么安靜的電腦,如果不是燈亮著,跟沒開一個樣。可能歸功于電源那14cm的風扇,只要很低的轉速就可以產生大風量。上淘寶買了根3米長的HDMI線,接到家里的32寸液晶上,很郁悶地發現不能點對點,那個電視的物理分辨率是1366*768,但卻不支持這個輸入分辨率。沒辦法,只好用1280*720輸入,看文字比較模糊,但也沒多大影響。看電影那叫一個爽,比電腦上爽多了。
    前天去電腦城買了一套雙飛燕的防水鼠標鍵盤套裝KB-827D,65塊。昨天和一個同事一起想去買三星的那款顯示器,無意中卻看到了一款AOC的2280V,參數和三星2243BW基本一樣,但是價格便宜不少,只要1540,還帶DVI線,3年質保,比三星的D-SUB線+1年質保要好。于是就要了一臺,店家包無點,開箱檢查了一下,兩臺都是完美屏,拿回來了。
    這個過程中,最郁悶的事情是弄那幾個顯示接口了。780G的主板一般都帶有D-SUB、DVI-D、HDMI三種接口,但是DVI和HDMI接口不能同時使用。技嘉的這塊主板就是這樣,而且還是自動選擇HDMI,也就是插上DVI和HDMI之后只有HDMI有東西。AOC的那兩個接口也是自動選擇,也就是兩個接口都插上的話,就會自動選擇DVI(本來可以手動選擇的,但是如果兩個都插上的話好像手動選擇無效)。
    首先碰到的問題是聲音。按照主板的說明書,如果需要通過HDMI口輸出聲音的話,必須在控制面板->聲音和音頻設備->音頻里面在聲音播放默認設備下選擇Realtek HDA HDMI Out。但是我把電腦搬回單位折騰的時候,發現這里并沒有出現Realtek HDA HDMI Out這個選項,只有Realtek HD Audio output!在設備管理器里卻能發現ATI HDMI Audio這個設備。搜索了半天,好像有人遇到過這個問題,但是沒有答案;有人說在BIOS里面開啟,但我發現默認已經開啟了;打電話給技嘉客服,那個人叫我先接上電視試試。那時候還沒有買HDMI線,試不了,于是就不管它了。結果HDMI線到了之后,一接上電視,馬上就出聲了,暈啊,原來必須插上HDMI線之后才能選擇那個Realtek HDA HDMI Out!!!!
    昨天把顯示器買回來之后也碰到問題了。我把DVI口和D-SUB口和HDMI口都接上了,啟動電腦,顯示器自動選擇DVI輸入,自檢界面->Windows滾動條都沒問題,但是滾動條過去之后,顯示器提示沒信號,黑屏了,怎么按都沒反應,選擇信源也不行。只能關機重啟,然后按F8選擇VGA模式,進去之后分辨率是640*480,沒問題,但是只要一調整分辨率,無論是調成800*600還是1680*1050,都一樣的沒信號,黑屏。把D-SUB線和DVI線分別拔下,還是不行。想到ATI控制中心里面看看,結果偏偏在這個時候ATI控制中心啟動不了!!重裝驅動,還是不行。下載最新的8.7的催化劑驅動,一裝完重啟就藍屏。只要又裝回8.6版。搞了三四個小時,弄到最后,把HDMI線拔了下來,只接一個DVI到顯示器,居然一切正常了,啟動成功,分辨率1680*1050,完美。仔細一想,才明白原來這塊主板只支持DVI和HDMI其中之一輸出,而且接上HDMI后默認就輸出HDMI了,雖然我那電視一直沒開,但是線插上之后就不再輸出DVI了。把DVI拔了之后,由于之前只有電視作為顯示器,沒有配置雙顯示器輸出,所以D-SUB也不會有信號,所以無論拔DVI還是拔D-SUB都沒信號,只有拔HDMI才行。這時候我又嘗試安裝中文版的8.6 ATI控制中心,裝完之后還是啟動不了,嘗試一下Restart Runtime,我靠,居然就可以啟動了!!神奇!!!進去把顯示器作為主顯示,電視作為擴展。重啟之后顯示器和電視機都能顯示了,而且顯示器是1680*1050,電視是1280*720,調整了一下電視的過掃描,使它滿屏,然后用KMPlayer放電影,把窗口拖到電視那邊,全屏,好了,可以一邊在書房上網一邊在客廳放電影了(我在書房和客廳之間的墻上打了個洞)!!有點遺憾的是,顯示器只能用D-SUB輸入,浪費了那根DVI線。不過這個可以通過獨立顯卡來解決,以后再說吧。
    780G主板的確厲害,集成的顯卡可以輕松硬解1080P的視頻,CPU占用不到10%,但是有時候會出現綠格子,還有一些奇怪的現象。所以可能的話我還是盡量使用軟解。不過到目前為止,4核CPU還沒到貨,這個4800+軟解VC1有時候都會卡,更別說H264了。而且AMD那個原裝風扇實在太爛了,看片的時候60多度,甚至死機,必須把蓋子打開,拿個臺扇往里吹才能把一部片子看完。后來花10塊買了個12cm的機箱風扇,裝上之后似乎也沒什么效果。看來只能換CPU散熱器了,初步決定買個九州風神的β400+,100左右,4根熱管的,對付那個9550應該可以吧。不過要等CPU到了再買。突然發現,DIY就是個燒錢的過程,我多年的積蓄已經花得差不多了……
    到目前投入的錢:
    主機3625+顯示器1540+機箱風扇10+HDMI線190+鼠標鍵盤65=5430
    預計還要投入的散熱器,突破5500了!!
    這就是我的第一臺自用新電腦。

    2008年9月6日更新:
    截至目前,已在淘寶上購入如下附件:
    1、九州風神β400+散熱器一個,連郵費102塊。買回來裝上才發現噪音太大了,不得已只好DIY了一下,把風扇拆掉,裝上原裝散熱器的風扇。
    2、為了在客廳控制電腦,買了個無線鼠標,太科的,可能是山寨貨,連郵費82,剛開始的時候直接在客廳就可以穿墻控制書房的電腦了,不過第二次就不行了,可能電力不足吧,現在只能把鼠標拿到墻邊才能有,已經買了一條5m的USB延長線,明天送貨。
    posted @ 2008-07-27 21:35 amp@java 閱讀(481) | 評論 (2)編輯 收藏

         摘要: Nokia MMS Library是一個開放源代碼的Java MMS開發包,里面包含了源碼、文檔、示例程序等,很容易就能學會。下面是用這個包發送彩信的方法: 1、電腦通過GPRS/EDGE MODEM或手機連接移動夢網,注意,必須是移動夢網(CMWAP),不是互聯網(CMNET),如果手動撥號,一般是撥*99***1#或*99***2#,撥通之后打開命令行窗口,telnet 10.0.0.172...  閱讀全文
    posted @ 2008-06-17 14:35 amp@java 閱讀(3466) | 評論 (11)編輯 收藏

    這幾天要在單位部署一個軟件包,是msi形式的,據說可以通過“域推送”的形式安裝,搜索了一下,發現需要在 組策略->軟件設置->軟件安裝 里面添加放在共享目錄里的軟件包。但是我試過無論在“計算機配置”里面還是在“用戶配置”里面添加那個軟件包,無論是“發布”還是“指派”,都沒辦法自動安裝,最多只是在“添加刪除程序”里面的“添加新程序”出現那個軟件包,還需要手動安裝。
    域控制器上按照部門劃分了多個組織單位(OU),并把用戶分配到各自的組織單位中,組策略就是在這些組織單位上面應用的。
    昨天晚上看了一下“Windows2000資源大全”,里面有講到這種軟件安裝方法。原來是要把計算機也劃分到組織單位中,然后在那個組織單位的組策略的“計算機配置”里面設置那個軟件包,當計算機啟動后,進入“應用計算機設置”階段,還沒出現登錄界面時,就會自動安裝。之前對組策略的理解有問題,以為組策略只應用于用戶,實際上是“用戶配置”應用于用戶,“計算機配置”應用于計算機,要對讓每臺計算機自動安裝,而不是在用戶登錄之后安裝,就必須在“計算機配置”里面設置,要把這個設置應用于所有計算機,就要把那些計算機劃分到某個組織單位,然后對這個組織單位應用組策略。

    之前嘗試過用另外一種方法實現軟件的自動安裝,這種方法不僅僅適用于msi,還適用于所有安裝文件。
    利用Windows的WMI服務,可以對遠程用戶的注冊表進行操作,在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce里面添加一個值為安裝文件路徑的字符串,就會在計算機啟動并登錄后執行該安裝文件,執行完畢后會把這個鍵值刪除,也就是只執行一次。
    利用PsTools,可以對遠程計算機進行重啟操作,當計算機重啟后,用戶登錄時,就會執行安裝過程。如果不需要倒計時重啟,還可以通過WMI服務進行重啟操作,這樣就可以完全通過Script來實現,并且能夠記錄操作的成功與否。
    通過以下代碼可以連接遠程計算機:
    Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
    Set objWMIService = objSwbemLocator.ConnectServer(strComputer,"root\default",strUser,strPassword,"MS_409","ntlmdomain:")
    其中strComputer是遠程計算機名,strUser是域管理員帳號,strPassword是域管理員密碼
    得到objWMIService之后,就可以像對本機一樣操作WMI,例如獲取注冊表操作類StdRegProv:
    Set objStdRegProv = objWMIService.Get("StdRegProv")
    關于遠程注冊表操作可以查看MSDN里的StdRegProv類說明。
    通過Win32_OperatingSystem類可以實現對遠程計算機的關機、重啟等操作。
    WMI是個強大的工具,在局域網中可以實現很多方便的管理操作。但是需要通過VBScript來實現,而VBScript的異常處理十分弱智;使用JScript的話,很多WMI類的操作又十分繁瑣。
    posted @ 2008-06-14 16:12 amp@java 閱讀(1093) | 評論 (0)編輯 收藏

        JSF只能采用POST的方法進行FORM提交,同一頁面要顯示不同的內容,只有通過POST來改變參數或者通過SESSION傳遞變量。有時候有大量相似的頁面,這些頁面只有很少一部分不同(例如不同用戶、不同角色、不同頁碼等),通過跟在URL后面的query string本來可以很容易地實現,但在JSF里卻不行,只要一提交,馬上就把?后面那串東西丟掉。假如有一個頁面,根據URL后面的id參數來顯示FORM的內容,提交的時候如果驗證出錯,那個FORM的內容就丟失了,顯示一個莫名其妙的頁面,因為這時候那個id參數已經沒有了。還有常用的分頁操作,本來在URL后面加上個頁碼就可以了,但是JSF的分頁控件卻只能通過POST來翻頁,一刷新就出來個“重試”“取消”的對話框,讓人煩惱。如果頁面內容根據不同用戶角色有細微不同,就得每個角色建立一個頁面,每個頁面對應一個managed bean,這些頁面的內容基本相同,bean的內容也基本相同,卻要分別建立,一點重用的機會都沒有。今天做的一個東西就遇到了這種問題:
    一個簡單的審批流程,只有3個角色,申請者、審批者、執行者,整個流程是這樣的:申請者填單->審批者查看并審批->執行者執行并填入結果->申請者查看。這樣,每種角色都有兩種列表:未回復和已回復,這兩種列表在三個角色里面都是相似的,但有細微區別:
    申請者 審批者 執行者
    未回復列表 自己已發出但未被執行者執行的列表 申請者已提交但自己未審批的列表 審批已通過但自己未執行的列表
    已回復列表 自己已發出且執行者已執行的列表 申請者已提交且自己已審批的列表 審批已通過且自己已執行的列表

    這些列表的不同之處在于:已登錄用戶的角色(可以從session中得到,但一個用戶可能有多種角色,他可能以不同的角色查看列表),列表的當前狀態(對每種角色都有兩種狀態),列表的頁碼。由于每個列表都有可能有大量數據,所以必須用到分頁。通過JSF的DataTable空間和DataScroller控件可以簡單地實現分頁,然而,這種分頁導致URL后面的參數無效了,這樣一來,這六種列表就必須通過6個頁面來顯示了,通過頁面的名稱來區分當前用戶的角色、所查看的列表的狀態,每個頁面通過POST來決定頁碼。本來一個頁面+一個bean+3個參數就可以決定,現在需要6個頁面+6個bean來完成了。

    list.jsp?type=0&role=0&page=1->type0_role0.jsp
    list.jsp?type=0&role=1&page=1->type0_role1.jsp
    list.jsp?type=0&role=2&page=1->type0_role2.jsp
    list.jsp?type=1&role=0&page=1->type1_role0.jsp
    list.jsp?type=1&role=1&page=1->type1_role1.jsp
    list.jsp?type=1&role=2&page=1->type1_role2.jsp

    假如有n種狀態m種角色那豈不是要n*m個頁面+n*m個bean?

    有點想放棄JSF這個雞肋了。

    希望有高手給條生路走走!
    posted @ 2008-06-04 19:48 amp@java 閱讀(2349) | 評論 (11)編輯 收藏

    剛剛才知道,原來Java的線程是不能重啟的,也就是說,當線程的run()方法執行到最后一行,退出之后,這個線程就結束了,不能再通過start()方法重啟啟動這個線程,只能重新構造一個線程對象,再調用其start()方法來啟動,但這個對象和原來那個對象已經不同了。
    為了實現某個線程對象的“重啟”功能,可以在它的run()方法的最外層加上一個循環語句:
    1 public void run(){
    2   while(!stop){
    3     //do something
    4   }
    5 }

    這樣,只要stop不為true,run()方法就不會結束,不斷地“重啟”。
    如果run()方法里面還有一個循環,那么就要兩個停止標志:
    1 public void run(){
    2   while(!stop){
    3     //do something
    4     while(!stop && !restart){
    5       //do other thing
    6     }
    7   }
    8 }
    9 
    這樣,如果需要“重啟”線程,只要把restart設為true即可,如果要退出線程,只要把stop設為true即可。
    posted @ 2008-04-22 10:56 amp@java 閱讀(4187) | 評論 (0)編輯 收藏

    之前用過一個帶CheckBox的Tree控件,叫dhtmlXTree,支持xml數據,功能很好很強大,但是有個問題怎么也解決不了,不知道什么原因,就是第一次顯示的時候能夠正常顯示樹形列表,但第二次進入相同頁面就會顯示錯誤,所有圖片都看不見,只看到其中的文字,而且這時候整個瀏覽器像死了一樣,點擊上面的任何鏈接都沒反應,必須關閉重新打開才有效,或者等上十幾分鐘才反應過來,不知道是不是一直在后臺運行某個Javascript腳本。雖然這個控件的源代碼可以看到,但是一條注釋都沒有,都不知道哪個部分出了問題。

    在google上搜索替代方案時,看到了BlueShoes的樹形控件,具有多種形態,包括CheckBox,RadioButton等,每種形態都有例子,而且有詳細的規范的文檔(phpdocument,與JavaDoc類似),關鍵是代碼里面也有詳細的注釋,可以看到每個部分的實現原理。與dhtmlXTree使用XML存儲數據不同的是,這個樹形控件使用多維數組來存儲數據,似乎可讀性和效率稍差,但出錯的幾率也少了,不需要用到瀏覽器的XML處理。與前者一樣也支持IE5。

    關于BlueShoes的樹形控件的詳細的情況可以看這里:http://www.blueshoes.org/en/javascript/tree/

    那個網站上還有很多其他控件,也是很優秀的,雖然它的后臺是php框架,但客戶端控件同樣可以用于JSP。
    posted @ 2008-02-26 11:28 amp@java 閱讀(457) | 評論 (0)編輯 收藏

    瀏覽器的緩存有時候顯得很討厭,明明已經更新了內容,就是不顯示新的,只要URL不變,瀏覽器就不會去檢查服務器是否已經更新,而是用緩存里的東西,起碼在IE里是這樣。
    使用AJAX經常需要動態更新某一過程的狀態,例如短信發送的狀態,如果相隔幾秒查詢一次,URL不變的話,顯示出來的狀態永遠不會改變,因為瀏覽器第一次獲取了內容之后就不再更新了。
    為了解決這個問題,最簡單的辦法就是在URL后面加上一個不斷改變的查詢字符串(query string),例如:
    request.jsp?q=q&date=(new Date()).getTime()
    紅色部分就是不斷改變的查詢字符串。

    感謝http://wangcheng.javaeye.com/blog/135887的提示

    http://batmanwl.blog.sohu.com/71841783.html這里還可以看到多種解決方案
    posted @ 2008-02-26 10:33 amp@java 閱讀(812) | 評論 (1)編輯 收藏

    通過JavaME的WMA可選包發送短信時,手機會提示是否允許程序發送該短信,雖然不太影響應用,但每次都要按一下允許也很不爽。從網上看到有人說對jar包簽名后就不會出現這種情況了,但是簽名的證書要向兩個大公司買,因為手機里面一般只內置了那兩個大公司的根證書,而且手機不允許安裝新的根證書,這不分明是圈錢嗎?不知道當初制定這個標準的家伙收了那兩個公司多少黑錢!雖然這樣會使很多病毒不能運行,但是那兩個公司又不是上帝,給錢就可以買到證書了,他們又沒什么力量也不會去研究購買證書的人要干什么,如果有惡意的人只要花點錢,同樣可以造出帶簽名的病毒來。
    但是辦法總是有的,有人另辟蹊徑,通過非常手段給手機安裝一個自己制作的根證書。詳細過程可以看這里:http://browndrf.blogspot.com/,原理就是利用了NOKIA某些型號的手機可以通過web下載證書并安裝的漏洞。我實驗了一下,整個過程其實不用那么復雜,不需要用到NOKIA的簽名工具,直接用SUN WTK的簽名工具就可以了,也不需要通過網絡安裝程序,跟平時安裝沒簽名的程序一樣。
    然而,簽了名的程序同樣需要確認才能發送短信!而且比沒簽名的程序更麻煩,還要在MIDLet-Permissions里面填上一大堆許可,不簽名的軟件這個項根本不用填。唯一的好處是安裝的時候不會提示程序不受信任,而且不能用無簽名的同名程序覆蓋。但是這種安裝過程的問題并不需要多大關注,因為安裝只是很少的時間,關鍵是使用。
    后來在這里:http://blog.csdn.net/zhengyun_ustc/archive/2006/04/07/654226.aspx又發現一篇文章,說明能夠安裝根證書的不過是個別機型的漏洞,是不符合MIDP 2.0安全標準的,算了,這個問題還是沒法解決,死心!
    JavaME真的有點像雞肋,它最大的優點是跨平臺,但各種手機的支持程度又各不相同,一點點小的差異就搞得人暈頭轉向。而且各種各樣的限制使得它最多就弄點小游戲玩玩,要連接網絡還得一堆的許可,程序大了還容易莫名其妙地崩潰。真是食之無味,棄之可惜。
    可是,我還是要搞……
    posted @ 2008-02-01 18:41 amp@java 閱讀(331) | 評論 (0)編輯 收藏

    主站蜘蛛池模板: 成人免费乱码大片A毛片| 国产亚洲精aa成人网站| 国产一区二区三区无码免费| 久久久久久A亚洲欧洲AV冫| 亚洲男女一区二区三区| 四虎影视在线看免费观看| 最新国产乱人伦偷精品免费网站| 很黄很黄的网站免费的| 亚洲人成网站观看在线播放| 亚洲精品亚洲人成在线麻豆| 免费人人潮人人爽一区二区| 少妇高潮太爽了在线观看免费| 亚洲av无码成人黄网站在线观看| 亚洲欧美国产欧美色欲| 精品无码人妻一区二区免费蜜桃| 亚洲国产专区一区| 亚洲成在人线aⅴ免费毛片| 免费不卡在线观看AV| 中文字幕亚洲乱码熟女一区二区| 国产99在线|亚洲| 99热免费在线观看| 亚洲AV日韩AV永久无码下载| 亚洲6080yy久久无码产自国产| 无码av免费毛片一区二区| 亚洲AV无码成人网站久久精品大| 在线播放免费人成视频网站| 好爽…又高潮了毛片免费看| 亚洲综合精品一二三区在线 | 亚洲男人的天堂在线| 无码人妻丰满熟妇区免费| 国产亚洲精品久久久久秋霞 | 亚洲熟妇无码另类久久久| 免费在线观看亚洲| 亚洲伊人久久综合中文成人网| 激情小说亚洲色图| 亚洲性日韩精品一区二区三区| 免费很黄无遮挡的视频毛片| 免费欧洲美女牲交视频| a级毛片在线免费观看| 亚洲成人在线网站| 国产91色综合久久免费分享|