i-chou's tech blog

Android iOS

[iOS开发]关于导入带有数据的SQLite文件

| Comments

DB文件需要引入到项目中的Supporting Files文件夹下。

注意:直接拖拽的形式引入时,需要勾选Add to tagets选项,同时根据情况注意勾选上面的Copy选项。

模拟器调试情况下,DB文件的存放路径如下: 当前用户/Library/Application Support/iPhone Simulator/版本号(6.0)/Applications/你的app名所在文件夹/Documents

Google API 方式制作饼状图

| Comments

最简单的一种方式,Android上面使用WebView控件加载即可,以下是GoogleAPI相关内容。

PS:需要添加网络访问权限。

URL: http://chart.apis.google.com/chart?cht=p3&chs=250x100&chd=t:60,40&chl=Hello%7CWorld

Components

https://chart.apis.google.com/chart?

This is the base URL for all chart requests. (However, seeImproving Performance on Pages with Many Charts below for an optional variation for pages with multiple charts.)cht=p3The chart type: here, a 3D pie chart.chs=250x100The chart size (width xheight), in pixels. See the maximum valueshere.chd=t:60,40The chart data. This data is in simple text format, but there areother formats.chl=Hello|WorldTheslice labels.&Parameters are separated by an ampersand.Note: When embedding an URL in HTML, for example as thesrc attribute of an tag, you should replace the& between parameters with the characters& This includes when you generate page HTML with PHP or some other language. However, when typing a URL in the browser, or whencalling a URL in code, for example when fetching a URL in PHP or Perl, you should use the& mark.

Xperia TM GX UI适配遇到的小问题

| Comments

Sony Xperia TM GX S0-04D 720*1280 和 S0-05D 均为软控制栏,最近在为这两款机器做适配时候遇到一些小问题,分享在这里。

  • 问题1:

    现象:Sony上,从第二行LineaLayout开始往下窜一定距离。从其他机器和模拟器上均显示正常。

    原因:LinearLayout的Wrap_content属性在Sony和其它机器里的解析有所不同。

    改善:将高度设置成内容的实际高度dp值。

  • 问题2:

    现象:4.0以后机种的SimpleOnGestureListener类手势问题。

    原因:onFiling方法触发频繁,导致更换背景的耗时操作使反映变卡。

    改善:更换背景耗时操作加入判断条件再触发。

Google产品体验_前端设计

| Comments

其实不仅仅是google,好多公司的产品体验都非常好,看似简单,但细微处让人舒服得很。

最近不经意间发现drive.google宣传页的前端设计,每个功能点介绍正好占据一个页面,唯独首页最上面的视频没有占据整个画面,而特意露出下一节的一行字,我猜想这是让用户知道下方还有内容可以看。

PS:因为是用mac版chrome体验,所以其他版本浏览器不清楚是不是这样。就算google不是刻意做成我理解的这样,我认为还是应该把这种用户体验考虑在自己以后的开发和设计理念中。

当Eclipse遇到ADT升级

| Comments

  • 问题一: Eclipse3.7.2 + ADT18 一直出现找不到jar中class的问题。今天终于找到结果。由于新版本中把lib名称改称libs的缘故。

    解决方案:

    This issue occurs because the “lib” folder is renamed to “libs” now by Android People. And as soon as we place our external jars to this “libs” folder then it will automatically be added to the build path of the application.

    Remove the libraries from the standard Java build path :

    Right click on the project name > Properties > Java Build Path > tab Libraries > remove everything except the “Android X.X” (2.3.3 in my case) and the “Android Dependencies”

    Rename the libraries folder from “lib” to “libs”

    By doing that, all the libraries in the folder “libs” are found by the Android plugin and are added to the “Android Dependencies” item of the project

    Clean the project (not exactly needed)

    You are good to go !

    参考:

    1. http://stackoverflow.com/questions/9923161/getting-classnotfound-error-after-updating-from-adt-16-to-adt-17

    2. http://android.foxykeep.com/dev/how-to-fix-the-classdefnotfounderror-with-adt-17

    3. http://www.eoeandroid.com/thread-165493-1-1.html

  • 问题二: Eclipse每次run都重新开启一个新的emulator运行

    解决方案:

    在点击 Run asAndroid Application以后,选择弹出窗口左下方的 use same device for furture launches

