2014年7月3日 星期四

整合maven 及 eclipse開發android app

起源:


使用lucene在android發生此錯誤:

ERROR/AndroidRuntime(733): FATAL EXCEPTION: main
java.lang.ExceptionInInitializerError
at org.apache.lucene.index.SegmentInfos.read(SegmentInfos.java:332)
at org.apache.lucene.index.StandardDirectoryReader
...

有時是這個錯誤:
I/TestRunner(2443): java.lang.NoClassDefFoundError: org/apache/lucene/codecs/Codec
I/TestRunner(2443): at org.apache.lucene.index.LiveIndexWriterConfig.<init>(LiveIndexWriterConfig.java:118)
I/TestRunner(2443): at org.apache.lucene.index.IndexWriterConfig.<init>(IndexWriterConfig.java:144)
I/TestRunner(2443):


有人說要用maven來解決:
Googling turns up some interesting results.

https://issues.apache.org/jira/browse/LUCENE-4204

According to the issue above,the Android APK builder removes some files in the META-INF/services directory,which is required by Lucene。They suggest some workarounds,like adding the necessary files from the lucene jars directly to the APK via some ant tasks done after the APK builder is done。Just be careful,since some lucene jars use the same files in the META-INF/services directory,and you may overwrite them uneccessarily.

I would actually suggest that you use the android maven plugin,as they have applied a fix for this already (see https://code.google.com/p/maven-android-plugin/issues/detail?id=97)。Just use the latest version of the plugin (or any version above 3.2.1).





正文

如果不是因為開發在android的lucene專案,遇到難以克服的困難,非得用到maven來解決,我大概絕不會碰這個東西,因為資料實在太難找,每份文件好像都只講一部分,重要部分,都語焉不詳,軟體名稱,都很類似,翻成中文後,更不知那個是那個。對我這個新手而言,把一切觀念都理清,著實花了好大的力氣。而且這東西,目前還看不出它的價值在那裡, 因為我是新手,花這麼大的力氣去研究它值不值得,但反正時間己經花了,也終於有些懂了,就把這幾天的心得,記錄一下,如果有第二個跟我一樣的人,不必再白費力氣去看網路上那些難懂的文章了。

個人認為寫的最清楚的是這篇文章,如果不是它,我想我還在maven的迷宮裡繞不出來,這裡特別感謝一下。
http://blog.csdn.net/wangwei_cq/article/details/17070307
以下引用一下:
「大多數情況下,開發Android使用基於Eclipse的Android Development Toolkit ADT。也可以使用Apache Ant來代替IDE的編譯工作。Android Maven Plugin則可以利用Apache Maven提供的功能,使開發團隊完成編譯,部署和發佈Android應用,還可以使用Maven強大的特性,如依賴管理,報表,代碼分析等等。」


我想大部分的人都是用eclipse的adt來開發測試,至於maven的強大特性,等時間來證明吧!


還有這個也對我理清觀念很有幫助:
http://www.vogella.com/tutorials/AndroidBuildMaven/article.html


引述內容:
「1.1。Android SDK and ADT

The Android SDK provides tooling for the command line to create and build Android projects.
The Android Developer Tools (ADT) offer the same functionality for Eclipse。In Eclipse you can manually export Android applications via the Eclipse wizard.
To build and deploy Android application the Android SDK provide tools which are currently based on Apache Ant.
The project lead of the ADT has recently announced that ADT is moving to a Gradle based build system and that the Eclipse tooling is also going to be based on the same build system.
Tooling for building Android Application with Maven are also available。The move of ADT to Gradle makes the support of Maven easier as Gradle uses Maven repositories to manage its dependencies。」


他先提到android sdk 與 adt的不同,sdk 是在命令列下建立android projects,而adt則在eclipse圖形介面內提供同樣功能。而android adk目前是用ant來建立及佈署android的app。而adt最近則宣佈用gradle來做這件事(建立及佈署android的app)。maven也同樣可用。只是從maven改到gradle,似乎更方便管理dependencies。


關於gradle,請參考:
http://www.codedata.com.tw/java/understanding-gradle-2-maven/
http://ithelp.ithome.com.tw/question/10129873



其他的內容,他還提到如果要在eclipse的adt之外,建立佈署android app,當然要做的事就多了,要很熟悉指令操作,要建立好環境變數等。因為我也是新手,這種事當然做不來,所以以下的操作,都是針對eclipse 的adt環境。


開始


必備條件:
1)JDK 1.6+。
2)Android SDK (r17 or later) 。http://developer.android.com/sdk/index.html
3)Maven 3.0.3+。http://maven.apache.org/download.html


以上如果是要在eclipse(adt)的環境裡使用,都是不需要的,因為前兩個,如果您已安裝好adt,而且已經正常使用adt開發app,那就已經具備了,可以不管。第三個maven,我是裝eclipse內的maven plugin來用,我也沒安裝這項,總之1,2,3項,我都沒特別去安裝。(會不會是安裝某些東西,自動裝上去的,我不敢保證)
所以基本我的認知上,除非你要在命令列模式使用maven,否則第三項也不用安裝。


安裝eclipse相關插件


主要有三個:
1) Android for Maven Eclipse 1.01 (m2e-android)
為Android Developer Tools (ADT)和 Maven Android Plugin添加Maven支持,為ADT提供Maven依賴管理的特性。

2) Maven Integration for Eclipse 1.5(m2e)
eclipse下的maven

3) Android Maven Plugin)
將Maven,Android和Eclipse串聯在一起




安裝Maven Integration for Eclipse 1.5

Help -> Install New Software...
在work with 的地方輸入http://download.eclipse.org/releases/luna/,按add,輸入一個名字。
選擇http://download.eclipse.org/releases/luna/
在type filter text 輸入 maven,會找到Maven Integration for Eclipse 1.5。可安裝成功。 (安裝1.5似乎會有問題, 1.4比較穩定, 在work with 用Kepler - http://download.eclipse.org/releases/kepler 可找到1.4版)




安裝Android for Maven Eclipse 1.01 (m2e-android)

Help -> Install New Software...
在work with 的地方輸入http://rgladwell.github.com/m2e-android/updates/,按add,輸入一個名字。
選擇http://rgladwell.github.com/m2e-android/updates/
在type filter text 輸入 android,會找到 Android for Maven Eclipse



安裝過程中,出現:

you are installing software that contains unsigned content。the authenticity or validity of this software cannot be established。do you want to continue with the installation?
選OK繼續即可,完成後重啟eclipse adt。


還有一個叫Maven Android Plugin(後來改名叫Android Maven Plugin)並未出現,因為它不用安裝,它會在稍後出現的pom.xml檔中被指定,並自動下載安裝,所以這個不必管。



用maven建立新專案


從Eclipse ADT,file->new->other->maven->maven project
圖一,直接按next
2014-07-02_1428171.png

圖二 在filter輸入de.akquinet.android.archetypes,出現三個項目,選第一個android-quickstart。

2014-07-02_1429071.png

圖三,填入相關資訊,注意預設platform是16,android-plugin-version的版本是3.8.2。事後可能會修改。


2014-07-02_1429071.png

錯誤修正:


建立完maven的新專案時,可能會有一些錯誤:

1)使用maven建立新專案時,會缺android.jar
在project->java build path中加入:D:\adt-bundle-windows-x86-20140321\sdk\platforms\android-19\android.jar (如果使用api 19)


2)在project->java build path中顯示src\test\java(missing)
請手動在src下建立\test\java目錄


3)gen目錄下的r.java無法自動產生,可能原因如下
主menu的project->android->project build target中的target name未打勾,導致gen目錄下r.java不能產生.
也有可能此處的api版本與AndroidManifest.xml中不一致所導致(或其他地方不一致)。在上圖三中預設的api是16,可是adt預設是19


4)前文提到的pom.xml在此時已產生,但可能有一些問題如下:

<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
<version>${android.plugin.version}</version>
<extensions>true</extensions>
</plugin>


使用<version>${android.plugin.version}</version> 會出現錯誤:
改成<version>3.9.0-rc.2</version> 才正確



5)專案內的全部錯誤均消失,但專案名稱仍有錯誤記號
導致無法執行,請在專案中,右鍵->maven->update project..
下列三項打勾:
update project configuration...
refresh workspace...
clean projects...
->按Ok,錯誤即消失


