|
方法一: Java代碼  - public void saveIcon(Bitmap icon) {
- if (icon == null) {
- return;
- }
-
- // 最終圖標要保存到瀏覽器的內部數據庫中,系統程序均保存為SQLite格式,Browser也不例外,因為圖片是二進制的所以使用字節數組存儲數據庫的
- // BLOB類型
- final ByteArrayOutputStream os = new ByteArrayOutputStream();
- // 將Bitmap壓縮成PNG編碼,質量為100%存儲
- icon.compress(Bitmap.CompressFormat.PNG, 100, os);
- // 構造SQLite的Content對象,這里也可以使用raw
- ContentValues values = new ContentValues();
- // 寫入數據庫的Browser.BookmarkColumns.TOUCH_ICON字段
- values.put(Browser.BookmarkColumns.TOUCH_ICON, os.toByteArray());
-
- DBUtil.update(....);//調用更新或者插入到數據庫的方法
- }
方法二:如果數據表入口時一個content:URI Java代碼  - import android.provider.MediaStore.Images.Media;
- import android.content.ContentValues;
- import java.io.OutputStream;
-
- // Save the name and description of an image in a ContentValues map.
- ContentValues values = new ContentValues(3);
- values.put(Media.DISPLAY_NAME, "road_trip_1");
- values.put(Media.DESCRIPTION, "Day 1, trip to Los Angeles");
- values.put(Media.MIME_TYPE, "image/jpeg");
-
- // Add a new record without the bitmap, but with the values just set.
- // insert() returns the URI of the new record.
- Uri uri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, values);
-
- // Now get a handle to the file for that record, and save the data into it.
- // Here, sourceBitmap is a Bitmap object representing the file to save to the database.
- try {
- OutputStream outStream = getContentResolver().openOutputStream(uri);
- sourceBitmap.compress(Bitmap.CompressFormat.JPEG, 50, outStream);
- outStream.close();
- } catch (Exception e) {
- Log.e(TAG, "exception while writing image", e);
- }
1、成員變量(全局變量)命名首字母以m開頭第二個字母大寫;(e.g int mIndex = 0) 2、常量全部大寫 3、靜態的變量命名首字母以s開頭第二個字母大寫;(e.g static int sIndex = 0)
原文出自:http://blog.csdn.net/aa4790139/article/details/6754230 第一種情況: Proguard returned with error code 1. See console Error: C:/Documents (系統找不到指定文件) 后來發現是因為將整個工程放到了桌面上,而桌面的目錄是C:/Documents and Settings/Administrator/桌面,在這里面有空格,而proguard進行發編譯的時候是不允許有空格的 如果換了正確路徑還不好用的話,直接刪除proguard就好了 注意:SDK和程序路徑最好不要有空格符 第二種情況: Proguard returned with error code 1. See console 異常: java.lang.ArrayIndexOutOfBoundsException 解決辦法:將proguard.cfg中的"-dontpreverify"改成“-dontoptimize” 參考文章:http://groups.google.com/group/android-developers/browse_thread/thread/eca3b0f5ce6ad00f
建一個自己的博客,既可以練習php,mysql,還能了解一些網站基礎知識。好了現在我就吧自己建立玩站的過程寫下來,供大家參考!過程是漫長的,只有自己摸索,才能不斷增加經驗,才能自己解決問題! 首先我們得要個空間,這個空間是用來放網頁文件滴,其實網站就是一個文件夾,里面放了許多網頁,在靜態網頁中,當你用瀏覽器訪問這個文件時它會首先訪問index.html,自己動手做過的同學肯定知道,當你把別人網站拷下來的時候體會就明顯了,我就這么干的(好像很廢話)。 1.我前前后后申請了N多空間,不是空間太小,就是無法登陸,或者DNS解析不上,所以我推薦用www.simplefreeweb.com,完全免費滴,等一晚上就把賬號密碼發過來了,后臺有很多工具mysql,phpmyadmin等等(額- -!我忘了說一點,懂一點數據庫和php的同學上手快一些,因為你連數據庫,表都不知道,那出現問題你都不知道在哪里)。 2.注冊好能登陸的前提下,再到cn.wordpress.org下載他們的wordpress(這是別人做好的玩站模板,直接可用,里面是php文件如果你自己有自信比他做的好,或者練習php,那就自己做吧)解壓上傳到空間,上傳工具很多,我用的是filezilla,用www.simplefreeweb.com提供的ftp站好密碼,上傳到ftp里面的www目錄下,記住上傳wordpress文件下的文件,不要把wordpress文件夾一起傳上去,要不然你要訪問yourname.simplefreeweb.com/wordpress才能訪問。 3.上傳完成,用simplefreeweb給你的后臺登陸網址登陸,在里面建立數據庫,再向數據庫添加用戶的時候一定要勾選全部權限,要不然在后面wordpress安裝的時候會連接出現問題! 4.建立好數據庫后,登陸你的網站yourname.simplefreeweb.com,會出現wordpress安裝導向,按照步驟就可以啦! 5.yourname.simplefreeweb.com這個是人家的二級域名,既不個性,有很難記,所以我們得要個自己的。網上的頂級域名很多但價格不菲,而且申請麻煩,所以我建議到http://www.dot.tk申請,很方便! 綁定域名,就是將這個域名指向你的網站,方法主要是域名解析,免費的解析商也很多,很久都沒消息(我的就是,ywww.simplefreeweb.com自帶的解析不給力啊)。但是,tk里面有個域名跳轉,當你申請完后把你的yourname.simplefreeweb.com填進去,這樣當訪問你的域名,如我的www.liubos.k時候,直接跳到liubo.simplefreeweb.com。好處是方便,缺點是當別人訪問非主頁時,還是顯示原來的網址!又等一晚上!第二天再訪問自己的網站www.xxx.tk吧!說到xxx,我又邪惡了,呵呵!
摘要: android 使用contentobserver監聽數據庫內容變化在android中經常會用到改變數據庫內容后再去使用數據庫更新的內容,很多人會重新去query一遍,但是這樣的問題就是程序會特別占內存,而且有可能會摟關cursor而導致程序內存未釋放等等。其實android內部提供了一種ContentObserver的東西來監聽數據庫內容的變化。ContentObserver的構造函數需要一個參... 閱讀全文
最近有個需求,不去調用系統界面發送彩信功能。做過發送短信功能的同學可能第一反應是這樣: 不使用 StartActivity,像發短信那樣,調用一個類似于發短信的方法 SmsManager smsManager = SmsManager.getDefault(); smsManager.sendTextMessage(phoneCode, null, text, null, null); 可以實現嗎? 答案是否定的,因為android上根本就沒有提供發送彩信的接口,如果你想發送彩信,對不起,請調用系統彩信app界面,如下
Intent sendIntent = new Intent(Intent.ACTION_SEND, Uri.parse("mms://"));
sendIntent.setType("image/jpeg");
String url = "file://sdcard//tmpPhoto.jpg";
sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(url));
startActivity(Intent.createChooser(sendIntent, "MMS:"));
但是這種方法往往不能滿足我們的需求,能不能不調用系統界面,自己實現發送彩信呢?經過幾天的努力,終于找到了解決辦法。 第一步:先構造出你要發送的彩信內容,即構建一個pdu,需要用到以下幾個類,這些類都是從android源碼的MMS應用中mms.pdu包中copy出來的。你需要將pdu包中的所有類 都拷貝到你的工程中,然后自己酌情調通。 final SendReq sendRequest = new SendReq(); final PduBody pduBody = new PduBody(); final PduPart part = new PduPart();//存放附件,每個附件是一個part,如果添加多個附件,就想body中add多個part。 pduBody.addPart(partPdu); sendRequest.setBody(pduBody); final PduComposer composer = new PduComposer(ctx, sendRequest); final byte[] bytesToSend = composer.make(); //將彩信的內容以及主題等信息轉化成byte數組,準備通過http協議發送到 ”http://mmsc.monternet.com”; 第二步:發送彩信到彩信中心。 構建pdu的代碼:
String subject = "測試彩信";
String recipient = "接收彩信的號碼";//138xxxxxxx
final SendReq sendRequest = new SendReq();
final EncodedStringValue[] sub = EncodedStringValue.extract(subject);
if (sub != null && sub.length > 0) {
sendRequest.setSubject(sub[0]);
}
final EncodedStringValue[] phoneNumbers = EncodedStringValue.extract(recipient);
if (phoneNumbers != null && phoneNumbers.length > 0) {
sendRequest.addTo(phoneNumbers[0]);
}
final PduBody pduBody = new PduBody();
final PduPart part = new PduPart();
part.setName("sample".getBytes());
part.setContentType("image/png".getBytes());
String furl = "file://mnt/sdcard//1.jpg";
final PduPart partPdu = new PduPart();
partPdu.setCharset(CharacterSets.UTF_8);//UTF_16
partPdu.setName(part.getName());
partPdu.setContentType(part.getContentType());
partPdu.setDataUri(Uri.parse(furl));
pduBody.addPart(partPdu);
sendRequest.setBody(pduBody);
final PduComposer composer = new PduComposer(ctx, sendRequest);
final byte[] bytesToSend = composer.make();
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
HttpConnectInterface.sendMMS(ctx, bytesToSend);
//
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start(); 發送pdu到彩信中心的代碼: public static String mmscUrl = "http://mmsc.monternet.com";
// public static String mmscUrl = "http://www.baidu.com/";
public static String mmsProxy = "10.0.0.172";
public static String mmsProt = "80";
private static String HDR_VALUE_ACCEPT_LANGUAGE = "";
// Definition for necessary HTTP headers.
private static final String HDR_KEY_ACCEPT = "Accept";
private static final String HDR_KEY_ACCEPT_LANGUAGE = "Accept-Language";
private static final String HDR_VALUE_ACCEPT =
"*/*, application/vnd.wap.mms-message, application/vnd.wap.sic";
public static byte[] sendMMS(Context context, byte[] pdu)throws IOException{
HDR_VALUE_ACCEPT_LANGUAGE = getHttpAcceptLanguage();
if (mmscUrl == null) {
throw new IllegalArgumentException("URL must not be null.");
}
HttpClient client = null;
try {
// Make sure to use a proxy which supports CONNECT.
client = HttpConnector.buileClient(context);
HttpPost post = new HttpPost(mmscUrl);
//mms PUD START
ByteArrayEntity entity = new ByteArrayEntity(pdu);
entity.setContentType("application/vnd.wap.mms-message");
post.setEntity(entity);
post.addHeader(HDR_KEY_ACCEPT, HDR_VALUE_ACCEPT);
post.addHeader(HDR_KEY_ACCEPT_LANGUAGE, HDR_VALUE_ACCEPT_LANGUAGE);
//mms PUD END
HttpParams params = client.getParams();
HttpProtocolParams.setContentCharset(params, "UTF-8");
HttpResponse response = client.execute(post);
LogUtility.showLog(tag, "111");
StatusLine status = response.getStatusLine();
LogUtility.showLog(tag, "status "+status.getStatusCode());
if (status.getStatusCode() != 200) { // HTTP 200 is not success.
LogUtility.showLog(tag, "!200");
throw new IOException("HTTP error: " + status.getReasonPhrase());
}
HttpEntity resentity = response.getEntity();
byte[] body = null;
if (resentity != null) {
try {
if (resentity.getContentLength() > 0) {
body = new byte[(int) resentity.getContentLength()];
DataInputStream dis = new DataInputStream(resentity.getContent());
try {
dis.readFully(body);
} finally {
try {
dis.close();
} catch (IOException e) {
Log.e(tag, "Error closing input stream: " + e.getMessage());
}
}
}
} finally {
if (entity != null) {
entity.consumeContent();
}
}
}
LogUtility.showLog(tag, "result:"+new String(body));
return body;
} catch (IllegalStateException e) {
LogUtility.showLog(tag, "",e);
// handleHttpConnectionException(e, mmscUrl);
} catch (IllegalArgumentException e) {
LogUtility.showLog(tag, "",e);
// handleHttpConnectionException(e, mmscUrl);
} catch (SocketException e) {
LogUtility.showLog(tag, "",e);
// handleHttpConnectionException(e, mmscUrl);
} catch (Exception e) {
LogUtility.showLog(tag, "",e);
//handleHttpConnectionException(e, mmscUrl);
} finally {
if (client != null) {
// client.;
}
}
return new byte[0];
} 至此,彩信的發送算是完成了。 總結:android的彩信相關操作都是沒有api的,包括彩信的讀取、發送、存儲。這些過程都是需要手動去完成的。想要弄懂這些過程,需要仔細閱讀android源碼中的mms這個app。還有就是去研究mmssms.db數據庫,因為彩信的讀取和存儲其實都是對mmssms.db這個數據庫的操作過程。而且因為這個是共享的數據庫,所以只能用ContentProvider這個組件去操作db。 總之,想要研究彩信這塊(包括普通短信),你就必須的研究mmssms.db的操作方法,多多了解每個表對應的哪個uri,每個uri能提供什么樣的操作,那些字段代表短信的那些屬性等。 最后推薦個好用的sqlite查看工具:SQLite Database Browser。
注意到在Activity的API中有大量的onXXXX形式的函數定義,除了我們前面用到的onCreate以外,還有onStart,onStop以及onPause等等。從字面上看,它們是一些事件回調,那么次序又是如何的呢?其實這種事情,自己做個實驗最明白不過了。在做這個實驗之前,我們先得找到在Android中的Log是如何輸出的。
顯然,我們要用的是android.util.log類,這個類相當的簡單易用,因為它提供的全是一些靜態方法:
Log.v(String tag, String msg); //VERBOSE
Log.d(String tag, String msg); //DEBUG
Log.i(String tag, String msg); //INFO
Log.w(String tag, String msg); //WARN
Log.e(String tag, String msg); //ERROR
前面的tag是由我們定義的一個標識,一般可以用“類名_方法名“來定義。 輸出的LOG信息,如果用Eclipse+ADT開發,在LogCat中就可以看到,否則用adb logcat也行,不過我是從來都依賴于IDE環境的。
好了,現在我們修改前面的HelloThree代碼:
public void onStart()
{
super.onStart();
Log.v(TAG,"onStart");
}
public void onStop()
{
super.onStop();
Log.v(TAG,"onStop");
}
public void onResume()
{
super.onResume();
Log.v(TAG,"onResume");
}
public void onRestart()
{
super.onRestart();
Log.v(TAG,"onReStart");
}
public void onPause()
{
super.onPause();
Log.v(TAG,"onPause");
}
public void onDestroy()
{
super.onDestroy();
Log.v(TAG,"onDestroy");
}
public void onFreeze(Bundle outState)
{
super.onFreeze(outState);
Log.v(TAG,"onFreeze");
} 在HelloThreeB中也同樣增加這樣的代碼,編譯,運行一下,從logcat中分析輸出的日志。 在啟動第一個界面Activity One時,它的次序是: onCreate (ONE) - onStart (ONE) - onResume(ONE) 雖然是第一次啟動,也要走一遍這個resume事件。然后,我們點goto跳到第二個Activity Two中(前一個沒有關閉),這時走的次序是: onFreeze(ONE) - onPause(ONE) - onCreate(TWO) - onStart(TWO) - onResume(TWO) - onStop(ONE) 說明,第二個Activity Two在啟動前,One會經歷一個:凍結、暫停的過程,在啟動Two后,One才會被停止? 然后,我們再點back回到第一個界面,這時走的次序是: onPause(TWO) - onActivityResult(ONE) - onStart(ONE) - onRestart(ONE) - onResume(ONE) - onStop(TWO) - onDestroy(TWO) 說明,返回時,Two沒有經歷凍結就直接暫停了,在One接收參數,重啟后,Two就停止并被銷毀了。 最后,我們點一下Exit退出應用,它的次序是: onPause(ONE) - onStop(ONE) - onDestroy(ONE) 說明如果我們用了finish的話,不會有freeze,但是仍會經歷pause - stop才被銷毀。
這里有點疑問的是:為什么回來時先是Start才是Restart?可是文檔中的圖上畫的卻是先restart再start的啊?不過,后面的表格中的描述好象是正確的,start后面總是跟著resume(如果是第一次)或者restart(如果原來被stop掉了,這種情況會在start與resume中插一個restart)。
下面不跑例子了,看看文檔吧。
1.Android用Activity Stack來管理多個Activity,所以呢,同一時刻只會有最頂上的那個Activity是處于active或者running狀態。其它的Activity都被壓在下面了。
2.如果非活動的Activity仍是可見的(即如果上面壓著的是一個非全屏的Activity或透明的Activity),它是處于paused狀態的。在系統內存不足的情況下,paused狀態的Activity是有可被系統殺掉的。只是不明白,如果它被干掉了,界面上的顯示又會變成什么模樣?看來下回有必要研究一下這種情況了。
3.幾個事件的配對可以比較清楚地理解它們的關系。Create與Destroy配成一對,叫entrie lifetime,在創建時分配資源,則在銷毀時釋放資源;往上一點還有Start與Stop一對,叫visible lifetime,表達的是可見與非可見這么一個過程;最頂上的就是Resume和Pause這一對了,叫foreground lifetime,表達的了是否處于激活狀態的過程。
4.因此,我們實現的Activity派生類,要重載兩個重要的方法:onCreate()進行初始化操作,onPause()保存當前操作的結果。
除了Activity Lifecycle以外,Android還有一個Process Lifecycle的說明:
在內存不足的時候,Android是會主動清理門戶的,那它又是如何判斷哪個process是可以清掉的呢?文檔中也提到了它的重要性排序:
1.最容易被清掉的是empty process,空進程是指那些沒有Activity與之綁定,也沒有任何應用程序組件(如Services或者IntentReceiver)與之綁定的進程,也就是說在這個process中沒有任何activity或者service之類的東西,它們僅僅是作為一個cache,在啟動新的Activity時可以提高速度。它們是會被優先清掉的。因此建議,我們的后臺操作,最好是作成Service的形式,也就是說應該在Activity中啟動一個Service去執行這些操作。
2.接下來就是background activity了,也就是被stop掉了那些activity所處的process,那些不可見的Activity被清掉的確是安全的,系統維持著一個LRU列表,多個處于background的activity都在這里面,系統可以根據LRU列表判斷哪些activity是可以被清掉的,以及其中哪一個應該是最先被清掉。不過,文檔中提到在這個已被清掉的Activity又被重新創建的時候,它的onCreate會被調用,參數就是onFreeze時的那個Bundle。不過這里有一點不明白的是,難道這個Activity被killed時,Android會幫它保留著這個Bundle嗎?
3.然后就輪到service process了,這是一個與Service綁定的進程,由startService方法啟動。雖然它們不為用戶所見,但一般是在處理一些長時間的操作(例如MP3的播放),系統會保護它,除非真的沒有內存可用了。
4.接著又輪到那些visible activity了,或者說visible process。前面也談到這個情況,被Paused的Activity也是有可能會被系統清掉,不過相對來說,它已經是處于一個比較安全的位置了。
5.最安全應該就是那個foreground activity了,不到迫不得已它是不會被清掉的。這種process不僅包括resume之后的activity,也包括那些onReceiveIntent之后的IntentReceiver實例。
在Android Application的生命周期的討論中,文檔也提到了一些需要注意的事項:因為Android應用程序的生存期并不是由應用本身直接控制的,而是由Android系統平臺進行管理的,所以,對于我們開發者而言,需要了解不同的組件Activity、Service和IntentReceiver的生命,切記的是:如果組件的選擇不當,很有可能系統會殺掉一個正在進行重要工作的進程。
啟動代碼混淆功能在較新版本的Android tools和ADT,項目工程里面是帶有proguard.cfg的代碼混淆配置文件,但默認是沒有啟動這個配置的,需要手動地在default.properties里面添加指定這個配置文件:# Project target. target=android-3 proguard.config=proguard.cfg 然后按F5刷新當前項目工程,這時候Eclipse檢測了文件的變動而重新編譯! 生成簽名發布apk1.Eclipse工程中右鍵工程,彈出選項中選擇 android工具-生成簽名應用包: 2.選擇需要打包的android項目工程(注:這里會自動選擇當前的Project的): 3.如果已有私鑰文件,選擇私鑰文件 輸入密碼,如果沒有私鑰文件見 第6和7步創建私鑰文件: 4.輸入私鑰別名和密碼: 5.選擇APK存儲的位置,并完成設置 開始生成: 6.沒有私鑰文件的情況,創建私鑰文件(注:這里私鑰文件的Location位置最好自己選擇一個新位置,便于牢記,而且最好把這個私鑰文件備份到其他地方去以免丟失,因為應用程序的更新需要同一私鑰文件): 7.輸入私鑰文件所需信息,并創建(注:這里的密碼是用于Key的別名的,和上面的KeyStore文件的不同,這點可以看步驟3和4。另外下面的名字,開發者資料等是不需要全部填寫的,dialog會有提示的): 這時候生成的apk,我發現是比debug版本的要小!如果你發現沒有變小的話,請確認項目工程是重新編譯的!但代碼混淆的效果一般般,基本上還是可以看到原來的語句!
摘要: android:allowTaskReparenting 用來標記Activity能否從啟動的Task移動到有著affinity的Task(當這個Task進入到前臺時)——“true”,表示能移動,“false”,表示它必須呆在啟動時呆在的那個Task里。 ... 閱讀全文
Apk簽名首先要有一個keystore的簽名用的文件. keystore是由jdk自帶的工具keytool生成的.具體生成方式參考一下: 開始->運行->cmd->cd 到你安裝的jdk的目錄這里我是 C:\Program Files\Java\jdk1.6.0_10\bin 然后輸入:keytool -genkey -alias asaiAndroid.keystore -keyalg RSA -validity 20000 -keystore asaiAndroid.keystore -alias 后跟的是別名這里是 asaiAndroid.keystore -keyalg 是加密方式這里是 RSA -validity 是有效期 這里是 20000 -keystore 就是要生成的keystore的名稱 這里是 asaiAndroid.keystore 然后按回車 按回車后首先會提示你輸入密碼:這個在簽名時要用的要記住了哦。 然后會再確認你的密碼。 之后會依次叫你輸入 姓名,組織單位,組織名稱,城市區域,省份名稱,國家代碼等。 參考:
運行完可以在 C:\Program Files\Java\jdk1.6.0_10\bin 里找到剛才生產的keyStore文件
好現在開始給Apk簽名了: 在 C:\Program Files\Java\jdk1.6.0_10\bin 還提供一個工具 jarsigner.exe 好現在可以在剛才的命令行后繼續運行以下命令給APK簽名: jarsigner -verbose -keystore asaiAndroid.keystore -signedjar LotteryOnline_signed.apk LotteryOnline.apk asaiAndroid.keystore -keystore:keystore 的名稱 LotteryOnline_signed.apk 是簽完名后的APK LotteryOnline.apk 是簽名前的apk 然后按回車:會要求輸入剛才設置的密碼,輸入后按回車就開始簽名了。 參考:
運行成功后在 C:\Program Files\Java\jdk1.6.0_10\bin 目錄下會多出一個被簽名的apk文件, 參考:
|