|
方法一: 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文件, 参考:
|