2013年8月23日星期五

新建的Android程式,預設無Menu bar (Action bar)

最近新建Android程式,發現Theme等背景都幫你設好了,
原本新建好的Android背景是黑的,
但新近建的Android程式,背景是白的;

查了一下,
原本是在 AndroidManifest.xml中多了android:theme="@style/AppTheme"

 <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

反正是程式自行建立的,所以應該不是壞事,
結果問題來了,在Activity中的onCreateOptionsMenu竟然跑不進去,



@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
Log.d(TAG, "onCreateOptionsMenu");
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

在Log裡面居然看不到它印出onCreateOptionsMenu的Log,
趕緊上網路查查去;
原來要修改style.xml(這也是程式自己產生的)

<resources>

    <!--
        Base application theme, dependent on API level. This theme is replaced
        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
    -->
    <style name="AppBaseTheme" parent="android:Theme.Light">
        <!--
            Theme customizations available in newer API levels can go in
            res/values-vXX/styles.xml, while customizations related to
            backward-compatibility can go here.
        -->
    </style>

    <!-- Application theme. -->
    <style name="AppTheme" parent="AppBaseTheme">
        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
    </style>

</resources>



原本的Theme使用是android:Theme.Light是不會產生Menu bar(Action bar)的,
要用android:Theme.Holo.Light來取代,修改如下:


<resources>

    <!--
        Base application theme, dependent on API level. This theme is replaced
        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
    -->
    <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
        <!--
            Theme customizations available in newer API levels can go in
            res/values-vXX/styles.xml, while customizations related to
            backward-compatibility can go here.
        -->
    </style>

    <!-- Application theme. -->
    <style name="AppTheme" parent="AppBaseTheme">
        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
    </style>

</resources>


這樣程式就會正常了。

2013年8月11日星期日

cakephp Facebook plugin FB.login callback 問題(已解決)

最近因工作需要,開始接觸cakephp用的FB  Plugin,
網路上找到的plugin:
webtechnick/CakePHP-Facebook-Plugin
網址:https://github.com/webtechnick/CakePHP-Facebook-Plugin

透過該網站的說明,將Plugin裝進去後,
第一關(登入)就卡關:

原程式碼:

echo $this->Facebook->login(array(
'perms' => 'email,read_stream,publish_stream',
'id'=>'loginButton',
'show-faces'=>false,
'status'=>'login',
));

狀況:
登入順利進行,但...怎麼登入後沒有導向我指定的網址?
設定網站說明的afterFacebookLogin callback也沒有用,
多加一個參數redirect後:

echo $this->Facebook->login(array(
'perms' => 'email,read_stream,publish_stream',
'id'=>'loginButton',
'show-faces'=>false,
'status'=>'login',
'redirect' => array('controller' => 'frontend', 'action' => 'login'),
));

原本看得到的登入icon,竟然不見了...
這個問題卡了二天,最後才找到解決方法;
根據
的說法,設定redirect參數是有用的,但設定後會發生login icon不見的問題,
所以要手動再設定img參數,如下方程式碼:

echo $this->Facebook->login(array(
'perms' => 'email,read_stream,publish_stream',
'id'=>'loginButton',
'show-faces'=>false,
'status'=>'login',
'redirect' => array('controller' => 'frontend', 'action' => 'login'),
'img'=>'Menubtno.png',
));

圖片因為已不是用原先FB的login圖片了,所以要自己做一張,
放在webroot/Facebook/img下,以上方的程式碼來說,
我有放一張圖在webroot/Facebook/img/Menubtno.png,
按下登入後,終於會導到我的login頁面了。

卡了二天,終於闖過第一關了。

2013年8月3日星期六

Android﹣從String取得Resources對應的int

寫Android程式時,在取Resources資源時,
正常情況不會知道對應的int,但一定會知道寫在String.xml中的name;