執行測試

建好要測試的設備(用虛擬機或實體設備,我是用wifi over air 直接連到平板測試, 但用wifi遇到問題)
專案,右鍵->run as...-> build...
在視窗的goal輸入合適的命令:

以下是使用Maven構建Android項目中常用的一些命令,你可以根據需要選擇合適的命令。
(在maven的命令列中使用 mvn clean package, 在eclipse -> run as->maven build…->goal, 去掉mvn輸入clean package即可)

mvn clean package
clean:會刪target的內容, package:打包(會產生dex檔),但不部署。 (建立convert to dex時, 如果記憶體太小, 會很慢, 請儘量減少不必要的程式, 至少要有700M的free memory. )

mvn clean install
打包,部署。

mvn clean package android:redeploy android:run
這個命令通常用於手機上已經安裝了要部署的應用,但簽名不同,所以我們打包的同時使用redeploy命令將現有應用刪除並重新部署,最後使用run命令運行應用。

mvn android:redeploy android:run
不打包,將已生成的包重新部署並在andriod設備運行。

mvn android:deploy android:run
部署並運行已生成的包,與redeploy不同的是,deploy不會刪除已有部署和應用數據。

(專案內的target目錄內放的是maven所產生的package, eclipse所產生的放在bin目錄內. )


再讓我引述別人的智慧,供以後參考:
http://mkn939.blogspot.tw/2013/03/maven-eclipsemaven-command-mode-step-by.html

「這個執行方法並沒有把Eclipse很完整的整合進來,
要回command mode打包war,還要手動deploy到server上,感覺有點累
但好處是Maven專案跟Eclipse切的很乾淨,
Eclipse只負責修改Java檔.其他的動作都由Maven完成,
避免使用太多套件(Eclipse plugin)造成Debug不易(鬼打牆事件)

如果使用Eclipse+m2eclipse開發,deploy時出現很奇怪的行為的時候
建議回到純Maven的操作方式,能方便找出問題的源頭」



以上指的是直接用命令列的方式,可以避開與eclipse整合在一起,出現一些奇怪的問題。

Read more...

2014年6月28日 星期六

關於java,android,lucene開發的一些事....

以下是個人學習java的一些記錄,隨時會增減修改。

使用grouplayout,JSplitPane的比例亂掉

JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
splitPane_2.setRightComponent(tabbedPane);

paneT1 = new JScrollPane();
paneT2 = new JPanel();


tabbedPane.addTab("簡要", paneT1);
tabbedPane.addTab("全文", paneT2);
GridBagLayout gbl_paneT2 = new GridBagLayout();
gbl_paneT2.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0};
gbl_paneT2.rowHeights = new int[]{0, 0, 0};
gbl_paneT2.columnWeights = new double[]{1.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
gbl_paneT2.rowWeights = new double[]{0.0, 1.0, Double.MIN_VALUE};
paneT2.setLayout(gbl_paneT2);

在JTabbedPane 中有兩個tab paneT1及pantT2, paneT1內只包含一個JScrollPane,內含JList, paneT2包含兩個JButton及一個含JScrollPane的JTextArea。paneT1因為只有一個JList所以沒有特別使用佈局(layout),而paneT2一開始先放一個JPanel,再考慮用grouplayout作佈局,可是不知怎麼的,一放上去以後,原來整個JSplitPane的比例就變的很tricky,整個比例都亂掉了,後來改用GridBagLayout才正常,原因...目前不知。。。


JScrollPane 為何用setViewportView,而不用add來加入物件

scrollPane_1.setViewportView(textArea_1);

Q:JscrollPane.setviewportview與JscrollPane.add之間的差異
當我們想要把展示的東西放在panel內,我們只需用add方法將其添加到panel,但我們為什麼不能添加一個table或textArea到ScrollPane中,而必須調用(呼叫)setviewportview的方法? 而不用add()方法呢?

A:基本上,你不應該使用JScrollPane#add 。

JScrollPane連接到一個JViewport ,JScrollPane用這個來顯示添加到view視圖中的任何組件(元件)(如textarea, table, list等)。
setViewportView是一個方便的方法,用來顯示滾動窗格(scrollpane)內容的一部分,它就像一個窗戶一樣,只能看到窗外世界的一部分,或像是照像機的觀景窗,所以add的方法,實際上在JScrollPane中並不代表任何意義。add只是單純將物件加入容器內。

rgZsh.gif

關於valueChanged執行兩次的情況


model = new DefaultTableModel(){
public boolean isCellEditable(int row, int column) {
return false;
}
};

lstModel = new DefaultListModel();
list = new JList(lstModel);

list.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent arg0) {
if (arg0.getValueIsAdjusting()) {
// The mouse button has not yet been released
return;
}
int idx=list.getSelectedIndex();
ss.moveCaret(2,idx,textArea_1);
//arg0.getLastIndex();
}
});


getValueIsAdjusting在按下滑鼠時,即使未放開滑鼠就已經執行,當放開滑鼠時,還會再執行一次,所以會造成執行兩次的情況,增加下面這一段是為了避免執行兩次的狀況發生。
if (arg0.getValueIsAdjusting()) {
// The mouse button has not yet been released
return;
}


利用ArrayList來處理java不固定長度的陣列

如果一開始不能確定陣列要給多少長度,而是要跑完一段長長的作業,才能知道陣列長度。可用ArrayList來代替一般的陣列,如下用add的方法,隨時加入元素到ArrayList中,不必事先決定陣列的長度。非常方便。但是要注意加入的元素最好是int, long 等單純的型別,如果在ArrayList中放入陣列,要很小心。因為放入陣列到arraylist事實上是放入該陣列的位址。它真實的值是指向別的地方。有可能發生意想不到的情況。我曾經發生一次誤用的情況,但因當時未記錄,現在也無法回想當時的情況,只能提醒自己小心。


ArrayList bl = new ArrayList();
ArrayList el = new ArrayList();

int b,e;
Pattern pattern = Pattern.compile(str);
Matcher matcher = pattern.matcher(textString);

int count = 0;
while(matcher.find()) {
b=matcher.start();
e=matcher.end();
String s=textString.substring(b-50,100+e);
lst.addElement(s);
count++;
System.out.println("found: " + count + " : "
+ matcher.start() + " - " + matcher.end());
bl.add(b);
el.add(e);
}

/*for (ScoreDoc scoreDoc : hits.scoreDocs) {
Document doc = searcher.doc(scoreDoc.doc);
*/

hitCollects=new int[bl.size()][2];
maxHit=bl.size();
for(int i=0;i<bl.size();i++){
hitCollects[i][0]=(int)bl.get(i);
hitCollects[i][1]=(int)el.get(i);
}

curHit=0;
return hitCollects;



正則表達式 -group 用法


Pattern p = Pattern.compile("(.+)\\*$");
Matcher m = p.matcher(str);
if (m.find()) {
str=m.group(1)+"file:///D|/w*";
}

以上的效果,如果是 abc* 會換成 abc\\*
group是針對()來說的,group(0)就是指的整個串,group(1) 指的是第一個括號裡的東西,group(2)指的第二個括號裡的東西。 所以上例中group(1) => (.+) => 一個以上的任意字元


str=str.replace("*","file:///D|/w*");
str=str.replace("*","[\\w']*");
以上兩句的區別,第二句包含縮寫符號,匹配ca*t,可以找出can't,第一句不行

str=str.replace("?","file:///D|/w");
將通配字元,轉成正則表示式

正規表示式,如何不區分大小寫