Android Canvas绘制文字 自动换行

| Comments

import java.util.Vector; 

import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.Paint.FontMetrics; 
import android.view.KeyEvent; 

public class TextUtil { 

private float  mTextPosx = 0;// x坐标 
private float  mTextPosy = 0;// y坐标 
private float mTextWidth = 0;// 绘制宽度 
private float mTextHeight = 0;// 绘制高度 
private int mFontHeight = 0;// 绘制字体高度 
private int mPageLineNum = 0;// 每一页显示的行数 
private int mCanvasBGColor = 0;// 背景颜色 
private int mFontColor = 0;// 字体颜色 
private int mAlpha = 0;// Alpha值 
private int mRealLine = 0;// 字符串真实的行数 
private int mCurrentLine = 0;// 当前行 
private int mTextSize = 0;// 字体大小 
private String mStrText = ""; 
private Vector mString = null; 
private Paint mPaint = null; 

public TextUtil(String StrText, float  x, float  y, float w, float h, int bgcolor, 
      int textcolor, int alpha, int textsize) { 
  mPaint = new Paint(); 
  mString = new Vector(); 
  this.mStrText = StrText; 
  this.mTextPosx = x; 
  this.mTextPosy = y; 
  this.mTextWidth = w; 
  this.mTextHeight = h; 
  this.mCanvasBGColor = bgcolor; 
  this.mFontColor = textcolor; 
  this.mAlpha = alpha; 
  this.mTextSize = textsize; 
} 

public void InitText() { 
  mString.clear();// 清空Vector 
  // 对画笔属性的设置 
  // mPaint.setARGB(this.mAlpha, Color.red(this.mFontColor), Color 
  // .green(this.mFontColor), Color.blue(this.mFontColor)); 
  mPaint.setTextSize(this.mTextSize); 
  mPaint.setColor(Color.BLUE); 
  mPaint.setAntiAlias(true); 

  this.GetTextIfon(); 
 } 

 /** 
  * 得到字符串信息包括行数,页数等信息 
  */ 
 public void GetTextIfon() { 
  char ch; 
  int w = 0; 
  int istart = 0; 
  FontMetrics fm = mPaint.getFontMetrics();// 得到系统默认字体属性 
  mFontHeight = (int) (Math.ceil(fm.descent - fm.top) + 2);// 获得字体高度 
  mPageLineNum = (int) (mTextHeight / mFontHeight);// 获得行数 

  int count = this.mStrText.length(); 
  for (int i = 0; i < count; i++) { 
      ch = this.mStrText.charAt(i); 
      float[] widths = new float[1]; 
      String str = String.valueOf(ch); 
      mPaint.getTextWidths(str, widths); 
      if (ch == '/n') { 
          mRealLine++;// 真实的行数加一 
          mString.addElement(this.mStrText.substring(istart, i)); 
          istart = i + 1; 
          w = 0; 
      } else { 
          w += (int) Math.ceil(widths[0]); 
          if (w > this.mTextWidth) { 
              mRealLine++;// 真实的行数加一 
              mString.addElement(this.mStrText.substring(istart, i)); 
              istart = i; 
              i--; 
              w = 0; 
          } else { 
              if (i == count - 1) { 
                  mRealLine++;// 真实的行数加一 
                  mString.addElement(this.mStrText.substring(istart, 
                          count)); 
              } 
          } 
      } 
  } 
} 

/** 
 * 绘制字符串 
 * 
 * @param canvas 
 */ 
public void DrawText(Canvas canvas) { 
     for (int i = this.mCurrentLine, j = 0; i < this.mRealLine; i++, j++) { 
          if (j > this.mPageLineNum) { 
              break; 
          } 
       canvas.drawText((String) (mString.elementAt(i)), this.mTextPosx, 
                this.mTextPosy + this.mFontHeight * j, mPaint); 
     } 
 } 

/** 
* 翻页等按键处理 
* 
* @param keyCode 
* @param event 
* @return 
*/ 
public boolean KeyDown(int keyCode, KeyEvent event) { 
    if (keyCode == KeyEvent.KEYCODE_DPAD_UP) { 
       if (this.mCurrentLine > 0) { 
            this.mCurrentLine--; 
        } 
    } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { 
        if ((this.mCurrentLine + this.mPageLineNum) < (this.mRealLine - 1)) { 
            this.mCurrentLine++; 
        } 
      } 
      return false; 
   } 
}