但因為這些name在編輯時會轉成JAVA的Field,放在R.java檔裡面,
所以取Resources資源時,必需透過類似R.string.name的方式,才能取到對應的int;

但世事不是都這麼美好的,有時name是在程式執行中才能拿到的,
而拿到手的是一個String,此時需要想辦法轉成R.string.name對應的int,
才能取對對應的,但要怎麼轉呢?

透過reflect的方式,下方是透過String取得Drawable的int範例程式碼:


public int getDrawableId(String id) throws SecurityException,NoSuchFieldException, IllegalArgumentException,IllegalAccessException {
Field f = (Field) R.drawable.class.getDeclaredField(id);
return f.getInt(R.drawable.class);
}

2013年6月17日星期一

jquerymobile 多點幾次後掛掉

前二天應朋友要求,
寫了一支用jQueryMobile架起來的手機版網站,
但在測試時,出現一個非常奇特的現像:
程式原始碼:
<a href="..." data-role="button">xxx</a>

點擊第一次時OK,點擊第二次時也OK,
結果點擊第三次時,網頁就掛在那邊,
停止回應了。

後來經過高人指點,將程式碼改為:
<a href="..." data-role="button" data-ajax="false">xxx</a>

就正常了,看起來原因是因為ajax引起,但詳細的原因不清楚,
不過改成這樣子就OK了。

2013年6月11日星期二

MAC的SSD硬碟多磁區的noatime掛載


因緣際會買了一台MAC,是SSD的硬碟,
上網查了一下,很多人在教針對SSD優化(延長壽命)的處理,
其中有一個是noatime掛載。

noatime掛載的資料請自行上網搜尋,
網路上很多人在說,
但都沒有提到,如果有第二顆SSD或第二個磁區時,
要如何讓多個磁區都能noatime掛載。

找到最後都沒有現成的,所以最後只好去研究plist裡面的東西到底是怎麼一回事,
在這裡將研究成果寫一下:
我在/Library/LaunchDaemons底下有一個com.tcj.noatime.plist(名稱自訂)檔案,內容如下(紅字為我寫的說明):


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
        "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>Label</key>(不能變動,因為要給程式判斷用)
        <string>com.tcj.noatime</string>(不能和其他plist的Label內容重覆,否則會無法執行)
        <key>ProgramArguments</key>
        <array>
            <string>mount</string>
            <string>-vuwo</string>
            <string>noatime</string>
            <string>/</string>(要掛載的路徑)
        </array>
        <key>RunAtLoad</key>
        <true />
    </dict>
 </plist>

結論:
了解意思後,再來看如果有多個磁區(路徑)要使用noatime掛載的話,步驟如下:
1.使用不同的檔案(plist)
2.變更Label中的string(以上一例來說就是 com.tcj.noatime 這一串文字,跟檔案沒有關係喔)。
3.重新開機。

這樣就可以了,下方是我掛載二個磁區成功的範例:
/dev/disk0s2 on / (hfs, local, journaled, noatime)

/dev/disk0s4 on /Volumes/Data (hfs, local, journaled, noatime)

二個檔案的差別參考:
1.

檔案1:

  <key>Label</key>(不能變動,因為要給程式判斷用)
  <string>com.tcj.noatime</string>(不能和其他plist的Label內容重覆,否則會無法執行)

  <string>/</string>(要掛載的路徑)


檔案2:


  <key>Label</key>(不能變動,因為要給程式判斷用)
  <string>com.tcjData.noatime</string>(不能和其他plist的Label內容重覆,否則會無法執行)

  <string>/Volumes/Data</string>(要掛載的路徑)


參考資料
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man5/launchd.plist.5.html

2013年5月17日星期五

GoogleCloudMessaging cannot be resolved to a type 已解決

今天在寫GCM時,一直碰到這個問題,
網路查也無解,
最後在GCM的Getting Start 中重新看到了一串