Pattern pattern = Pattern.compile("file:///D|/b%22%2Bstr%2B%22/b");
Pattern pattern = Pattern.compile("file:///D|/b%22%2Bstr%2B%22/b%22%2CPattern.CASE_INSENSITIVE);

正規表示式-\b\B的意義

\b 指的是英文字與空格(不一定是空格,如換行,不是字母的符號等...)的間隙的那個位置,比對英文字的邊界,例如空格 例如 /\bn\w/ 可以比對 "noonday" 中的 'no' ;
/\wy\b/ 可比對 "possibly yesterday." 中的 'ly'

\B 比對非「英文字的邊界」 例如, /\w\Bn/ 可以比對 "noonday" 中的 'on' ,
另外 /y\B\w/ 可以比對 "possibly yesterday." 中的 'ye'

有無加"file:///D|/b"區別
加上的話,b*nd 會比對出 behind, blind,即使是句子的第一個英文字前無空白,仍能正確比對
若不加,b*nd 會比對出behind,blind,hidebrand


如何使用正則表示去除雙引號

Matcher matcher = pattern.matcher(textString);
Pattern p = Pattern.compile("^\\\"(.+)\\\"$");
Matcher m = p.matcher(str);

if (m.find()) {
str = m.group(1);
}



lucene 分詞器的選擇-StandardAnalyzer

關於stop word的問題
使用StandardAnalyzer分詞,會去掉stop word,如on the in a an等,使得像"on record"這樣的phrase search失敗,而只找到record的文件,造成搜尋結果比預期多,且不準確。
改用WhitespaceAnalyzer,也無法改善,且像"alan,"字尾緊跟著","號會找不到,用StandardAnalyze則無問題
SimpleAnalyzer "alan,"可找到,但"on record"還是找不到

解決方法:阻止StandardAnalyzer去除stop word
1)在建立索引時,使用如下命令建立StandardAnalyzer
Analyzer analyzer =
new StandardAnalyzer(Version.LUCENE_48, CharArraySet.EMPTY_SET);
IndexWriterConfig conf = new IndexWriterConfig(Version.LUCENE_48, analyzer);

2)在搜尋建立QueryParser時,使用如下命令建立StandardAnalyzer
Analyzer analyzer =
new StandardAnalyzer(Version.LUCENE_48, CharArraySet.EMPTY_SET);
QueryParser parser =
new QueryParser(Version.LUCENE_48, where, analyzer);

關於縮寫字及連字符
StandardAnalyzer 找不到縮寫字 如can't , "single-handedly"加雙引號可以找到,不加則當成single handedly 2個字去找,找出很多.


移除java Jtextarea內所有的highlights

public static void removeHighlights(JTextArea textComp) {
Highlighter hilite = textComp.getHighlighter();
Highlighter.Highlight[] hilites = hilite.getHighlights();

for (int i = 0; i < hilites.length; i++) {
//if (hilites[i].getPainter() instanceof MyHighlightPainter) {
hilite.removeHighlight(hilites[i]);
//}
}
}


改變highlight的顏色

Highlighter.HighlightPainter greenPainter =
new DefaultHighlighter.DefaultHighlightPainter(Color.GREEN);
Highlighter h = ta.getHighlighter();

h.addHighlight(hitCollects[curHit][0], hitCollects[curHit][1],
greenPainter);


正則表示式範例

abc\W+([A-Za-z]+\W+)*def
取abc至def間所有英文字的token

\b(\w+\W+){0,3}take(\W+\w+){0,3}\b
以take為中心向前或後最多取10組文數字的token,即使遇到換行符號,仍會往前或往後取,因此不限於只取一行文字
\W是分隔token的符號(除了文數字以外的字元,如空白,標點,換行等...)
\w是文數字及底線
以下為例:
abc def 7678
sdkd dir take much
cat doff place
會取出 7678 sdkd dir take much cat doff

如果用在一個長的文件中,有二個以上的結果,取過的部分,不會再取一次:

bb take cc dd ee take ff gg
\b(\w+\W+){0,2}take(\W+\w+){0,2}\b
第一次取出 [bb take cc dd]
第二次依規則前後最多取二組,應取出 [dd ee take ff gg]
但dd已經在第一次選取時取過了,因此第二次選取只會取出
[ee take ff gg]



coming with you...No.
00350 I need you here to take care of Arendelle.
00351 On my honor.
00352 I leave

表示次數的regex後面,不加或再加上?或+之不同:

光看這樣的說明是無法分出三者不同,以下舉例說明。
Greedy quantifiers
字串 "xfooxxxxxxfoo"
(不加) pattern ".*foo"
結果 xfooxxxxxxfoo
Greedy字面翻譯是貪婪,也就是盡可能的取字串,其實最貪婪的是第三種方法,因為Greedy還會把之後相符的資料留下來,Possessive吃的連骨頭都不剩。

Reluctant quantifiers
字串 "xfooxxxxxxfoo"
(加上?)pattern ".*?foo"
結果 xfoo 和 xxxxxxfoo
Reluctant字面翻譯是勉強,也就是抓最小可能,像這個例子,第一次抓一個x之後發現後面和foo相符,就得第一個結果,然後一直到最後又得到第二個結果。

Possessive quantifiers
字串 "xfooxxxxxxfoo"
(加上+)pattern ".*+foo"
結果 沒有相符合資料,因為所有的資料都與"."比較相符,最後沒有剩下的字串可以和foo做比較,所以沒有符合資料。


java 注意contructor 不必宣告傳回值

public class aaa{....
public aaa(){
}
}

上例中如果寫成public void aaa()會被視為一般函數


宣告建立ArrayList時,先指定型別

ArrayList
ArrayList<Integer> bl = new ArrayList<Integer>();

bl.add(1);
bl.add(2);
bl.add(3);

使用新的for語法
for (int a:bl){
System.out.println(a) //印出123
}

因前面宣告建立ArrayList時,先指定型別為int,則在取出資料時,就不用做型別轉換.如下例1),否刖就要先轉成int,如例2)
1) a = bl.get(i);
2) a = (int) bl.get(i);


netbeans 比對兩個檔案的技巧

先同時開啟兩個要比對的檔案,拖動其中一個檔案的頁籤,往右或往下,待出現方框時放開,則會將兩個檔案分別並排開啟。

getContentPane().invalidate(),getContentPane().validate()的使用

table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent event) {

....程式碼.....

getContentPane().invalidate();
getContentPane().validate();
}

getContentPane().invalidate();=>出錯,只能放在valueChanged的範圍內
getContentPane().validate();
});


繼承關係下的Constructor執行順序

先將所有變數設為內定值。對數值型態來說,其值為0; 對reference來說,其值為null; 對boolean來說,其值為false。
呼叫父類別的constructor。如果子類別Constructor裡沒有指定父類別的Constructor, 則使用父類別沒有參數的Constructor。
執行變數宣告的初始化動作。
執行自己的constructor。

netbeans好用的命令 右鍵->find usages 可跨檔案尋找,用find只能在一個檔案內找

ArrayList<String> strList = new ArrayList<String>();
strList.add("abc");
strList.add("def");
strList.add("ghi");
s="Def";

這種情況下用 int index=strList.indexOf(s) 無法找出正確資料,因無法忽略大小寫

必須改用手工去比對
int index = -1;
for (int i=0;i<strList.size();i++){
if (strList.get(i).equalsIgnoreCase(s)) {
index=i;
break;
}
}

String a="abc";
String b="abc";
a==b 不一定為真,因判斷的是a,b所參考的物件是否相同,並不是值是否相同
應該用a.equals(b)才是判斷值是否相同


使用字串相加 string a="a"+b";效率較差

----
最近看了一個面試題是這樣的:

char 是否能存儲一個中文字符,為什麼?

char類型一般佔用兩個字節,所以能存儲中文字符(一個中文字符佔用兩個字節)。

char a = '中' ;(合法) char a = 'ab' ;(非法的)

所以char類型在內存中佔用兩個字節空間,但是只能表示一個字符。若是只要表示一個字節的字符,可以考慮byte。

byte表示字節,佔用內存一個字節的空間。

byte a = 'a' ;(合法) byte a = '中' ;(非法的,不能存放中文字符)

另外:1 byte = 8 bit (bit就是0和1的一個位數,8bit表示一個字節)

String str = "中" ;

byte[] a = str.getBytes();

System.out.println(a.length); //打印出多長?

result:可能2,3,4.

原因是getBytes()方法會根據當前默認的字符編碼格式獲取字節數組,gbk/gb2312佔2位,utf-8佔3位,unicode佔4位(很多地方看見別人說是佔兩位,但是親測出來的結果是4,求解!)

可以str.getBytes("GBK"),str.getBytes("UTF-8")使用,指定了編碼格式,就不根據默認的取得了。
----
eclipse
'Launching android' has encountered a problem.

An internal error occurred during : "Launching android".

Clicking "details >>" produces an extra line:

Path for project must have only one segment

因為configuration未給名,run->run configurations,選擇一個configuration在project的地方給名字即可
--------
eclipse ctrl+h 可多檔搜尋文字
在logcat的某一項目的第一行,按ctrl+c可複製,如果在第二行就不行
--------