AndroidManifest.xml部分属性说明

| Comments

  • android:allowTaskReparenting

    用法<application android:allowTaskReparenting="true/false"></application> 是否允许Activity更换从属的任务,比如从短信息任务 切换到浏览器任务。用来标记Activity能否从启动的Task移动到有着affinity的Task(当这个Task进入到前台时)—— “true”,表示能移动,“false”,表示它必须呆在启动时呆在的那个Task里。

    如果这个特性没有被设定,设定到<application>元素上的allowTaskReparenting特性的值会应用到Activity上。默认值为“false”。

    一般来说,当Activity启动后,它就与启动它的Task关联,并且在那里耗尽它的整个生命周期。当当前的Task不再显示时,你可以使用这个特性来 强制Activity移动到有着affinity的Task中。典型用法是:把一个应用程序的Activity移到另一个应用程序的主Task中。

    例如,如果e-mail中包含一个web页的链接,点击它就会启动一个Activity来显示这个页面。这个Activity是由Browser应用程序 定义的,但是,现在它作为e-mail Task的一部分。如果它重新宿主到Browser Task里,当Browser下一次进入到前台时,它就能被看见,并且,当e-mail Task再次进入前台时,就看不到它了。

    Actvity的affinity是由taskAffinity特性定义的。Task的affinity是通过读取根Activity的affinity 决定。因此,根据定义,根Activity总是位于相同affinity的Task里。由于启动模式为“singleTask”和 “singleInstance”的Activity只能位于Task的底部,因此,重新宿主只能限于“standard”和“singleTop”模 式。

  • android:alwaysRetainTaskState

    用法<activity android:alwaysRetainTaskState="true/false"></activity> 用来标记Activity所在的Task的状态是否总是由系统来保持——“true”,表示总是;“false”,表示在某种情形下允许系统恢复Task 到它的初始化状态。默认值是“false”。这个特性只针对Task的根Activity有意义;对其它Activity来说,忽略之。 一般来说,特定的情形如当用户从主画面重新选择这个Task时,系统会对这个Task进行清理(从stack中删除位于根Activity之上的所有Activivity)。典型的情况,当用户有一段时间没有访问这个Task时也会这么做,例如30分钟。 然而,当这个特性设为“true”时,用户总是能回到这个Task的最新状态,无论他们是如何启动的。这非常有用,例如,像Browser应用程序,这里有很多的状态(例如多个打开的Tab),用户不想丢失这些状态。

  • android:clearTaskOnLanunch

    用法<activity android:clearTaskOnLanunch=”true/false”></activity> 用来标记是否从Task中清除所有的Activity,除了根Activity外(每当从主画面重新启动时)——“true”,表示总是清除至它的 根 Activity,“false”表示不。默认值是“false”。这个特性只对启动一个新的Task的Activity(根Activity)有意义; 对Task中其它的Activity忽略。 当这个值为“true”,每次用户重新启动这个Task时,都会进入到它的根Activity中,不管这个Task最后在做些什么,也不管用户是使 用 BACK还是HOME离开的。当这个值为“false”时,可能会在一些情形下(参考alwaysRetainTaskState特性)清除Task的 Activity,但不总是。 假设,某人从主画面启动了Activity P,并从那里迁移至Activity Q。接下来用户按下HOME,然后返回Activity P。一般,用户可能见到的是Activity Q,因为它是P的Task中最后工作的内容。然而,如果P设定这个特性为“true”,当用户按下HOME并使这个Task再次进入前台时,其上的所有的 Activity(在这里是Q)都将被清除。因此,当返回到这个Task时,用户只能看到P。 如果这个特性和allowTaskReparenting都设定为“true”,那些能重新宿主的Activity会移动到共享affinity的Task中;剩下的Activity都将被抛弃,如上所述。

  • android:configChanges

    当配置list发生修改时, 是否调用 onConfigurationChanged() 方法 比如 “locale|navigation|orientation”. 举例:在按下power键时,直接在应用程序里onPause处理就好。当app是竖屏时,这样处理没问题。但是当app是横屏时,按下power 键,app会强制回到竖屏,并且会重新调用activity的onCreate。很多时候这不是预期结果,所以就会用到 android:configChanges

    在配置文件里设置android:configChanges=”keyboardHidden|orientation”,这样在屏幕方向改变的时候就 不会重新调用activity的onCreate()方法,而是调用onConfigurationChanged(),然后在activity里面重在 下。

  • android:enabled

    activity 是否可以被实例化 用法:<activity android:enabled="true"></activity>

  • android:excludeFromRecents

    是否可被显示在最近打开的activity列表里 用法:<activity android:excludeFromRecents="true"></activity>

  • android:exported

    是否允许activity被其它程序调用

  • android:finishOnTaskLaunch

    用来标记当用户再次启动它的Task(在主画面选择这个Task)时已经存在的Activity实例是否要关闭(结束)——“true”,表示应该关闭,“false”表示不关闭。默认值是“false”。 如果这个特性和allowTaskReparenting都设定为“true”,这个特性胜出。Activity的affinity忽略。这个 Activity不会重新宿主,但是会销毁。

  • android.icon

    用法:<application android:icon="@drawable/xx_icon"></application>,加在应用程序图标

  • android:label

    定义了每个title栏的名称,但是优先级低于activity中的setTitle()