The sections below guide you through the process of setting up a GCM implementation. Before you start, make sure to set up the Google Play Services SDK. You need this SDK to use theGoogleCloudMessaging methods.


也就是說,GoogleCloudMessaging這個Class是藏在 Google Play Services SDK中的,
所以請先透過你的Andorid SDK manager,將Google Play Services下載或更新成最新版,
之後到<android-sdk-folder>/extras/google/google_play_services/libproject/google-play-services_lib/libs/,找到google-play-services.jar,把它用到你的專案來,
就可以把GoogleCloudMessaging 這個Class import進來了。

2013年4月20日星期六

android帶入預設資料sqlite

最近因為有需要,所以想讓程式安裝之時,
直接帶入一千多筆的資料,
網路上查了一下,

大部份都是說:
1.將sqlite檔丟入asset。
2.在建立DB時,判斷檔案是否存在,不存在則去asset,
透過串流的方式,將資料帶回來。

但這個方法不知道為什麼,不適用在我這邊。
所以我到最後的處理方式是:
用Insert的方式,但是一千多筆的Insert是會寫死人的,
所以最後的解決方法;
1.讀取一千多筆資料
2.透過寫入檔案的方式,將程式語法寫出來。
3.打開檔案,直接copy程式語法

這樣子就可以做到很多筆資料的Inser,
但缺點是:
1.寫出來旳程式因為是用串的,所以常常會錯,需要一改再改。
2.程式碼突然變很長。

寫出來的東西給大家參考一下:(下面那一串是用程式幫我組出來的)

db.execSQL("INSERT INTO frequency(_id, lotto_649_id, NO_1, NO_2, NO_3, NO_4, NO_5, NO_6, NO_7, NO_8, NO_9, NO_10, NO_11, NO_12, NO_13, NO_14, NO_15, NO_16, NO_17, NO_18, NO_19, NO_20, NO_21, NO_22, NO_23, NO_24, NO_25, NO_26, NO_27, NO_28, NO_29, NO_30, NO_31, NO_32, NO_33, NO_34, NO_35, NO_36, NO_37, NO_38, NO_39, NO_40, NO_41, NO_42, NO_43, NO_44, NO_45, NO_46, NO_47, NO_48, NO_49) VALUES(645, 645, 104, 110, 91, 92, 92, 78, 85, 103, 86, 90, 91, 85, 98, 79, 99, 81, 63, 95, 86, 90, 99, 102, 101, 91, 88, 97, 91, 107, 80, 93, 106, 94, 87, 84, 91, 104, 88, 101, 94, 87, 93, 93, 103, 92, 92, 82, 90, 91, 96);");

2013年4月18日星期四

將Google說明文件改成中文


要用Google的東西時,常常得看一堆英文,
但後來發現Google很友善的將英文都翻好了,
只需在網址後多一串文字就可以變更語系了,
例如:
英文:https://developers.google.com/mobile-ads-sdk/docs/android/fundamentals
中文:https://developers.google.com/mobile-ads-sdk/docs/android/fundamentals?hl=zh-TW

幹得好啊!Google大神

android 與 Google AdMob


1.參考網頁架設環境