06-18 16:44:42.982: E/AndroidRuntime(3437): java.lang.RuntimeException:
Unable to start activity ComponentInfo{com.example.engandroid/com.example.engandroid.ItemListActivity}:
android.view.InflateException: Binary XML file line #24: Error inflating class fragment


错误信息:

android.view.InflateException: Binary XML file line #8: Error inflating class fragment

http://blog.csdn.net/duguang77/article/details/17579847

下面我总结下此错误出现的原因:

1.XML文件中引入的Fragment路径不对(如下图)

2.在Activity继承Fragment时引入的包名不对

关于什么时候引入android.app.Fragment和
android.support.v4.app.Fragment(向下相容3.0以下)

public class MainActivity extends Activity { // above 3.0
public class MainActivity extends FragmentActivity { // below 3.0


请参考我的另外一篇文章:

点击了解:【android fragment android.support.v4.app.Fragment与android.app.Fragment区别】

06-18 17:46:26.981: E/AndroidRuntime(4193): Caused by: java.lang.IllegalArgumentException:
Binary XML file line #24: Duplicate id 0x7f05003d, tag null, or parent id 0xffffffff with another fragment
for com.example.engandroid.ItemListFragment

The problem is that what you are trying to do shouldn't be done. You shouldn't be inflating fragments inside other fragments. From Android's documentation:

Note: You cannot inflate a layout into a fragment when that layout includes a <fragment>. Nested fragments are only supported when added to a fragment dynamically.

While you may be able to accomplish the task with the hacks presented here, I highly suggest you don't do it. Its impossible to be sure that these hacks will handle what each new Android OS does when you try to inflate a layout for a fragment containing another fragment.

The only Android-supported way to add a fragment to another fragment is via a transaction from the child fragment manager.

---------

<fragment
android:id="@+id/eng_list"
android:name="com.example.engsearcha.EngListFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
tools:layout="@android:layout/list_content" />

<FrameLayout
android:id="@+id/eng_detail_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3" />

以上佈局,如果 android:layout_width="0dp"不設為 0dp,會使得比例變得很不正常

----------
eclipse 使用ctrl+H作search時,如果是選擇?java search,file search,有時因從外部copy檔案進來,未sync會搜尋不到,此時會提示錯誤,從detail中可看到訊息
先在package explorer中refresh即可


setContentView(R.layout.activity_eng_list);中的R.layout.[activity_eng_list]和檔名[activity_eng_list].xml是同步的,用refactor->rename改其中一個地方,另一個也會跟著改
而 activity_eng_list.xml內有一段:
<fragment
android:id="@+id/eng_list"
android:name="com.example.engsearcha.EngListFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
tools:layout="@android:layout/list_content" />
會建立啟動com.example.engsearcha.EngListFragment這一個物件. 這是屬於靜態建立fragment.
----------

setListAdapter(new ArrayAdapter<DummyContent.DummyItem>(getActivity(),
android.R.layout.simple_list_item_activated_1,
android.R.id.text1, DummyContent.ITEMS));


android.R.layout.simple_list_item_1:一行text
android.R.layout.simple_list_item_2:一行text較大,一行text較小
android.R.layout.simple_list_item_single_choice:單選
android.R.layout.simple_list_item_multiple_choice:多選按鈕
android.R.layout.simple_list_item_checked:勾選盒
------------

static後面加大括號的含義
static { }
In the Java programming language, a block is a group of lines of code enclosed in curly braces. Blocks serve many purposes in Java--
for instance, control Java keywords such as "while" take a block as an argument. In particular, Java supports "static blocks."
A static block gets executed exactly once per class--rather than once per object created in the class, as would be the case for code
included in a constructor method. You can use static Java blocks to perform one-time tasks when the class in question gets loaded into
memory by the Java Virtual Machine.

static blocks只有在類別被載入時,執行一次,物件被建立時,不會執行
----------

Few days back I came to know about a different way of initializing collections and objects in Java. Although this method of initialization has been there in Java since quite a few years now, very few people actually knows about it or have used it in their code. The technique is called Double Brace Initialization technique in Java.

Let us see first how we will initialize an ArrayList in Java by "normal" way:
List<String> countries = new ArrayList<String>();
countries.add("Switzerland");
countries.add("France");
countries.add("Germany");
countries.add("Italy");
countries.add("India");

Above code snippet first creates an object of ArrayList type String and then add one by one countries in it.

Now check the Double Brace Initialization of the same code:
List<String> countries = new ArrayList<String>() {{
add("India");
add("Switzerland");
add("Italy");
add("France");
add("Germany");
}};


How does this works?

Well, the double brace ( {{ .. }} ) initialization in Java works this way. The first brace creates a new AnonymousInnerClass,
第一個大括號,宣告是一個內部的匿名類別
the second declares an instance initializer block that is run when the anonymous inner class is instantiated.
This type of initializer block is formally called an "instance initializer",
because it is declared withing the instance scope of the class
第二個大括號是一個"instance initializer",當物件被建立時執行(類似constructor)

- "static initializers" are a related concept where the keyword static is placed before the brace that starts the block,
and which is executed at the class level as soon as the classloader completes loading the class .
The initializer block can use any methods, fields and final variables available in the containing scope,
but one has to be wary of the fact that initializers are run before constructors.

If you have not understood the concept, try executing following code and it will make things clear for you.
public class Test {
public Test() {
System.out.println("Constructor called");
}
static {
System.out.println("Static block called");
}

{
System.out.println("Instance initializer called");
}

public static void main(String[] args) {
new Test();
new Test();
}
}
Output:
第一個new Text()執行時:
Static block called
Instance initializer called
Constructor called
第二個new Text()執行時:
Instance initializer called
Constructor called

執行的優先次序:static block->instance initializer->constructor
static block:類別載入時,只執行一次
Instance initializer:物件建立時執行.
Constructor:物件建立時執行

Instance initializer比Constructor好用之處
1)可以處理catch exceptions.
2)如果一個類別有多個constructor,每次可能執行不同的constructor,但是你希望每次都要執行一段程式碼,則你必需每一個constructo重覆寫一段相同的程式碼,執行同一件事,如果寫在Instance initializer裡,就只要寫一次就好.
3)用在內部匿名類別,因為內部匿名類別不能宣告constructor

----------

This seems to explain it well:

"Instance initializers are a useful alternative to instance variable initializers whenever:

initializer code must catch exceptions, or

perform fancy calculations that can't be expressed with an instance variable initializer. You could, of course, always write such code in constructors.

But in a class that had multiple constructors, you would have to repeat the code in each constructor. With an instance initializer,
you can just write the code once, and it will be executed no matter what constructor is used to create the object.
Instance initializers are also useful in anonymous inner classes, which can't declare any constructors at all."

Read more...

四種免費中文ocr文字辨識的測試與使用

因為工作需要,必須做一些中文文字的辨識(OCR),找了許多資料,找到了一些免費軟體,我測試了四種均是免費OCR軟體(除了附加在ms office那個,當然Office是要錢的,不過我想大部分人都有吧,所以也把它的附加功能列入免費軟體)。
這些辨識工具,在不同情況下,有不同的使用方式,有些工具如果操作錯誤,還會影響辨識效果,有些安裝時沒注意到細節,還會一直出現錯誤,因為花了很多功夫,試了很多軟體,所以乾脆作成記錄,方便以後有同樣需求時參考,也提供有相同需求的朋友一些方向,不用像我走了許多冤枉路,浪費了許多時間。

這裡所提供的文字辨識功能均支援中文辨識(當然也支援英文),我所測試的均以繁體中文為主,唯一例外的是Capture2Text,因找到資料說它對簡體字的辨識效果不錯,因此也特別測試了一下,如果您不想看下面冗長的文章,以下的注意事項及使用心得,可以先給您一個快速的參考:

注意事項:

*要使用JOCR或Office來辨識:
1)必須在安裝office時,選擇安裝 Microsoft Office Document Imaging,(最好選全部安裝,因為裡面的Microsoft Office Document Image Writer在不是使用Jocr的情況,而是用Microsoft Office Document Imaging 時會用到)

2)據找到的資料指出要在Office 2003以上的版本才可使用。(我實測office xp不能使用,我沒有Office 2003,直接使用Office 2007)

