2012年10月23日星期二

Android中正确使用自定义style及Theme

【零】
如果你仅仅是对默认的主题进行很少的修改,可以查看Android本身提供的一些主题模式,比如将背景变成透明,可以在AndroidManifest.xml中你想改的activity的tag中加入:
android:theme="@android:style/Theme.Translucent"
然后直接运行就可以了。可以参考官方说明

【一】
如果需要将一个Activity的主题改成自定义形式:

1.先在AndroidManifest.xml中你想改的activity的tag中加入:
android:theme="@style/MyTheme"
如果需要将该主题模式运用于所有Activity,可以在AndroidManifest.xml中写上这样一句:
<activity android:theme="@style/MyTheme">

2.然后在res/values文件夹下创建一个styles.xml的文件,在文件中写入:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="MyTheme" parent="android:Theme.Light" >
          <!--需要定义的内容-->
    </style>
</resources>

3.需要定义的内容一般以item形式定义,例如:
<item name="android:textColor">#00FF00</item>
这样可以应用自定义的主题模式了。

【二】
需要注意的还有Android版本问题,如果开发的应用面向Android3.0以下的用户,那么最好采取以下步骤:

1.在res文件夹下创建values-v11(面向Android 3.0+)和values-v14(面向Android 4.0+两个文件夹。

2.在这两个文件夹中分别写入
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="MyTheme" parent="android:Theme.Holo.Light" >
          <!--需要定义的内容-->
    </style>
</resources>

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="MyTheme" parent="android:Theme.DeviceDefault.Light" >
          <!--需要定义的内容-->
    </style>
</resources>
以上Holo是对于Android 3.0+的,DeviceDefault是对于Android 4.0+的。

或者其他你需要引用的parent,比如
    <style name="MyTheme" parent="android:Theme.Holo.Light.NoActionBar" >
          <!--需要定义的内容-->

【三】
最后一个问题是在自定义的主题中定义不同插件的模式,这里以Tab插件为例,我们可以用这样的形式
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="MyTheme" parent="android:Theme.Holo.Light.NoActionBar" >
          <item name="android:tabWidgetStyle">@style/LightTabWidget</item>
    </style>
    <style name="LightTabWidget" parent="@android:style/Widget.TabWidget">
       <!-- 需要定义的内容 -->
    </style>
</resources>
来单独定义插件的一些属性。

这里可以参考themes_device_defaults.xml的源码。

使用Android新版theme改变插件的主题

写好一个Project之后发现它的Spinner,TimePicker之类的Widgets不知何时都变成了旧版的主题。这个问题看似非常之弱却毫无解决的头绪。于是从头写过,一步一步Run,终于发现问题根源。

原因原来是在res/AndroidManifest.xml中误加入一条:
android:theme="@android:style/Theme.NoTitleBar" 

须知这是一条旧版Android的主题的命令,同一个Activity中的所有插件自然就统统变成了旧版的形式。

要用新版(API Level 13 up)的主题来起到上述命令去掉TitleBar的作用,可以使用如下语句:
android:theme="@android:style/Theme.Holo.Light.NoActionBar"
或者
android:theme="@android:style/Theme.Holo.Light.NoActionBar.Fullscreen"
官方说明见此处

以后要注意碰到类似主题形式变化的问题,检查一下AndroidManifest.xml这个文件哦。

2012年10月19日星期五

在Java中给String Array正确地赋值

在写程序的时候遇到这个问题好几次了,因为不能明确报错,程序卡住了都不知道什么原因。结果是每次都抓耳挠腮很久,解决了之后又觉得是无关紧要的问题就没有记录,下次碰到又继续循环……由此可见,再minor的细节问题都是要有良好的记录的,不然就是自讨苦吃的浪费时间。

以下举几个给String Array例子:

String[] str;
str[] = a[];   \\a为已赋值的String Array
正确

String[] str;
for(i=0; i<10; i++) {
str[i] = a[i];  \\a为已赋值的String Array
}
出错

String[] str;
str = new String[10];
for(i=0; i<10; i++) {
str[i] = a[i];   \\a为已赋值的String Array
}
正确

String[][] strs;
strs = {str, a};   \\a, str为已赋值的String Array
出错

String[][] strs;
strs = new String[][] {str, a};  \\a, str为已赋值的String Array
正确

以上的
String[]/[][] str;
str = new String[]/[][];
均可以写成String[]/[][] str = new String[]/[][];

总结:给String Array赋值时,除了直接将另一个数组直接传递给该数组以外,都需要写成string = new String[]/[][];的形式。


2012年10月18日星期四

解决错误:/gen already exists but is not a source folder. Convert to a source folder or rename it.

这个错误一般是由对函数库的改动或是路径的重置引起的,显示为
/myProject/gen already exists but is not a source folder. Convert to a source folder or rename it.

解决这个错误的方法如下:

1.右键点击Package Exploreer下的myProject,选择Properties.

2.选择Java Build Path,再选择Source.

3.点击右边的Add Folder, 选中gen文件夹,点击OK,之后Yes.

4.在Properties的主面板中点击OK确定。

5.右键点击Package Exploreer下的myProject,选择Android Tools, 点击Fix Project Properties .

这样我们就把gen文件夹转变为一个source folder了。

现在我们再Project->Clean,就发现错误已经不再出现了。

值得注意的是,如果这个错误是由路径的重置引起的,那么一定要按照上述方法再将src文件夹转变为一个真正的source folder(出现一个方块形package标志)。

2012年10月15日星期一

发布Android应用时如何给apk自行签署金钥


发布Android应用时,它会提醒你提交自行签署金钥版的apk压缩包。因为之前一直Eclipse中调试模式下用的unbug版的签署,现在要换成自己签署了。在Linux下自行签署金钥步骤如下:

1.在装Java JDK时会同时装keytool,这个东东一般装在/usr/bin下。现在我们要调用它,先打开cd /usr/bin,同时为了让我们有调用权限,之后的步骤需要在root下操作su.

2.调用keytook来建立一个私人密钥,不同参数的含义请参见说明。这里要注意的是,因为上传到android市场时它会提示你有效密钥应超过50年,所以我用了20000天,不知道用少了是否有影响。建立密钥命令如下:
keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 20000
这时候命令行中会出现如下问题,依次回答:
输入keystore密码:  
再次输入新密码: 
您的名字与姓氏是什么?
  [Unknown]:  XXXX
您的组织单位名称是什么?
  [Unknown]:  XX
您的组织名称是什么?
  [Unknown]:  XX
您所在的城市或区域名称是什么?
  [Unknown]:  HK
您所在的州或省份名称是什么?
  [Unknown]:  HK
该单位的两字母国家代码是什么
  [Unknown]:  HK
CN=XXXX, OU=XX, O=XX, L=HK, ST=HK, C=HK 正确吗?
  [否]:  y

正在为以下对象生成 2,048 位 RSA 密钥对和自签名证书 (SHA1withRSA)(有效期为 20,000 天):
CN=XXXX, OU=XX, O=XX, L=HK, ST=HK, C=HK
输入<alias_name>的主密码
(如果和 keystore 密码相同,按回车):  
再次输入新密码: 
[正在存储 my-release-key.keystore]
这样,就私人密钥就创建成功了。

3.在发布模式下编译应用。在Eclipse里Package Explorer下右键单击你所要加密的项目,选择Android Tool,再选择Export Unsigned Application Package,将这个apk在某一路径下保存,默认保存在Eclipse文件夹下。


4.其实放在那里没什么用,我们需要把这个apk转移到建立私人密钥的地方
mv /home/xxxx/eclipse/myActivity.apk /usr/bin
其中myActivity是你刚刚编译的应用的名字。


5.好了,现在可以用自己的私人密钥给自己开发的应用签署了,命令是
jarsigner -verbose -sigalg MD5withRSA -digestalg SHA1 -keystore my-release-key.keystore myActivity.apk alias_name
相关参数可以参考说明
这时候命令行中会出现如下问题,依次回答:
输入密钥库的口令短语: 
输入 alias_name 的密钥口令:
答对之后出现:
   正在添加: META-INF/MANIFEST.MF
   正在添加: META-INF/ALIAS_NA.SF
   正在添加: META-INF/ALIAS_NA.RSA
  .
  .
  .
后面还有一大长串就不详细列出了

6.最后,我们要确定加密完成。
jarsigner -verify -verbose myActivity.apk 
会显示你加密的package的具体信息,最后面是说明:
 s = 已验证签名 
  m = 在清单中列出条目
  k = 在密钥库中至少找到了一个证书
  i = 在身份作用域内至少找到了一个证书

jar 已验证。

7.现在就可以在Android市场上发布你的应用了,要注意的是:
apk 套件名稱不能以下列值為開頭:[com.android, com.google, android, com.example]

8.为了优化你将要发布的应用,可以使用zipalign工具,这个工具在android-sdks->tools文件夹下,是一个.exe文件。用它来进行优化,需要使用命令

./zipalign -v 4 myActivity.apk zimyActivity.apk
其中myActivity.apk是zipalign之前的压缩档案,zimyActivity.apk是优化之后输出的压缩档案。如果希望直接覆盖原档案,则可以用
./zipalign -f -v 4 myActivity.apk
最后出现
Verification successful
就OK了。

2012年10月14日星期日

解决error: Found text " " where item tag is expected

这是一个Android开发中.xml文件里一个奇怪的编译错误,具体报错如下:
[2012-10-15 13:38:07 - com.example.xxx.MainActivity] /home/xxx/workspace/com.example.xxx.MainActivity/res/values-zh-rTW/strings.xml:12: error: Found text "
[2012-10-15 13:38:07 - com.example.xxx.MainActivity]     " where item tag is expected

其实这是空格的格式不正确造成的。如果是原始的手工编辑文档,是不会出现这个问题的。但是如果在不同的文档格式中复制粘帖,就会导致上述错误。

所以为了解决这个问题,建议:

1.检查是否存在不必要的空格,如有即删。如果不行,那么2;

2.重新进行复制粘帖,尽量不要使用不同的文档格式。如果不行,那么3;

3.Replace所有xml文档中whitespace with你手工敲出的space. 如果不行,那么4;

4.自己手工重新编辑一遍。

这类错误可以试试用MS word or excel调用一下文档,看是否空格格式错误。

补充说明一下:类似的错误(xml文档中空格格式错误)还会gen文件夹中R.java出现
Syntax error on tokens, delete these  tokens
的报错。同样通过以上的方法可以解决这个错误。

如何制作一张不规则图片

这里以GIMP Image Editor为例,将一张图片中的不规则形状截取出来,最后创建一张不规则的图片。Photoshop也可以按照类似的方法操作。

1.打开原图片,在View里Zoom放大,使你能看清所有细节。

2.用索套工具Free Select Tool将你所要截取的部分圈起来。如果图片的颜色比较单一,可以Select by Color.

3.菜单栏里或者右键选择编辑复制,Edit->Copy.

4.File->New来建立一个新的图像,在Advanced Options 里面有个Fill With, 选择Transparency, 点击OK.

5.在新建的空白背景(即灰黑相间的格子)中菜单栏里或者右键选择Edit->Paste.

6.选择已经粘帖上的图案,在菜单栏里或者右键选择Image->Fit Canvas to Selection,然后在同样的地方选择Crop to Selection.

7.File->Save保存图片,一定要保存成png格式,因为jpg不支持透明背景。然后按照默认选项Export然后Save.

一个不规则图片就做好了,因为这是个透明背景的图片,将其放入任何其他背景中都只会显示你所截取的图案部分。

Linux下复制命令的错误:cp: omitting directory ` '

想把一个文件夹复制到另一个路径下,敲入命令:
cp /var/www/xxx /home/username
却出现如下错误提示:
cp: omitting directory `xxx' 

这其实是一个很菜鸟的错误,因为我们在这里要操作的是文件夹,其中包含多个文件,所以需要的命令应该是:
cp -r /var/www/xxx /home/username
其中-r的意思recursively copy all the files
或者用另一命令:
cp -a /var/www/xxx /home/username
-a就是all啦

需要注意的是,以上两个命令有少少的区别:
cp -r可能会改变文件夹或文件的某些属性和权限;而用cp -a复制过去,原本和复制本是一模一样的。