2.登入AdMob(http://zhtw.admob.com/my_sites/,沒有就去申請一個吧),建立應用程式。(網頁上有一排字﹣﹣「 2012 年 5 月 1 日起,我們將不再支援 AdMob 行動網站」,其意思是不再支援行動網站,跟Android內嵌廣告無關,浪費了我半個小時去了解它的意思。

3.建立過程中比較有問題的應該是 Android 套裝 URL: 這一個,都還沒丟上Market怎麼知道呢?網頁上有提示你例如:market://details?id=<packagename>,所以就照填,把packagename換成程式在用的就可以了,填錯了之後也可以回來變更。

4.回到1.https://developers.google.com/mobile-ads-sdk/docs/?hl=zh-TW,開始寫程式了。

建議:
參考
來測試,這樣廣告的出現會比較即時

Android Design Pattern -- Template (Android設計模式 -- 範本)


Android的UI程現能像網頁一樣,固定Header、footer等,只變換中間嗎? 答案是可以的。

這是一個設計的概念,像網頁,或者像PowerPoint的背景一樣,
每一個UI都有固定的Header、footer,只有中間會一直變換,
實際做出的程式可下載:

這是一個簡單的概念程式,
主要的Header、footer由activity_main.xml處理,中間空下來的,則透過各個View來做變換。

供備忘及參考。

array個數(PHP、JAVA)


PHP
$array=array(0,1,2,3);
echo count($array) \\==> 4

JAVA
int[] array=new int[]{0,1,2,3};
echo array.length \\==> 4

HTML的空白字元


在HTML要顯示一個空白,就要在HTML網頁中輸入&nbsp;
,輸入一個&nbsp;就代表一個空白。

MySQL資料備份&還原


針對MySQL有效,
備份指令:( )內文字請自行轉換成應該填寫的內容
mysqldump -u(user) -p (database-name) > (filename).sql

還原指令:
mysql -u(root) -p (database-name) < (filename).sql

PHP日期符合資料庫格式


MySQL的日期資料格式是像這樣的
2013-03-14 20:40:17
那如何讓PHP顯示的日期也變成這樣呢?

PHP程式碼:

echo date('Y-m-d H:m:s') //==>顯示現在的時間,格式同資料庫的格式。

如果需要自訂時間的話,可以用
echo date('Y-m-d H:m:s',mktime(date("H"), date("i"),  date("s"), date("m")-1, date("d"), date("Y")));
//顯示上個月份今日,其中mktime的參數順序為時、分、秒、月、日、年,格式同資料庫用

substring mothod for JAVA、PHP、javascript


以下為PHP、JAVA、javascript的substring語法

PHP 
string substr ( string $string , int $start [, int $length ] )

JAVA
public String substring(int beginIndex)
or
public String substring(int beginIndex, int endIndex)

javascript
string.substring(from, to)

String length method for PHP、JAVA、javascript


PHP:
int strlen ( string $string )

JAVA:(String object)
public int length()

javascript:
string.length

android 取得螢幕解析度


// 取得螢幕解析度
 DisplayMetrics dm = new DisplayMetrics();
 this.getWindowManager().getDefaultDisplay().getMetrics(dm);
 Log.i(getClass().getName(),"Screen dpi=( "+dm.widthPixels+" , "+dm.heightPixels+" )");

android AdMob size設定


新版的 Google AdMob Ads SDK (Ver 6.3.1)已有自動取得螢幕大小並設定廣告大小的功能,將AdSize設定為SMART_BANNER後,google ad會自行拉取適合的廣告大小,
詳細的廣告大小可以參考

另外,在google本身的AD程中式,有一項設定是:
  如果取得的廣告大小比螢幕可顯示的大小還大時,
  則不會出現

所以如果廣告無法出現時,
請查看Layout裡面是不是有設定Padding等,造成可顯示大小不夠。

android畫圖﹠橡皮擦功能實現(說明﹠範例下載)


這幾天為了Android的橡皮擦功能搞死人了,
看了網路上的說明,好像懂又好像不懂(實際上就是不懂),
好不容易跌跌撞撞的把路做出來了,
在這裡幫助後人吧!

1.下載範例吧~

2.把它裝起來使用吧~~

3.這支程式是呼叫照相功能後,直接在上傳畫圖的雛形程式,
所以功能計有:
  1)照相
  2)畫畫
  3)橡皮擦
另外也使用Template Design Pattern的概念,

至於其他功能按了沒有用是正常現象,
要讓它有作用請自己寫,謝謝。

針對橡皮擦功能的程式說明:
1.取得相片的圖並放在PhotoView
2.CanvasView是重疊在PhotoView上
3.CanvasView取得相片時,使用相片的大小,建立一張新的Bitmap,並將它給tempCanvas。