3)office 2007要安裝service pack 3,才能正常使用。

*中文原始文件的文字方向很重要,會大大的影響辨識結果,我所測試的文字均是橫向,Google Doc直接在其說明資料,表明不支援直行中文字辨識,Capture2Text有選項可以調整橫向或直向中文字。


使用心得:

*在幾個免費的ocr軟體中,操作上最沒有問題的是Capture2Text,在操作過程中,沒有出現異常錯誤,

*在我測試的條件下,辨識率最好的是JOCR及Capture2Text(只限於辨識簡體中文時),辨識效果最不佳的是Google 雲端硬碟,特別強調我的測試條件,是因為這只是我工作過程中的附帶記錄,所以測試OCR的原始樣本並不多,只是我工作上使用到的情況,大都是直接在螢幕上擷取文字來辨識,並未用掃描器或數位相機從紙本文件中辨識,這也可能是Google雲端及Office Document Imaging的辨識效果較差的原因(文末有同一原始文件,各個軟體的辨識結果供參考,請參看辨識結果比一比)。

*而辨識速度,除了Capture2Text可以感覺到慢了一些,其他的看不出明顯的差異。

*操作最煩瑣的是使用Office的 Microsoft Office Document Imaging來作辨識,它必須先把原始圖檔用一個虛擬印表機轉成tif檔,再到Microsoft Office Document Imaging進行辨識。

綜合以上,我認為用Jocr最優秀,它檔案極小,操作簡單,辨識率也不錯,速度也還好,但像Jocr或Capture2Text是直接在螢幕上選取一個區域作辨識,如果是多個文件(圖檔),或是原始圖檔超過一個畫面大小,就會比較麻煩。
而Google或Office是直接讀取圖檔,可以一次讀進一個或多個影像檔進行辨識,不必在螢幕上選取操作,在多檔或批次作業上佔優勢。

反之Jocr及Capture2Text雖然不利於多檔或大檔案辨識,但其優點就是,在螢幕上看到的影像文字,只要一選取,立即辨識,方便又快速,像有時候遇到電腦顯示的錯誤訊息,或視窗上的文字,想在搜尋引擎上尋找相關資料,如果萬一不能用複製,貼上來處理,就必須親自打字,如果用Jocr或Capture2Text就可以即時辨識成文字來運用。


以下逐一說明操作步驟:

JOcr

下載:JOCR 1.0 Download (Free) - JOCR.exe

JOCR是一個可以辨識圖片裡的文字並存成文字檔的免費軟體,不過其實它只是借用Microsoft Office的殼,實際的功能是Microsoft Office提供的, 因此它的檔案極小,不到100K。

使用前你的office 必須安裝Microsoft Office Document Imaging,如果安裝office時,沒有安裝的話,請把您的office光碟拿出來,增加安裝此一項目, 如下圖所示。
2014-06-05 08 49 50.png

至於那一版的Microsoft Office才有提供呢,我目前使用的Office XP找不到此功能,應該是Microsoft Office 2003以上的版本才有,(我另外找到Microsoft Office 2007有提供),JOCR的操作非常簡單,它不用安裝,只要在下載回來的檔案上按兩下滑鼠左鍵即可執行;還有它的檔案非常小,大約只有80K左右。

使用JOcr前先到Ms Office 工具中作語言項目的設定,從程式集進入「Microsoft Office->Microsoft Office工具->Microsoft Office Document Imaging 」

2014-06-05 06 33 46.png


進入後從工具->選項->OCR 選擇您要的語言,這裡當然選擇中文(繁體)如下圖:
2014-06-05 08 21 56.png


上述設定完成後,接著啟動JOCR,先按下「Capture Region」,然後選取圖片中你想辨識的區域,接著選擇辨識的語言,並按下「Recognize」就會開始辨識,辨識完成的文字會出現在記事本內, 如果您出現如下圖的錯誤訊息,是要你到Ms Office 工具中作語言項目的設定,可是我已照著設定,仍不能正常工作, 後來我安裝了Office 2007 Service Pack 3,就可正常使用了。

2014-06-05 08 23 32.png




直接使用Office內 Microsoft Office Document Imaging的OCR功能


如同前文所講,JOcr只是借用Office的功能,提供一個較方便的方式來作辨識,那當然也可以直接使用Office內的功能來完成,雖然Office不是免費的軟體,但是應該大部分的人都有安裝。使用方法如下:

先安裝 Microsoft Office Document Image Writer, 如上面第一個圖中所示,如果您有全部安裝Microsoft Office Document Imaging的話,也會安裝Microsoft Office Document Image Writer,安裝完成後會在系統的印表機中多出一個Microsoft Office Document Image Writer的虛擬印表機。


使用步驟
1) 先在檔案總管找出要辨識的圖片(不同於JOCR可以在螢幕上直接指定一塊區域來辨識,它辨識的是整個圖檔),請在圖片上按滑鼠右鍵,選擇[列印],出現相片列印精靈後,點擊[下一步],選擇印表機時,請選擇Microsoft Office Document Image Writer的印表機。

2) 點擊[列印喜好設定],定好要印的紙張大小(建議用A3紙),如果圖片文字方向不對,請選好直印或橫印加以調整,選擇好之後點擊[確定],點擊[下一步]。

3)點選[下一步],存成tif格式檔案, (這個虛擬印表機事實上是一個轉檔的功能,將你的圖片轉成tif檔,以方便下一步的辨識 )

4)在剛剛存好檔的 tif 檔,使用 Microsoft Office Document Imaging 來開啟(操作方式上面JOCR時已提到過,程式集進入「Microsoft Office->Microsoft Office工具->Microsoft Office Document Imaging 」)。


5)進入後選檔案->開啟,打開上述轉好的tif檔
打開後可看到如下圖的縮圖,再縮圖上按右鍵,還有一些功能選項,如果在上文列印(轉tif檔)原圖時,沒有選好紙張方向,在此處也可以旋轉頁面來調整。

2014-06-16_105532.png

再進入「工具->使用OCR 辨識文字」,辨識完成後,並不會出現任何完成的訊息,而是在左邊的預覽圖右下角就會出現已辨識的圖樣,如下圖紅框內的圖示。

2014-06-16_105652.png

再點「工具 -> 傳送文字到 Word」。


Capture2Text


Capture2Text個人認為是一款還算不錯的免費文字辨識軟體,它可以像JOcr一樣直接在螢幕上,選定一個區域作辨認,又不必像JOcr必須背著Office這個大包袱,另一方面,它也不像直接在Office內作辨識那麼繁瑣,但有一個問題,就是它的辨識速度較慢,辨識簡體中文較準確,繁體中文差了一些,不過目前很多pdf或圖片檔的免費電子書,幾乎都是簡體中文,拿它來辨識,應該是非常適合,所以這裡也一並介紹。


Capture2Text下載點/

各種語言的tessdata pack(包含中文繁簡體)

簡體中文的nhocr pack (如果是辨識簡體,建議下載這個,辨識率較高)

這裡也提供個人已壓縮好的Capture2Text,含繁簡體(87M),當然主程式本來就含有日英德法西班牙意大利文,如果想省事的人可直接下這套解壓即可使用, 下載點:
http://pan.baidu.com/s/1hqFZWMC

如果不是下載我自製的懶人包,這裡提供使用繁簡體nhocr的使用方式:
下載下來主程式以後,直接解壓縮,簡體中文的nhocr pack也下載下來,一樣解壓後,將nhocr pack內的檔案全部copy到Capture2Text主程式內的\Utils\nhocr\Dic的資料夾內。
然後直接執行Capture2Text內的Capture2Text,exe執行檔,在右下工作列中會出現Capture2Text的圖示,在圖示上點右鍵,選擇ocr language,再挑選欲辨識的語言。

2014-06-05 19 00 56.png

(如果要辨識繁體中文,只能下載tessdata pack,因為nhocr沒有繁體中文, 請copy 到\Utils\tesseract\tessdata資料夾內,其他步驟與上相同)



要開始辨識時,請先將鼠標移到您要辨識螢幕區域的左上角,按下Windows鍵+Q,然後直接拖動滑鼠(不用按滑鼠鍵),圈出一個藍色的矩形範圍(如下圖)。

2014-06-05 19 07 04.png