Android应用开发之(优化布局层次结构)

| Comments

有一个常见的错误看法:只使用基础的布局结构会生产高效的布局。然而,每个您程序中的每个控件和布局都需要初始化、布局位置、和绘制。例如使用嵌套的LinearLayout可以导致很多的层次结构。更严重的是,如果在嵌套的LinearLayout中使用layout_weight参数将会导致更加严重的性能问题,因为里面的控件在计算大小的时候会计算两次。如果在ListView 或者 GridView中使用则会更加严重。

这节课程将会介绍如何使用 Heirachy ViewerLayoutopt 工具来检查和优化布局。

检查布局

在 Android SDK 中包含了一个href=“http://developer.android.com/guide/developing/tools/hierarchy-viewer.html”>Heirachy Viewer 工具,使用该工具可以在您的程序运行的时候分析程序的布局。使用该工具来发现布局中的瓶颈所在。

Hierarchy Viewer 让你选择其连接的设备或者模拟器中的一个运行中的程序,然后显示该界面的布局树形结构。在每个控件方块中的交通灯分别代表 计算尺寸(Measure)、布局子控件(Layout)、和绘制的性能,通过颜色来帮助您分析潜在的问题。

例如,下图显示了一个用于 ListView的布局。该布局在左边显示一个小图标,在图标右边显示两行文本内容。当该布局会被多次使用(inflated)到的时候性能问题就比较明显, 比如这个例子 由于这个布局是在ListView中使用的, 所以每个ListView中的一项都会解析下该布局然后绘制出来。

hierarchyviewer 工具位于 /tools/ 目录。打开后 Hierarchy Viewer 将显示一个可用设备的列表和正在运行的界面。点击 Load View Hierarchy 来查看选中的界面的布局分析结果。例如,下图显示了上面定义的ListView中每一项的布局结果。

查看渲染一个View的时间

上面左侧的图中,您可以看到有三层布局结构。在每个方块上面点击可以查看显示该控件所需要的时间。对于需要时间比较长的地方就是我们应该去重点优化的地方。

显示一个列表条目所需要的时间如下:

Measure: 0.977ms

Layout: 0.167ms

Draw: 2.717ms

改进布局

上面的布局被一个嵌套的 LinearLayout 占用了过多的解析时间,如果把布局的嵌套层次降低可能会提高性能.使用 RelativeLayout 可以实现这个功能。使用RelativeLayout后可以看到现在布局由3层变为了2层,分析图如下