public void setPhoto(Bitmap photo) {
 this.photo = photo;
 tempBitmap=Bitmap.createBitmap(photo.getWidth(),photo.getHeight(),Config.ARGB_8888);
 temptCanvas =new Canvas(tempBitmap);
 temptCanvas.drawColor(Color.TRANSPARENT);
}

4.Override CanvasView的onDraw功能,並用temptCanvas.drawPath,之後再用 canvas.drawBitmap(tempBitmap, 0f,0f, null);,這樣就可以將畫在temptCanvas的圖,用canvas重畫出來了。

@Override
protected void onDraw(Canvas canvas) {
 super.onDraw(canvas);

 for (Pair<Paint, Path> pair : pathArray) {
  if (null != pair.second && !pair.second.isEmpty()) {
  temptCanvas.drawPath(pair.second, pair.first);
  }
 }
 if(null!=tempBitmap){
  canvas.drawBitmap(tempBitmap, 0f,0f, null);
 }
}

5.另外網路上也有人寫了很多了,就是橡皮擦的畫筆設定﹣﹣
rubber.setXfermode(new PorterDuffXfermode(Mode.DST_OUT));

還有看不懂的~~程式碼都給你啦,自己一邊玩去。



android動態變更Margin(拖曳效果)


最近寫程式都一直鬼打牆,總是繞不出來,
剛剛又為了一個奇怪的問題一直繞:

要實現拖曳現果,所以動變更leftMargin ﹠ topMargin,
沒想到畫面死都不動,但新增了一個圖案後,
後現剛剛拖曳的效果是有用的,因為原圖已經被拖到指定的位置了,
只是畫面沒有更新;

原程式碼:

@Override
public boolean onScroll(MotionEvent started, MotionEvent current,
float distanceX, float distanceY) {
 if(imgMove){
  layoutParams=(RelativeLayout.LayoutParams)img.getLayoutParams();
  layoutParams.leftMargin=(int)current.getX()-fromPoint.x;
  layoutParams.topMargin=(int)current.getY()-fromPoint.y;
 }
 return false;
}


想說用invalidate()來達成畫面刷新的效果,
結果Android大人鳥都不鳥我;

後來經歴千山萬水後,終於找到解法:

@Override
public boolean onScroll(MotionEvent started, MotionEvent current,
float distanceX, float distanceY) {
 if(imgMove){
  layoutParams=(RelativeLayout.LayoutParams)img.getLayoutParams();
  layoutParams.leftMargin=(int)current.getX()-fromPoint.x;
  layoutParams.topMargin=(int)current.getY()-fromPoint.y;
  img.setLayoutParams(layoutParams);
 }
 return false;
}

加入上面那一行,畫面馬上就可以看到效果了。

又浪費了三個小時的生命,留給後人去乘涼吧!

android的string.xml之﹣﹣帶參數用法


在string.xml中宣告如下:

<string name="msessage_status">上限數:%1$s,已使用:%2$s</string>

在程式中呼叫:
String.format(getText(R.string.msessage_status).toString(),limit,count);

即可達到帶參數的效果

android讓使用者選圖並取得實體路徑


Android本身有Intent可以直接呼叫「圖片庫」程式,
讓使用者選擇想要的圖後,
再回傳讓程式進行後續處理。
程式碼如下:

 openFile.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent( Intent.ACTION_PICK );
    // 過濾檔案格式
    intent.setType( "image/*" );
    // 建立 "檔案選擇器" 的 Intent (第二個參數: 選擇器的標題)
    Intent destIntent = Intent.createChooser( intent, baseActivity.getText(R.string.select_file) );
    // 切換到檔案選擇器 (它的處理結果, 會觸發 onActivityResult 事件)
    baseActivity.startActivityForResult( destIntent, BaseActivity.PICTURE_SELECTED);
}
});

