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已經幫你作掉了,
但很顯然我們可以預計如果語系不一樣的話,
輸出的也會不一樣,所以如果確定程式不會有語系的問題,
第二種也是不錯的選擇。