使用RelativeLayout后的层次结构

Figure 4. Layout hierarchy for the layout in figure 1, using RelativeLayout.

现在显示一个列表条目所需要的时间如下:

Measure: 0.598ms

Layout: 0.110ms

Draw: 2.146ms

看起来是一个很微弱的提升,但是这个时间可以叠加多次,应为每个列表条目在显示的时候都有解析该布局。

当在LinearLayout 中使用 layout_weight 就又不一样了,这样会增加计算控件大小的时间。在使用layout_weight的时候您应该多考虑考虑。

使用 Layoutopt

在您的最终布局文件中运行下 layoutopt 工具来看看还有没有可以优化的空间是个很好的习惯。 Layoutopt 工具也位于SDK的 tools/ 目录下,您可以用该工具优化单个文件也可以优化一个目录中的所有文件。

当您在单个文件中运行 layoutopt 后,该工具会打印出出现问题的行号和问题的描述,有些问题也会给出优化方案。例如

$ layoutopt samples/
    samples/compound.xml
        7:23 The root-level <FrameLayout/> can be replaced with <merge/>
        11:21 This LinearLayout layout or its FrameLayout parent is useless
    samples/simple.xml
        7:7 The root-level <FrameLayout/> can be replaced with <merge/>

当你修改了布局文件以后,可以再次运行一下 Hierarchy Viewer 来看看具体提升了多少性能。

from Android Developer

PC谢幕曲

| Comments

不久的将来,PC就只有开发人员使用了。