使用者選擇完,回到程式後:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

// after picture selected
if (requestCode == BaseActivity.PICTURE_SELECTED) {
 if (resultCode == RESULT_OK) {
  Uri uri = data.getData();
  System.out.println("mainActivity data="+data);
  System.out.println("mainActivity uri="+uri);
  String str = "DrawMyView"// Data you want to send
  
  }
 }
}

此時發現Log印出來的是類似
uri=content://media/external/images/media/23505
這樣的東西

如果需要對應回實體檔案的話,則需要再透過其他步驟,
程式碼如下:
private String getRealPathFromURI(Uri contentURI) {
    Cursor cursor = baseActivity.getContentResolver()
              .query(contentURI, nullnullnullnull); 
    cursor.moveToFirst(); 
    int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); 
    String name= cursor.getString(idx);
    cursor.close();
    return name;
}

此時就可以看到使用者選擇的圖片所存在的實體路徑。

android在程式中取得View的高度


基本上android在Activity的生命週期中,
是無法取得View的動度高度或寬度的,
原因是因為View尚未顯示出來,
所以程式取得的值都是0。

如果真的有需要取得這個View的高度或寬度時,
有兩個方法可以試看看
1.繼承一個View(視個人需要,繼承需要的View),並使用它(在XML或Code中)
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
在這個Method裡面可以取得Size變更前與變更後的高

2.新增監聽者(我的View是drawContent這個變數,這個Class) implements OnGlobalLayoutListener

drawContent = (RelativeLayout) view.findViewById(R.id.drawContent);
ViewTreeObserver vto = drawContent.getViewTreeObserver();
vto.addOnGlobalLayoutListener(this);

@Override
public void onGlobalLayout() {
if (drawContent.getWidth() != 0 && drawContent.getHeight() != 0) {
ViewTreeObserver obs = drawContent.getViewTreeObserver();
obs.removeGlobalOnLayoutListener(this);
//do things after get size
}
}

不過不管是第一點或第二點,
我在實作上都有碰到問題,
就是取得的Size並不是我想要的,
所以我在程式上動了一個手腳:
1.先在RelativeLayout裡加入一個ImageView
2.將這個ImageView的圖塞滿RelativeLayout,此時的RelativeLayout Size就會是我想要的最大值
3.在onGlobalLayout()中,將原本的ImageView作隱藏的動作,讓使用者看不到塞滿的圖。

為了這個,也是搞了一天,大家加油吧。

android利用Intent分享貼圖至Facebook


基本上利用Android的Intent,就可以簡單的將文字或圖片分享至Facebook,
不過有一個大前提是﹣﹣該台Android必需安裝Facebook的程式

沒有安裝怎麼辦呢?那就只能透過Facebook的API去呼叫了,
但是那樣就必需去研究Facebook的API,會變得比較麻煩。