這個範圍就是您要作辨識的區域,此時你可以用空白鍵切換左上,右下角,再拖動滑鼠改變選取區大小,也可以按下滑鼠右鍵,拖動以移動整個選取區,還可以用方向鍵調整選取大小,區域選定好以後,再次按下Windows鍵+Q(或滑鼠左鍵),Capture2Text就開始辨識作業,辨識速度取決您的電腦速度,辨識完成後,會彈出一個視窗,成功辨識的文字會在視窗內,也會放在剪貼薄內,要運用直接貼上即可。

下面兩個圖分別是簡體繁體中文的辨識效果,在popup result的結果視窗中,可以看到簡體(選用Chinese-NHocr)比繁體效果要好很多,
以一個免費的ocr軟體來說,乍看之下似乎有許多字未能正確辨識,但這裡的例子是直接選取螢幕的文字作測試,本來解析度就不太高,如果原始圖片或pdf上的圖片文字解析度比螢幕高,或字體大小比較大,也許效果會好很多。


簡體中文字的辨識效果:
2014-06-05 18 47 22.png

繁體中文字的辨識效果:
2014-06-05 18 50 19.png

另外在設定的地方(工作列圖示->右鍵->perferences)。可進行一些設定,其中ocr頁面有幾個值得注意的地方:
1)Text Direction選取文字的方向,如果方向錯的話,辨識結果會非常差,要特別注意。
另外ocr-pre-processing如果勾選會增加辨識時間,但辨識度會提高許多。

2014-06-05 18 57 11.png



Google 文件的OCR功能

以上介紹的幾種OCR功能均是借用軟體來完成,但臨時找不到適合的軟體,也可以利用Google雲端硬碟上的OCR功能,它一樣也支持中文文字辨識。
使用方法如下:
前往Google Doc網站:
https://drive.google.com/

按下上傳文件圖示,再選取->檔案

2014-06-15_140028.png


在上傳設定中選擇->「將PDF檔案或圖片,...轉為Google文件」,勾選此一選項將使Google Doc會進行OCR辨識作業。
2014-06-15 11 11 40.png


因為這些圖是我直接從螢幕擷取下來的,可能是解析度太差了,第一次除了原圖檔外,未辨識出出任何文字
2014-06-15 11 28 02.png

第二次我把原來的文字放大一些再進行擷取,結果嚇了一大跳,這是什麼情況,是有辨識出一些文字,但Google文件把字放的超大的,所以也看不出OCR的效果。
2014-06-15 11 28 40.png
我手動把字縮小一些,才看出原貌,這次辨識的很不錯,但不知為何只辨識出一部分,不知是否Google Doc把字放大了,導致辨識不全,因為Google Doc強調它除了能辨識出文字之外,還能辨識出字體,如斜體,粗體等,可能功能太多反而出現不能預期的錯誤。
(除了以上的測試,我還使用不同擷圖軟體,picpick及faststone分別擷取png檔,將dpi品質調高到500,又試過jpeg的品質調為最佳,擷出來的圖檔,都不能辨認,只有把原始文字放大,才認得出來)

2014-06-15 11 29 08.png


免費中文OCR軟體-辨識結果比一比

以下是同一段中文字,使用不同免費ocr軟件的辨識結果,可以見到JOCR真的是最優的,同時也很遺憾Google Doc又未識別出任何文字.可能是這種直接擷取螢幕文字的方式,真的對Google Doc較不能適應吧! (Google Doc我是使用擷圖軟體,分別擷取png檔,將dpi品質調高到500,又試過jpeg的品質調為最佳,擷出來的圖檔,都不能辨認,只有把原始文字放大,才認得出來)
2014-06-15_214021.png

以上就是針對幾個免費的中文ocr軟體的比較與測試報告,希望對大家有所助益。


參考:
The 3 Best Free OCR Tools To Convert Your Files Back Into Editable Documents

Convert screenshots to text with Capture2Text, a free optical character recognition (OCR) app

Read more...

2014年5月19日 星期一

java--Cannot refer to a non-final variable XXX inside an inner class defined in a different method

前幾天使用java,總是出現一個與final變數有關的錯誤,雖然知道如何修正,但卻不知原理。最近對java熟悉了一些,終於知道問題所在,特別加以記錄。

1 public class MainFrame extends JFrame {
2 private JTextField textInput;

3 public MainFrame() {
4 textInput = new JTextField();
5 JButton btnOK= JButton("");
6 btnOK.getModel();
7 btnOK.addActionListener(new ActionListener() {

8 public void actionPerformed(ActionEvent arg0) {
9 Searcher searcher = new Searcher();

10 if (arg0.getSource()==btnOK)
11 try {
12 searcher.search("contents", textInput.getText());
13 }
14 } catch (IOException | ParseException e) {
15 e.printStackTrace();
16 } } }); }
}

第8行的函數actionPerformed() 是位於第3行public MainFrame() 的函數內,如果第5行JButton btnOK= JButton()是在MainFrame()的函數內定義,那麼在第10行if (arg0.getSource()==btnOK) ,這裡使用到btnOK的話,在編寫java程式時就會出現關於使用final 變數的錯誤如下

Cannot refer to a non-final variable btnOK inside an inner class defined in a different method
這句話的意思是說在不同方法(method)中定義的內部類別(inner class)不可以參考到非final的變數。

究其原因,在於第10行用到的內部類別的區域變數btnOK並不是真的與第5行的btnOK是同一個變數,而是在內部類別中被複製一份出來,由於是複本,即便您在內部類別中對btnOK作了修改,也不會影響原來真正的變數,事實上您也通不過編譯器的檢查,因為編譯器要求您加上"final"關鍵字,這樣您就不能在內部類別中改變btnOK的值。
另一個方法是把btnOK變全域的變數,這樣不管在內部類別或外部都用到同一個變數,就不存在複本的問題了。

綜合以上,有兩個解決方法:
1.在第5行JButton btnOK= JButton("")的地方,改成 final JButton btnOK= JButton("")
2.btnOK不要在MainFrame()的函數內定義,而是在所有函數的外圍,在class本體內定義,改成如下範例:
在第2行下面增加private JButton btnOK;

至於要使用final變數的原因,更詳細請看
http://hi.baidu.com/_sherry_liu/item/58140f7387c28d336dc37c9e
關於 final 的用法,原理,基本常識,請看
http://blog.kenyang.net/2011/03/java-staticfinal.html

1 public class MainFrame extends JFrame {
2 private JTextField textInput;
private JButton btnOK;

3 public MainFrame() {
4 textInput = new JTextField();
5 btnOK= JButton("");
6 btnOK.getModel();
7 btnOK.addActionListener(new ActionListener() {

8 public void actionPerformed(ActionEvent arg0) {
9 Searcher searcher = new Searcher();

10 if (arg0.getSource()==btnOK)
11 try {
12 searcher.search("contents", textInput.getText());
13 }
14 } catch (IOException | ParseException e) {
15 e.printStackTrace();
16 } } }); }
}


Read more...

2014年5月18日 星期日

心得筆記-java 的加強版 for 迴圈 (for each迴圈)

java 的 for 迴圈出現一種以前從沒有看過的格式。它是JAVA 5.0 後多的一種 for 迴圈寫法,目的是簡化陣列與集合物件的元素存取方式.
在JDK 5.0版新增加強型的for迴圈,其功能類似其他程式語言的foreach迴圈,可以輕鬆走訪陣列或集合物件的元素。

for-each 迴圈語法

for (型別 變數 : 集合或陣列物件參考或函式呼叫) {迴圈內程序}

冒號前面稱為宣告式, 後面稱為運算式. 宣告式的變數型別必須與陣列或集合的元素相容, 此變數將用在迴圈內部以便存取元素. 運算式可以是集合或陣列物件參考, 也可以是函式呼叫 (傳回陣列或集合).


舉例:

* for迴圈新舊寫法的對照
public class NewFor {
public static void main(String[] args) {

String [] a = {"1","3","5","7","9","11"};

//5.0前的for迴圈寫法
for(int i = 0 ; i < a.length ; i++){
String temp = a[i];
System.out.print(temp + ", ");
}

System.out.println();

//5.0後for迴圈也可以用這種新的寫法(for-each)
for(String temp : a){
System.out.print(temp + ", ");
}


* 用字串變數name配合加強型的for迴圈(for-each)來走訪names[]陣列

String[] names;
for ( String name: names )
{

System.out.print('\"'+name+"\"(字串長度:");
System.out.println(name.length() + ")");

}

可以看到程式碼比傳統用法更簡潔



* 用for 迴圈印出二維陣列之元素
int[][] a={{1,2},{3,4,5}, {6,7,8,9}};
for (int[] i : a) {
System.out.print(i.length);} //印出二維陣列的元素個數 2 3 4 (a[0]有二個元素{1,2}, a[1]有三個元素{3,4,5}, a[2]有四個元素{6,7,8,9})

for (int i : a[2]) {System.out.print(i);} //印出二維陣列第三個元素的內容6 7 8 9



* 以上範例均以陣列為例,如果用在集合物件的寫法
for (ScoreDoc scoreDoc : hits.scoreDocs) {
Document doc = searcher.doc(scoreDoc.doc);
System.out.println(doc.get("fullpath"));
}

這是我練習java時所寫的一個例中,hit.scoreDocs 為一集合物件,內含不定個數的物件,scoreDoc每次迴圈執行時,均會取得其中一個物件,for 迴圈遍歷結束後,便會把hit.scoreDocs內所有物件,指定給Document 型別的物件 doc , 並印出該文件的路徑。

如果用傳統寫法,應該是以下的樣子:
ScoreDoc scoreDoc;
for (int i=0;i<hits.scoreDocs.length;i++){
scoreDoc=hits.scoreDocs[i];
Document doc = searcher.doc(scoreDoc.doc);
System.out.println(doc.get("fullpath"));
}

參考:
http://tony1966.myweb.hinet.net/java/core/flow_control.htm

http://www.ibm.com/developerworks/library/j-forin/index.html


補充:
很多程式語言都有支援for-each這類的語法,簡單的說for-each語法就是當我們想要存取一個 Array 或 Collection 裡面所有的元時可以更方便、更有效率的語法。for-each 也有人稱為 enhanced for 或 for-in。

使用上要注意的事項有:

只適用於 Java 5.0 以後的版本
只適用於有 implement Iterable 的類別基本上 Array 與 Collection 類別都沒問題。
只能存取裡面元素而不能置換掉它,記住,for-each 裡面的變數是 local 變數離開 for-each 之後就會消失。
只能同時針對一個 Array 或 Collection 進行操作。
只能同時針對一個元素操作。
只能從頭開始訪問每個元素。

以上取自:
http://yindingtsai.blogspot.tw/2010/03/java-for-each-for-eachfor-each-array.html

Read more...

心得筆記- java 陣列的建立(固定,變動)

Java陣列的特性


Java的陣列並不以一塊連續的記憶體空間來表達,而是把陣列視為特殊的物件。此物件不但可存放資料,還利用該物件的length屬性記錄著該陣列的長度。


一維陣列的建立

int[] x;
x = new int[10]; // 必須利用new指令產生並定義該物件的空間
for (int i = 0; i < x.length; i++) { // 此物件有一個length屬性,用以紀錄該陣列的長度
x[i] = 10; //給定陣列的初值
}

多維陣列建立(二維陣列以上)


Java陣列物件是只能儲存基本資料型態或reference的一維陣列,二維以上的陣列是透過reference指到其他的一維陣列物件來達成。



二維陣列的建立 (第二維陣列的長度一致)
int[][] x;
x = new int[10][20]; //因陣列固定, 可以一次建立陣列物件
for (int i = 0; i < x.length; i++) {
for (int j = 0; j < x[i].length; j++) {
x[i][j] = 10; //定義初值
}


二維陣列的建立 (第二維陣列的長度不一致)
由於java以一維陣列來模擬二維陣列,因此透過第一個陣列的reference所找到的陣列,其長度不必然相同

int[][] x;
x = new int[10][]; // 因二維陣列不固定, 因此先產生10個第一維陣列
for (int i = 0; i < x.length; i++) {
x[i] = new int[i];
// 再分別產生i個第二維陣列, 因第一維陣列存放reference,可透過它指向另一個陣列,i值可以使用變數, 造成不固定長度。
}


不可使用未定義空間的陣列


Java在執行期間會對陣列的索引做檢查,如果超出來合法範圍,就會產生ArrayIndexOutOfBoundException的錯誤。

例如:
int[] x = new int[10]; //合法定義的空間為x[0] .. x[9]
x[10]=10; //超過範圍

就會產生ArrayIndexOutOfBoundException的錯誤訊息,並且終止該程式

java.lang.ArrayIndexOutOfBoundsException: 10
at ArrayExample4.main(ArrayExample4.java:5)
Exception in thread "main"

上面訊息的意義是:
java.lang.ArrayIndexOutOfBoundsException: 10告訴我們索引值是10的時候引起了此問題
at ArrayExample4.main(ArrayExample4.java:5)告訴我們呼叫ArrayExample4.main時在ArrayExample4.java的第五行產生錯誤

參考:
http://programming.im.ncnu.edu.tw/J_Chapter3.htm

Read more...

2014年5月16日 星期五

光陽機車偶而發不動問題記錄

這幾天買了四年多的光陽v1 125,開始出現一些毛病。原本很好啟動,現在有時候會啟動一兩次才能發動,有一次下雨天,到學校去載小孩,回程的時候,居然發動了四五次,好不容易才發動。

心想也許是電瓶老化了,用電表量一下電壓,12.8v。還很正常。但聽說車子不發動時,量到的只是表面電壓。我又量了一下發動時的瞬間電壓,大約10.1v到10.4v之間。有時候會降低到9.8v,但這都可以順利啟動。如果發不動時的瞬間電壓,往往只有5, 6v左右。

又有人說也許是電線接觸不良,我發現電池正極的地方卡了許多粉末,於是我拆開電線將之清除。再測試發動情況,發現瞬間啟動電壓已經提升到11v。心想也許是這個原因,可是還來不及高興太久,下一次的發動,還是不好發。

為了避免顧路的危險,還是決定買一顆電池來換。

新電池買來,前幾天還可以。但有一天突然又發不動了。這下子可以證明不是電池的問題了。而且原來那顆電池,電力應該也還夠。所以之前所說的表面電壓的說法,也許可信,但不全然是這一原因。像這種偶而發生發不動的狀況,應該是最難處理了。牽去機車行,也不一定查的出來。目前就且戰且走,待有一天完全發不動的時候再處理了。

Read more...

2014年5月11日 星期日

注電解液到機車電瓶經驗

從拍賣買了一顆機車電瓶。本來以為買來裝上去就好了。想不到還要自己diy,把電解液注液到電池裡。看外包裝的說明書,寫的有點複雜。其實說穿了就是把裝電池液的瓶子倒過來,對準電瓶的六個孔插進去,讓瓶子裡的電解液自動流到電瓶裡去。說來簡單,但做起來還是有一些地方要注意。

先撕開電瓶上紅色標籤。讓電瓶的注液孔露出來。
IMG_20140509_111847.jpg


先把白色瓶子上的黑色蓋子拆下來。先放到一旁,待會兒還會用到。
IMG_20140509_112036.jpg
IMG_20140509_112111.jpg

再將白色瓶子倒過來, 對準電瓶的六個孔垂直的插進去。這時白色瓶子六個瓶口的洞會被戳破,這個步驟需要用點力氣。

IMG_20140509_112239.jpg

插進去以後,讓白色瓶子裡的電解液自然流入電瓶內。這時後會看到白色瓶子裡會有氣泡冒出。說明書說這個狀態要維持二十分鐘以上。

IMG_20140509_112422.jpg

二十分鐘以後,用手拍拍白色瓶子上方,確保所有液體均已流入電瓶內。

取下白色瓶子,把剛才拆下的黑色蓋子蓋上電瓶上方的六個孔。要用力把它壓入,壓到底。

IMG_20140509_112730.jpg


這個步驟更需要力氣。小弟力氣實在不夠,只好借用工具。

IMG_20140509_112937.jpg


電瓶注液完成!新的電瓶量出來的電壓是13.14v。裝到機車,大功告成。

IMG_20140509_113133.jpg

Read more...

2014年5月6日 星期二

富士全錄FUJI XEROX P205B填充碳粉經驗談

今天使用印表機時,突然不能印了。一開機,沒出現慣有的機器熱機滾動的聲音,取而代之的是機器上的橘色燈閃了一下,然後熄滅。而慣常亮的綠燈倒是正常。

本來以為是這臺富士全錄FUJI XEROX P205B故障了。研究了一下,最後發現是沒碳粉了。還好當時買印表機時,另外向店家多買了兩盒碳粉。現在派上用場了。

可是怎麼安裝呢,其實也很簡單,只要取出碳粉匣,這臺p205b本身就有在碳粉匣上設計填充碳粉的洞。壓下碳粉匣上一個小凸起旁的卡榫,再撥開這個凸出部分,填充的洞就露出來了,直接把碳粉注入到洞裡面,再撥回凸出部分,裝回印表機。

但是怎麼還不能印呢?該不會是要更換原廠的碳粉匣,才能印吧!又上網作了一番功課,才發現必須執行全錄的一個印表機工具程式,並開啟"非原廠的功能。才能列印。

到富士全錄FUJI XEROX 下載工具程式(SimpleMonitor及印表機設定公用程式/快速啟用公用程式)
http://www.fujixerox.com.tw/downloads?product_id=81
操作步驟: 執行富士全錄的印表機設定公用程式->印表機維護->非全錄原裝碳粉模式->勾選啟動

雖然開啟這個功能,會出現什麼.....使用非原廠碳粉匣會喪失保固....等等字眼。但總得來說,全錄還算體貼我們這些窮客戶。也不需換晶片,只要打開印表機的工具軟體設定一下,一切又恢正常可以列印了。不像先前我使用hp噴墨印表機時,必須用美工刀把墨水夾切開,還要填充,弄的到處是墨水不說,也沒填進去多少。到最後還是非得買他們原廠的墨水匣。

youtube有教學
https://www.youtube.com/watch?v=V4bCdf7QP0s

不過這段影還有換晶片的動作,可能因為他買的是原廠的填充碳粉,我的是副廠的,直接如上述改設定就好了。

這裡有討論
http://www.mobile01.com/topicdetail.php?f=499&t=2560323

Read more...

2014年4月10日 星期四

android wifi 開發除錯,只要一行指令,免usb連接線

使用wifi 作android開發的debug
1. 開Wifi
2. 用 USB 傳輸線接上你的手機
3. 找到Android SDKadb的路徑
4. dos執行的視窗中打入 cmd
意思是切換資料夾到剛剛找的adb路徑
輸入adb tcpip 5555
5. 然後就可以脫離USB連線了
再輸入adb connect 192.168.0.102:5555
192.168.0.102 是你手機的IP位址, 讓電腦連線到你的手機
6. 這時候你就可以用無線做操作了

打入adb devices,就會列出這個特別的裝置
List of devices attached
192.168.0.102:5555 device


注意:
操作過程如果出現not implement的訊息, 可能是如下原因:
adb 的服務需要偵聽5037 port,這個port搞不好就被豌豆莢或360助手之類的程序佔用,導致adb服務有問題。可以將之移除再試。

也可以用如下方法,查出是那一個程序在作怪:
netstat -a -n -o | findstr "5037" |more
查看所有端口使用情況,第一行的最後一列的數字就是佔用該端口的進程ID。
然後在用tasklist查找使用的進程:
tasklist | findstr "xxxx"
xxxx為佔用5037端口的進程PID,在任務管理器裡kill掉之後

----
後來又發現更簡單的方法,連usb線都不用接了。
在android 手機平板找到這套
ADB over WIFI Widget,安裝後直接執行它
它會讓你在電腦端,打adb connect 192.168.0.102:5555 的指令,就打這一行指令,不用再作其他事,就連上了。

Read more...

2014年1月26日 星期日

安卓(android) 上的全文檢索app

當我們在查找文件的時候,經常會用一些桌面搜尋軟體(desktop search),利用某個關鍵字,查找在那些文件的內容出現過,這也可以稱做全文檢索(full text search;FTS)。在傳統windows 上的全文檢索(fulltext search),好用的軟件不少,如docfetcher, Copernic Desktop Search, google desktop search等,但在android 上頭,好用的軟體就不好找了,我試了許多不同的app,有些只能找檔名,有些號稱全文檢索,但其實只能找郵件,簡訊,連絡人等,真的能像docfetcher這樣能找word, excel, pdf, txt檔的內容的,實在少之又少。

經過一番尋找,勉強可以用的只有全文文檔搜索器,還有一個fulltext search, 這個同名的軟體有兩個,要找作者是cooler的那個,另一個試了真是不好用。 其中我比較喜歡全文文檔搜索器,介面比較清爽,可以擷取顯示搜索文件的片斷,也可以用雙引號,尋找特定的文字,還能用正則表達式或*?去找,它應該是對岸開發的軟體,因此對中文的支持度也不錯,對office (word) 的支持度也很好。但有些缺點,例如好像只有找一層目錄,第二層以下的資料夾,就找不出來。還有好像只支援一些格式的文字檔,如utf8,如果是utf16也會找不到。但最糟糕的是,這個軟體已經許久未更新,未來可能也不會再更新,所以前面的問題,好像沒改善的可能。但目前android的全文檢索軟體真的很難找,只能將就用了。

而另一個fulltext seach,如果只有英文文件的話,也還好,但對中文的支持不佳,介面也顯得陽春一些,怎麼樣也比不上全文文檔搜索器,但唯一的好處是可以指定要作檢索的資料夾,而不是整個磁碟的尋找,而且也可以找多層次以下的目錄。目前我是兩個軟體交互使用,希望會有人能開發安卓市場更好用的全文檢索app,造福在android有需要此功能的使用者。

--------
近日又發現一款不錯的檢索軟體 andro search, 這款以前我也試過, 同樣問題不少, 但最近作者似乎更新的很勤, 以前的問題, 似乎均改善了. 而且應該是目前發現最好用, 且問題最少的一款搜尋軟體。

Read more...

2014年1月11日 星期六

103年3月6日起, 行經南科園區,小心路口監視器拍交通違規

103年3月6日起, 行經南科園區,小心路口監視器拍交通違規

在南科上班或會經過南科的朋友注意了, 路口的監視器不僅為了治安用途 , 還可以用來執行舉發交通違規, 設置 地點如下圖.

主旨:為降低園區交通事故,維護用路人安全,爰依據道路交通管理處罰條例之規定自103年3月6日起於台南園區內部分路口執行監視器錄影方式逕行舉發交通違規之工作,請協助周知所屬員工,請 查照。
說明:
一、依據道路交通管理處罰條例第7條之2第一項第七款規定辦理。
二、本局網站之「園區通報」上業已公布旨揭監視器設置地點,供民眾上網查詢,請轉知所屬員工,以促請園區工作伙伴知法、守法,共同維護園區交通行車秩序,確保用路人生命及財產安全。

1389232988284.jpg

Read more...

2014年1月10日 星期五

usb隨身碟容量變小的解決方法

usb隨身碟容量變小的解決方法


當使用隨身碟或sd卡時, 如果使用某些格式化工具, 使得容量改變, 例如原來8G變成2G, 如何恢復成原來的8G呢? 這裡提供一個簡單的方法:

在windows 7 (windows xp不支援列出usb裝置), 在命令列模式, 輸入執行 diskpart

出現 diskpart 的大於符號, 再輸入 :
list disk
這時會列出, 所有掛在系統上的磁碟, 包含usb隨身碟(u盤)或sd卡, 如果是使用windows xp,將無法列出隨身碟。如果您想恢復容量的隨身碟在第2個裝置(每個磁碟, 隨身碟, u盤, sd卡, mini sd卡,任何儲存裝置其前均會有一代號), 請輸入:
select disk 2
確定選擇到變小的隨身碟後, 再輸入:
clean
這時會清除隨身碟的資料(請誤必小心操作, 以免清除到別的磁碟或usb碟的資料)
再輸入:
create partition primary
會在隨身碟建立一個主要分割區

回到windows系統, 對此容量變小的usb隨身碟, 加以格式化, 完成後, 就可以發現原來縮小減少的的容量, 已經恢復正常大小了。


這裡還找到一篇能恢復隨身碟容量的相關文章, 還未及細看,如果有朋友依上面方法仍不能解決usb空間縮小的問題,可自行參考:

http://www.trishtech.com/2011/06/restore-usb-flash-disk-back-to-full-capacity/

Read more...

  © Blogger templates Psi by Ourblogtemplates.com 2008

Back to TOP