科技周报:
技术发展不断革新,面对竞争的压力和利润的最大化需求,计算机技术的革新需比市场实际需求发展得更快。当PC的成长速度已无法满足人们日益增长的快捷需求,PC独霸江湖的时代便渐渐逝去,随着带宽的扩大、显示设备的革新、云计算以及应用产品的普及,PC的未来将毫无光景。个人电脑将不再统治数码世界,而是会像智能手机与平板电脑一样,成为众多电子设备之一,并随着时间的推移,渐渐销声匿迹。 PC兴衰史 没有服务器、没有本地化处理、网络不发达的时代,人们在相互交流以及信息汲取方面受到重重阻碍,效率以及准确性受到了严峻考验。而二战时期对信息的紧迫需求大大推动了创造的发展,使得资源可以运用于基本的技术试验,促进了计算机的出现。 伴随着计算机在尖端科学技术与工程设计方面的普遍应用,人们对计算机的性能、容量要求不断提高,在计算机行业,按照技术轨道领先一步推出新型技术产品意味着可能提前占有市场。 然而,市场始终是为需求服务的。综观PC发展史,从发展初期至2000年,由于人们的需求刚刚从书本纸张过渡到本地化信息处理,对于快捷处理的需求日益增长,成就了个人电脑的辉煌历史,使得台式计算机成为主导PC市场成败的关键。 而随着互联网的发展,人们对于解决信息处理方面的要求,从传统的台式机逐渐演变到满足交互体验的任意电子产品上,繁杂冗余的大体积台式机毛利润越来越低,陷入了低价化困境。 在巨大压力下,Intel积极开发低耗电处理器,PC市场从原本的台式机时代逐步转移至笔记本电脑时代,而基于云服务的出现,人们对信息加工的需求不再需要经过本地处理,更轻便的过渡产品便成为了引领潮流的先驱,使得笔记本也逃不过低价化的命运,整个PC行业逐渐步入阴霾。 移动终端——过渡产品 所谓过渡产品,既是说包括手机及平板电脑等终端产品,在信息加工方面已经可以逐步代替PC的本地化处理功能,但由于过渡产品仍不能完全满足今后科技对于低成本高效率的信息需求,只是基于其低廉的价格优势以及轻便的体积,成为更多消费者愿意选择的产品。 随着3G网络的大势兴起,3G手机与智能手机的逐步革新,平板电脑不断洗牌,智能终端已经成为当下最潮最热的流行趋势。不难看出,智能操作系统的兴起使得手机退化为终端载体,而生产厂商为了实现差异化竞争,只能在硬件技术上进行提升,降低成本以保证消费者市场。 选择是复杂的,不仅包括技术的先进性,还包括了社会的认同和接受。 对多数消费者来说,轻便装备不但可满足他们上网与玩电子游戏的需求,也是节省时间方便出行的必备工具;而对企业来说,iPad与iPhone等亦足以胜任作简报、工作会议等工作需要;对社会来说,耗能越少越低碳,不但可以节约能源与资源,还能减缩大量废弃电子产品的处理成本。 从企业来看,微软决定让Windows操作系统兼容ARM架构的处理器,也就是说英特尔如今已无法巩固其在PC业的主导地位,ARM在移动芯片的主宰地位更不是英特尔一朝一夕能颠覆的,这预示着长久以来占据市场主导地位的Wintel联盟(Windows+Intel)不再能驱动PC成长。 PC之劫 经济危机带来的影响加速了整个PC行业的利润率下滑,而用户和市场同时决定了计算机技术的发展,在市场判定规则一定的情况下,技术优越者取胜,使得经济之间的竞争转化为技术之间的竞争。随着PC市场的下滑,制造商整合将成为行业更常见的趋势。 2005年IBM将PC业务卖给联想,从PC制造商转型为最大的高端服务提供商,现在看来此举无疑是具有远见卓识的一步。近日,联想整合NEC、收购德国Medion,惠普放出分拆或者出售PC业务的消息,方正集团将PC业务出售给宏公司,戴尔也对外宣称业务中心从PC走向其他领域。众多的产业格局变化都反映了过去以PC为主的厂商想要摆脱走向衰亡的命运。 举例来说,惠普近几年来一直稳坐个人电脑业务头把交椅,在利润率低下已经成为当下整个PC行业不争事实的前提下,惠普做出分拆PC业务的决定,实际上已经等于给这个产业划上了休止符。尽管惠普最终反悔决策表示将继续保留PC业务,但初衷并不是认为PC业务还有未来,只不过因为无法承担分拆成本过高造成的负担。 后PC时代 如今,PC仍旧在市场占有一席之地,因为目前就技术而言,PC在部分层面上占有一定优势。首先,带宽技术的不理想,特别是无线资费的高昂以及带宽的限制,使得需要进行大数量处理的信息技术仍要靠PC来完成。 其次,显示设备的局限性,消费者要享受高质量的视听需求,相比手机与平板电脑,PC仍然是看视频看电影的首选。此外,交互体验的需求也是部分高端玩家选择PC的主要原因之一。 最后,云端建设的不完善,许多存储信息需要靠PC的硬盘完成,而处理器匹配等也是目前尚在开发阶段的问题。 由此看来,今后的计算机技术若是完成了云构架的完善、带宽的革新以及显示设备的提升 ,PC产业必将消亡。到时人们需要的只是一个轻便的操作设备与显示设备,通过云端设备提供强大的运算能力和信息平台,便可完成所有信息处理功能。 就企业而言,随着PC重要性的下降,必会造成数字世界中的权利分配从终端用户和软件开发者向操作系统厂商发生转移。 除了云建设以外,应用程序商店与社交媒体的地位逐步上升,将让原本PC时代以硬件规格定胜负的游戏规则,逐步转为这三项服务与其他阵营之间的差异化大战。这可以推算出与其吊死在PC这一根无利可图的大树上,企业为寻求出路会向操作系统发展。改变组织结构、创立软件与创新服务部门,或者以快速并购方式弥补营运缺点等,都是各企业目前在寻觅的生存规则。 后PC时代的到来伴随着业务的整合、应用的拓展以及云端设备提供的强大运算能力和信息平台,那个单纯靠硬件打拼的时代已不复存在。如同恩格尔·巴特所说,今后的计算机技术将建立在共享信息的基础上,这也是科学技术进步的关键,因为基于新平台的信息交互可以使创造活动的时效性与质量得到有效提高,满足信息时代的处理要求。 综上所述,PC会经历一个慢慢消亡的过程,从主导市场变为与智能终端产品并列而存,随着云建设的崛起以及目前已经着手改良的带宽与网络资费问题,PC将在不久的未来逐步退出历史舞台。