廢話不多說,分享的程式碼如下:


Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/*");

intent.putExtra(Intent.EXTRA_STREAM,
Uri.parse("file://"getSharePictureFile().getAbsolutePath()));  //圖片的實體路徑

startActivity(Intent.createChooser(intent,getString(R.string.share_title).toString()));

執行後,facebook及其他分享程式就會跳出來讓使用者選擇了。

除了
Intent.EXTRA_STREAM放置圖片外,
Intent另外可利用
intent.putExtra(Intent.EXTRA_SUBJECT,baseActivity.getString(R.string.share_title).toString()); //放標題
intent.putExtra(Intent.EXTRA_TEXT, context); //放文字

不過這兩個對Facebook無效。

android利用Spinner達到PopupMenu的效果


PopupMenu是在Android Level 11(Android 3.0)才有支援,但如果想讓更多使用者使用話,也可以不用PopupMenu,利用Spinner即可達到效果。

Spinner(下拉式選單)在Android中會自動跳出選項讓使用者選擇,
這個部份就很像PopupMenu了,不過仍有幾個地方需要修正。

1.程式一執行就會跑到Listener的onItemSelected去把預設的選項先執行一次(PopupMenu是使用者要用到時才會呼叫)。

2.Spinner選擇和現在值相同時,不會呼叫Listener的onItemSelected,只有使用者選擇不同的值才會觸發。

3.Spinner佔有View的空間。

解決方法:

1.自行新增Listener,並將被擇時的執行方法寫進來。
2.繼承Spinner,@Override public void setSelection(int position) ,在設定Position時,即呼叫自行新增的Listener。
3.Activity裡設定boolean變數,判斷Listener是程式的第一次呼叫?還是被使用者呼叫?
4.隱藏Spinner。

基本上只要這樣做,即可利用Spinner達到PopupMenu的效果。

利用chrome進行javacript debug


Google出產的chrome不單單是瀏灠器,
更是工程師的好利器,
它可以來直接變更HTML、CSS,
並且可以看到調整後的效果,
不過這次要說的是javascript的debug功能。

1.連結到想debug的頁面。
2.滑鼠右鍵「檢查元素」,此時會跑出一個視窗,預設的頁籤是「Elements」(HTML、CSS都可以在這邊直接進行調整,可以直接看到修改的效果,當然啦,調整後的值必需再設定回Server,不然只是改好玩的。)
3.切到「Source」頁籤
4.預設的左方「檔案選擇器」是隱藏的,左上角有一個可以按的按鈕按下去,可以把「檔案選擇器」叫出來,選擇要針對那一個檔案(頁面)做Debug。
5.選擇檔案後,可以看到HTML原始碼跑出來了,找到想暫停的地方,點選左方的行號。
6.重新整理網頁。
7.如此就可以看到javascript被中斷了,剩下的只要有一些Debug經驗的人,應該都沒問題了。

值得一提的是Chrome還有一個很好用的Console,可以直接下javascript並生效。
它隱藏的位置在「檢查元素」頁面的左下角第二個按鈕。

叫出來後,它也會告訴你目前的頁面有那些錯誤(包含HTML找不到圖都會跟你講),
那個部份可直接打字,可以試著輸入
alert('test');

你就可以直接看到視窗跳一個alert出來了,如果在中斷點的話,直接輸入變數,
它也會告訴你目前這個變數值為何!!

Google Chrome,這真是太神奇了!!

android 截取View畫面並存成圖檔


Android提供了一些API呼叫,
可以簡單的將自己開發的程式畫面存成圖檔。
(自己開發:就是可以拿到View這個類別就對了)

方法一:透過View


drawContent.setDrawingCacheEnabled(true);//drawContent 是一個RelativeLayout
Bitmap b = drawContent.getDrawingCache();
try {
//file是最後輸出的實體路徑
 b.compress(CompressFormat.JPEG, 95, new FileOutputStream(file));
 Toast.makeText("save success",Toast.LENGTH_LONG).show();
} catch (FileNotFoundException e) {
 Toast.makeText("save fail",Toast.LENGTH_LONG).show();
}

上方的程式碼是簡單的解釋就是儲存View整個的畫面,
但是有一個重點是...這個View必須要是Visible的。

方法二:透過Canvas

Bitmap tempBitmap = Bitmap.createBitmap(getWidth(),getHeight(), Config.ARGB_4444);//開一個新的圖檔,寬、高、ARGB自訂
Canvas temptCanvas = new Canvas(tempBitmap);//開一個畫布
//開始利用Canvas的API進行繪畫
....
//繪畫結束
temptCanvas.drawBitmap(tempBitmap, 0,0, null);
temptCanvas.save(Canvas.ALL_SAVE_FLAG);
temptCanvas.restore();
try {
//fileName是要輸出的實體路徑
tempBitmap.compress(CompressFormat.JPEG, 95,
new FileOutputStream(fileName));
catch (Exception e) {
e.printStackTrace();
}

第二種方法可以不需要設定Visible也能做到儲存的效果,
至於那一種方法比較好,視個人需要吧!!

PS:
第二種方法因為要透過Bitmap.createBitmap API,所以如果圖片的解析度太高(寬、高的數值太大),很容易發生OutOfMemory Error。

OutOfMemory要解決的話...請自行Google吧!!因為那又可以寫一篇文章了!!


Android將物件存入Sqlite


某些時候需要儲存一個物件,而且這個物件不是簡單的文字或數字,
可以儲存到Sqlite嗎?答案是可以的。

1.
首先是Sqlite的table建立
EX:
CREATE TABLE MyTest('id' INTEGER PRIMARY KEY, object BLOB);

2.
implements Serializable
Ex:
public MyObject mplements Serializable{

}

3.
儲存:

ContentValues values = new ContentValues();

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(baos);
out.writeObject(myObject);

byte[] bytes = baos.toByteArray();
values.put("object", bytes);

out.close();
baos.close();

resolver.insert(MyTest.CONTENT_URI, values);

光是這樣就可以將物件存到DB了,但如果要讀出來呢?

4.讀取
Cursor c = resolver.query(MyTest.CONTENT_URI,new String[] { "id","object" },null,null, null);

 while (c.moveToNext()) {
 ObjectInputStream objectIn = null;
  try {
   objectIn = new ObjectInputStream(  new ByteArrayInputStream(  c.getBlob(1)));
   MyObject myObject = (MyObject) objectIn.readObject(); 
  }catch (Exception ex) {
   ex.printStackTrace();
  } finally {
   if (null != objectIn) {
   objectIn.close();
   }
 }

這樣就可以將物件還原了

...本來是這樣就可以了,但後來發現,程式雖然不會有問題,
但還原回來的物件和存進去的物件有差別,所以有一點要注意的:
要被儲存進Sqlite的物件必須是implements Serializable,舉例來說:
我的MyObject有二個子物件,一個是HashMap,一個是Activity,
這樣子的話,儲進Sqlite的只有HashMap,因為HashMap有implements Serializable,
所以取出來的就只有HashMap。

建議:
1.
繼承將想儲入的Object,implements Serializable,而裡面的類別如果有特別情況需儲入資料庫的,也是繼承Object,,implements Serializable。
2.
在MyObject中建立一段程式碼如下:
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException {
 in.defaultReadObject();
 initial();
}
這一段程式碼在讀取的程式碼中會被呼叫,
即 MyObject myObject = (MyObject) objectIn.readObject(); 
這個時候,這一段程式碼就會被呼叫了,在這個時間點,
物件(MyObject)內的有實作Serializable的變數都會被還原回來,
此時可以利用initial() method,初始化想做的事情。

很複雜對不對...誰叫你想把物件放入Sqlite呢?

加油吧!!




JAVA與星期幾


利用

Calendar c=Calendar.getInstance();
System.out.println(c.get(Calendar.DAY_OF_WEEK));

這樣就可以得出一個數字來判斷今天是星期幾,
問題是這個數字要怎麼和我們的認知對應起來。

首先我們要知道數字與星期的對應如下:

2=>星期一
3=>星期二
4=>星期三
5=>星期四
6=>星期五
7=>星期六
1=>星期日

既然知道了對應的數字,了不起用一個文字陣列去對應相關的日期就可以了,
如果覺得這樣太麻煩,java也提供了另一種方法來處理

SimpleDateFormat df = new SimpleDateFormat("EEE");
String dayinfo = df.format(c.getTime());
System.out.println(dayinfo);//輸出:星期日

這邊可以直接看到輸出的竟然是中文,
所以可以說java已經幫你作掉了,
但很顯然我們可以預計如果語系不一樣的話,
輸出的也會不一樣,所以如果確定程式不會有語系的問題,
第二種也是不錯的選擇。