咖啡伴侣

呆在上海
posts - 163, comments - 156, trackbacks - 0, articles - 2


在android中context可以作很多操作,但是最主要的功能是加载和访问资源。在android中有两种context,
一种是 application context,一种是activity context,通常我们在各种类和方法间传递的是activity context。
比如一个activity的onCreate:
protected void onCreate(Bundle state) {
        super.onCreate(state);

        TextView label = new TextView(this); //传递context给view control
        label.setText("Leaks are bad");

        setContentView(label);
}
把activity context传递给view,意味着view拥有一个指向activity的引用,进而引用activity占有的资源:view hierachy, resource等。
这样如果context发生内存泄露的话,就会泄露很多内存。
这里泄露的意思是gc没有办法回收activity的内存。

Leaking an entire activity是很容易的一件事。

当屏幕旋转的时候,系统会销毁当前的activity,保存状态信息,再创建一个新的。

比如我们写了一个应用程序,它需要加载一个很大的图片,我们不希望每次旋转屏 幕的时候都销毁这个图片,重新加载。
实现这个要求的简单想法就是定义一个静态的Drawable,这样Activity 类创建销毁它始终保存在内存中。
实现类似:
public class myactivity extends Activity {
        private static Drawable sBackground;
        protected void onCreate(Bundle state) {
                super.onCreate(state);

                TextView label = new TextView(this);
                label.setText("Leaks are bad");

                if (sBackground == null) {
                        sBackground = getDrawable(R.drawable.large_bitmap);
                }
        label.setBackgroundDrawable(sBackground);//drawable attached to a view

        setContentView(label);
        }
}
这段程序看起来很简单,但是却问题很大。当屏幕旋转的时候会有leak(即gc没法销毁activity)。
我们刚才说过,屏幕旋转的时候系统会销毁当前的activity。但是当drawable和view关联后,drawable保存了view的 reference,即sBackground保存了label的引用,
而label保存了activity的引用。既然drawable不能销毁,它所 引用和间接引用的都不能销毁,这样系统就没有办法销毁当前的activity,于是造成了内存泄露。
gc对这种类型的内存泄露是无能为力的。

避免这种内存泄露的方法是避免activity中的任何对象的生命周期长过activity,避免由于对象对 activity的引用导致activity不能正常被销毁。
我们可以使用application context。application context伴随application的一生,与activity的生命周期无关。
application context可以通过Context.getApplicationContext或者Activity.getApplication方法获取。

避免context相关的内存泄露,记住以下几点:
1. 不要让生命周期长的对象引用activity context,即保证引用activity的对象要与activity本身生命周期是一样的
2. 对于生命周期长的对象,可以使用application context
3. 避免非静态的内部类,尽量使用静态类,避免生命周期问题,注意内部类对外部对象引用导致的生命周期变化

posted @ 2011-07-21 14:57 oathleo 阅读(692) | 评论 (0)编辑 收藏

http://blog.csdn.net/hellogv/article/details/5986835
  上一篇简 单介绍了SurfaceView的基本使用,这次就介绍SurfaceView与多线程的混搭。SurfaceView与多线程混搭,是为了防止动画闪烁 而实现的一种多线程应用。android的多线程用法与JAVA的多线程用法完全一样,本文不做多线程方面的介绍了。直接讲解SurfaceView与多 线程的混合使用,即开一条线程专门读取图片,另外一条线程专门绘图。

        本文程序运行截图如下,左边是开单个线程读取并绘图,右边是开两个线程,一个专门读取图片,一个专门绘图:

对 比一下,右边动画的帧速明显比左边的快,左右两者都没使用Thread.sleep()。为什么要开两个线程一个读一个画,而不去开两个线程像左边那样都 “边读边画”呢?因为SurfaceView每次绘图都会锁定Canvas,也就是说同一片区域这次没画完下次就不能画,因此要提高动画播放的效率,就得开一条线程专门画图,开另外一条线程做预处理的工作。

main.xml的源码:

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent" android:layout_height="fill_parent"  
  4.     android:orientation="vertical">  
  5.   
  6.     <LinearLayout android:id="@+id/LinearLayout01"  
  7.         android:layout_width="wrap_content" android:layout_height="wrap_content">  
  8.         <Button android:id="@+id/Button01" android:layout_width="wrap_content"  
  9.             android:layout_height="wrap_content" android:text="单个独立线程"></Button>  
  10.         <Button android:id="@+id/Button02" android:layout_width="wrap_content"  
  11.             android:layout_height="wrap_content" android:text="两个独立线程"></Button>  
  12.     </LinearLayout>  
  13.     <SurfaceView android:id="@+id/SurfaceView01"  
  14.         android:layout_width="fill_parent" android:layout_height="fill_parent"></SurfaceView>  
  15. </LinearLayout>  

本文程序的源码:

 

  1. package com.testSurfaceView;  
  2.   
  3. import java.lang.reflect.Field;  
  4. import java.util.ArrayList;  
  5. import android.app.Activity;  
  6. import android.graphics.Bitmap;  
  7. import android.graphics.BitmapFactory;  
  8. import android.graphics.Canvas;  
  9. import android.graphics.Paint;  
  10. import android.graphics.Rect;  
  11. import android.os.Bundle;  
  12. import android.util.Log;  
  13. import android.view.SurfaceHolder;  
  14. import android.view.SurfaceView;  
  15. import android.view.View;  
  16. import android.widget.Button;  
  17.   
  18. public class testSurfaceView extends Activity {  
  19.     /** Called when the activity is first created. */  
  20.     Button btnSingleThread, btnDoubleThread;  
  21.     SurfaceView sfv;  
  22.     SurfaceHolder sfh;  
  23.     ArrayList<Integer> imgList = new ArrayList<Integer>();  
  24.     int imgWidth, imgHeight;  
  25.     Bitmap bitmap;//独立线程读取,独立线程绘图  
  26.   
  27.     @Override  
  28.     public void onCreate(Bundle savedInstanceState) {  
  29.         super.onCreate(savedInstanceState);  
  30.         setContentView(R.layout.main);  
  31.   
  32.         btnSingleThread = (Button) this.findViewById(R.id.Button01);  
  33.         btnDoubleThread = (Button) this.findViewById(R.id.Button02);  
  34.         btnSingleThread.setOnClickListener(new ClickEvent());  
  35.         btnDoubleThread.setOnClickListener(new ClickEvent());  
  36.         sfv = (SurfaceView) this.findViewById(R.id.SurfaceView01);  
  37.         sfh = sfv.getHolder();  
  38.         sfh.addCallback(new MyCallBack());// 自动运行surfaceCreated以及surfaceChanged  
  39.     }  
  40.   
  41.     class ClickEvent implements View.OnClickListener {  
  42.   
  43.         @Override  
  44.         public void onClick(View v) {  
  45.   
  46.             if (v == btnSingleThread) {  
  47.                 new Load_DrawImage(0, 0).start();//开一条线程读取并绘图  
  48.             } else if (v == btnDoubleThread) {  
  49.                 new LoadImage().start();//开一条线程读取  
  50.                 new DrawImage(imgWidth + 10, 0).start();//开一条线程绘图  
  51.             }  
  52.   
  53.         }  
  54.   
  55.     }  
  56.   
  57.     class MyCallBack implements SurfaceHolder.Callback {  
  58.   
  59.         @Override  
  60.         public void surfaceChanged(SurfaceHolder holder, int format, int width,  
  61.                 int height) {  
  62.             Log.i("Surface:", "Change");  
  63.   
  64.         }  
  65.   
  66.         @Override  
  67.         public void surfaceCreated(SurfaceHolder holder) {  
  68.             Log.i("Surface:", "Create");  
  69.   
  70.             // 用反射机制来获取资源中的图片ID和尺寸  
  71.             Field[] fields = R.drawable.class.getDeclaredFields();  
  72.             for (Field field : fields) {  
  73.                 if (!"icon".equals(field.getName()))// 除了icon之外的图片  
  74.                 {  
  75.                     int index = 0;  
  76.                     try {  
  77.                         index = field.getInt(R.drawable.class);  
  78.                     } catch (IllegalArgumentException e) {  
  79.                         // TODO Auto-generated catch block  
  80.                         e.printStackTrace();  
  81.                     } catch (IllegalAccessException e) {  
  82.                         // TODO Auto-generated catch block  
  83.                         e.printStackTrace();  
  84.                     }  
  85.                     // 保存图片ID  
  86.                     imgList.add(index);  
  87.                 }  
  88.             }  
  89.             // 取得图像大小  
  90.             Bitmap bmImg = BitmapFactory.decodeResource(getResources(),  
  91.                     imgList.get(0));  
  92.             imgWidth = bmImg.getWidth();  
  93.             imgHeight = bmImg.getHeight();  
  94.         }  
  95.   
  96.         @Override  
  97.         public void surfaceDestroyed(SurfaceHolder holder) {  
  98.             Log.i("Surface:", "Destroy");  
  99.   
  100.         }  
  101.   
  102.     }  
  103.   
  104.     /* 
  105.      * 读取并显示图片的线程 
  106.      */  
  107.     class Load_DrawImage extends Thread {  
  108.         int x, y;  
  109.         int imgIndex = 0;  
  110.   
  111.         public Load_DrawImage(int x, int y) {  
  112.             this.x = x;  
  113.             this.y = y;  
  114.         }  
  115.   
  116.         public void run() {  
  117.             while (true) {  
  118.                 Canvas c = sfh.lockCanvas(new Rect(this.x, this.y, this.x  
  119.                         + imgWidth, this.y + imgHeight));  
  120.                 Bitmap bmImg = BitmapFactory.decodeResource(getResources(),  
  121.                         imgList.get(imgIndex));  
  122.                 c.drawBitmap(bmImg, this.x, this.y, new Paint());  
  123.                 imgIndex++;  
  124.                 if (imgIndex == imgList.size())  
  125.                     imgIndex = 0;  
  126.   
  127.                 sfh.unlockCanvasAndPost(c);// 更新屏幕显示内容  
  128.             }  
  129.         }  
  130.     };  
  131.   
  132.     /* 
  133.      * 只负责绘图的线程 
  134.      */  
  135.     class DrawImage extends Thread {  
  136.         int x, y;  
  137.   
  138.         public DrawImage(int x, int y) {  
  139.             this.x = x;  
  140.             this.y = y;  
  141.         }  
  142.   
  143.         public void run() {  
  144.             while (true) {  
  145.                 if (bitmap != null) {//如果图像有效  
  146.                     Canvas c = sfh.lockCanvas(new Rect(this.x, this.y, this.x  
  147.                             + imgWidth, this.y + imgHeight));  
  148.   
  149.                     c.drawBitmap(bitmap, this.x, this.y, new Paint());  
  150.   
  151.                     sfh.unlockCanvasAndPost(c);// 更新屏幕显示内容  
  152.                 }  
  153.             }  
  154.         }  
  155.     };  
  156.   
  157.     /* 
  158.      * 只负责读取图片的线程 
  159.      */  
  160.     class LoadImage extends Thread {  
  161.         int imgIndex = 0;  
  162.   
  163.         public void run() {  
  164.             while (true) {  
  165.                 bitmap = BitmapFactory.decodeResource(getResources(),  
  166.                         imgList.get(imgIndex));  
  167.                 imgIndex++;  
  168.                 if (imgIndex == imgList.size())//如果到尽头则重新读取  
  169.                     imgIndex = 0;  
  170.             }  
  171.         }  
  172.     };  
  173. }  


posted @ 2011-07-21 10:11 oathleo 阅读(445) | 评论 (0)编辑 收藏

Android提高第五篇之Service

分类: Android提高 2010-11-08 11:48 5360人阅读 评论(11) 收藏 举报

本文来自http://blog.csdn.net/hellogv/ ,引用必须注明出处!

        上次介绍了Activity以及Intent的使用, 这次就介绍Service,如果把Activity比喻为前台程序,那么Service就是后台程序,Service的整个生命周期都只会在后台执行。 Service跟Activity一样也由Intent调用。在工程里想要添加一个Service,先新建继承Service的类,然后到 AndroidManifest.xml -> Application ->Application Nodes中的Service标签中添加。

         Service要由Activity通过startService 或者 bindService来启动,Intent负责传递参数。先贴出本文程序运行截图:

 

本文主要讲解Service的调用,以及其生命周期。

上图是startService之后再stopService的Service状态变化。

上图是bindService之后再unbindService的Service状态变化。

       startService与bindService都可以启动Service,那么它们之间有什么区别呢?它们两者的区别就是使Service的周期改变。由 startService启动的Service必须要有stopService来结束Service,不调用stopService则会造成 Activity结束了而Service还运行着。bindService启动的Service可以由unbindService来结束,也可以在 Activity结束之后(onDestroy)自动结束。

 上图是startService之后再Activity.finish()的Service状态变化,Service还在跑着。

上图是bindService之后再Activity.finish()的Service状态变化,Service最后自动unbindService。

main.xml代码:

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical" android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent">  
  5.     <Button android:layout_width="wrap_content"  
  6.         android:layout_height="wrap_content" android:id="@+id/btnStartMyService"  
  7.         android:text="StartMyService"></Button>  
  8.     <Button android:layout_width="wrap_content"  
  9.         android:layout_height="wrap_content" android:id="@+id/btnStopMyService"  
  10.         android:text="StopMyService"></Button>  
  11.     <Button android:layout_width="wrap_content"  
  12.         android:layout_height="wrap_content" android:id="@+id/btnBindMyService"  
  13.         android:text="BindMyService"></Button>  
  14.     <Button android:layout_width="wrap_content"  
  15.         android:layout_height="wrap_content" android:id="@+id/btnUnbindMyService"  
  16.         android:text="UnbindMyService"></Button>  
  17.     <Button android:layout_width="wrap_content"  
  18.         android:layout_height="wrap_content" android:id="@+id/btnExit"  
  19.         android:text="退出程序"></Button>  
  20. </LinearLayout>  

testService.java的源码:

  1. package com.testService;  
  2.   
  3. import android.app.Activity;  
  4. import android.app.Service;  
  5. import android.content.ComponentName;  
  6. import android.content.Intent;  
  7. import android.content.ServiceConnection;  
  8. import android.os.Bundle;  
  9. import android.os.IBinder;  
  10. import android.util.Log;  
  11. import android.view.View;  
  12. import android.widget.Button;  
  13.   
  14. public class testService extends Activity {  
  15.     Button btnStartMyService,btnStopMyService,btnBindMyService,btnUnbindMyService,btnExit;  
  16.     @Override  
  17.     public void onCreate(Bundle savedInstanceState) {  
  18.         super.onCreate(savedInstanceState);  
  19.         setContentView(R.layout.main);  
  20.         btnStartMyService=(Button)this.findViewById(R.id.btnStartMyService);  
  21.         btnStartMyService.setOnClickListener(new ClickEvent());  
  22.           
  23.         btnStopMyService=(Button)this.findViewById(R.id.btnStopMyService);  
  24.         btnStopMyService.setOnClickListener(new ClickEvent());  
  25.           
  26.         btnBindMyService=(Button)this.findViewById(R.id.btnBindMyService);  
  27.         btnBindMyService.setOnClickListener(new ClickEvent());  
  28.           
  29.         btnUnbindMyService=(Button)this.findViewById(R.id.btnUnbindMyService);  
  30.         btnUnbindMyService.setOnClickListener(new ClickEvent());   
  31.           
  32.         btnExit=(Button)this.findViewById(R.id.btnExit);  
  33.         btnExit.setOnClickListener(new ClickEvent());  
  34.     }  
  35.     @Override  
  36.     public void onDestroy()  
  37.     {  
  38.         super.onDestroy();  
  39.         Log.e("Activity","onDestroy");  
  40.     }  
  41.       
  42.     private ServiceConnection _connection = new ServiceConnection() {    
  43.         @Override  
  44.         public void onServiceConnected(ComponentName arg0, IBinder arg1) {  
  45.             // TODO Auto-generated method stub  
  46.         }  
  47.   
  48.         @Override  
  49.         public void onServiceDisconnected(ComponentName name) {  
  50.             // TODO Auto-generated method stub  
  51.         }    
  52.     };    
  53.     class ClickEvent implements View.OnClickListener{  
  54.   
  55.         @Override  
  56.         public void onClick(View v) {  
  57.             Intent intent=new Intent(testService.this,MyService.class);  
  58.             if(v==btnStartMyService){  
  59.                 testService.this.startService(intent);  
  60.             }  
  61.             else if(v==btnStopMyService){  
  62.                 testService.this.stopService(intent);  
  63.             }  
  64.             else if(v==btnBindMyService){  
  65.                 testService.this.bindService(intent, _connection, Service.BIND_AUTO_CREATE);  
  66.             }  
  67.             else if(v==btnUnbindMyService){  
  68.                 if(MyService.ServiceState=="onBind")//Service绑定了之后才能解绑  
  69.                     testService.this.unbindService(_connection);  
  70.             }  
  71.             else if(v==btnExit)  
  72.             {  
  73.                 testService.this.finish();  
  74.             }  
  75.               
  76.         }  
  77.           
  78.     }  
  79. }  

MyService.java的源码:

  1. package com.testService;  
  2.   
  3. import android.app.Service;  
  4. import android.content.Intent;  
  5. import android.os.IBinder;  
  6. import android.util.Log;  
  7.   
  8. public class MyService extends Service {  
  9.     static public String ServiceState="";  
  10.     @Override  
  11.     public IBinder onBind(Intent arg0) {  
  12.         Log.e("Service", "onBind");  
  13.         ServiceState="onBind";  
  14.         return null;  
  15.     }  
  16.     @Override  
  17.     public boolean onUnbind(Intent intent){  
  18.         super.onUnbind(intent);  
  19.         Log.e("Service", "onUnbind");  
  20.         ServiceState="onUnbind";  
  21.         return false;  
  22.           
  23.     }  
  24.     @Override  
  25.     public void onCreate(){  
  26.         super.onCreate();  
  27.         Log.e("Service", "onCreate");  
  28.         ServiceState="onCreate";  
  29.     }  
  30.     @Override  
  31.     public void onDestroy(){  
  32.         super.onDestroy();  
  33.         Log.e("Service", "onDestroy");  
  34.         ServiceState="onDestroy";  
  35.     }  
  36.     @Override  
  37.     public void onStart(Intent intent,int startid){  
  38.         super.onStart(intent, startid);  
  39.         Log.e("Service", "onStart");  
  40.         ServiceState="onStart";  
  41.     }  
  42.   
  43. }  


posted @ 2011-07-21 10:10 oathleo 阅读(195) | 评论 (0)编辑 收藏

Android入门第十六篇之Style与Theme

分类: Android入门 2011-01-11 11:16 10361人阅读 评论(28) 收藏 举报

 本文来自http://blog.csdn.net/hellogv/ ,引用必须注明出处!

       越来越多互联网企业都在Android平台上部署其客户端,为了提升用户体验,这些客户端都做得布局合理而且美观.......Android的Style设计就是提升用户体验的关键之一。Android上的Style分为了两个方面:

  1. Theme是针对窗体级别的,改变窗体样式;
  2. Style是针对窗体元素级别的,改变指定控件或者Layout的样式。

Android 系统的themes.xml和style.xml(位于/base/core/res/res/values/)包含了很多系统定义好的style,建议 在里面挑个合适的,然后再继承修改。以下属性是在Themes中比较常见的,源自Android系统本身的themes.xml:

  1. <!-- Window attributes -->  
  2. <item name="windowBackground">@android:drawable/screen_background_dark</item>  
  3. <item name="windowFrame">@null</item>  
  4. <item name="windowNoTitle">false</item>  
  5. <item name="windowFullscreen">false</item>  
  6. <item name="windowIsFloating">false</item>  
  7. <item name="windowContentOverlay">@android:drawable/title_bar_shadow</item>  
  8. <item name="windowTitleStyle">@android:style/WindowTitle</item>  
  9. <item name="windowTitleSize">25dip</item>  
  10. <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground</item>  
  11. <item name="android:windowAnimationStyle">@android:style/Animation.Activity</item>  

至于控件的Style设计就范围大多了,看看Eclipse的Android控件属性编辑器[Properties]就大概知道有哪些条目, 而Android内置的style.xml也只是定义每个控件的默认样式而已....不过控件的style不建议大改,耐看的style更能让用户长时间 使用软件。另外,控件的Style在很多情况下都用到9.png,学习9.png就必须到/base/core/res/res/drawable- hdpi里面看看,里面有很多系统内置的9.png。

PS:为了研究Android的Style和Theme,强烈建议下载Android的base.git!

接下来看看本文程序的效果图:

本文程序的themes.xml代码如下,自定义了WindowTitle,:

 

<?xml version="1.0" encoding="UTF-8"?>
<resources>
 <!--继承Android内置的Theme.Light,位于/base/core/res/res/values/themes.xml -->
 <style name="Theme" parent="android:Theme.Light">
  <item name="android:windowFullscreen">true</item>
  <item name="android:windowTitleSize">60dip</item>
  <item name="android:windowTitleStyle">@style/WindowTitle</item>
 </style>

 <style name="WindowTitle" parent="android:WindowTitle">
  <item name="android:singleLine">true</item>
  <item name="android:shadowColor">#BB000000</item>
  <item name="android:shadowRadius">2.75</item>
 </style>
</resources>

 

 

要为Activity使用theme,要么使用代码 setTheme(R.style.Theme),要么在Application Manifest里面设置

本文程序的styles.xml代码如下,background默认使用的是9.png,xml定义在/base/core/res/res/drawable/之下:

 

 

<?xml version="1.0" encoding="UTF-8"?>
<resources>
 <style name="TextView">
  <item name="android:textSize">18sp</item>
  <item name="android:textColor">#008</item>
  <item name="android:shadowColor">@android:color/black</item>
  <item name="android:shadowRadius">2.0</item>
 </style>

 <style name="EditText">
  <item name="android:shadowColor">@android:color/black</item>
  <item name="android:shadowRadius">1.0</item>
  <item name="android:background">@android:drawable/btn_default</item>
  <item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
 </style>

    <style name="Button">
        <item name="android:background">@android:drawable/edit_text</item>
        <item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
    </style>
</resources>

 

main.xml代码如下:

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical" android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent">  
  5.     <TextView android:layout_width="fill_parent"  
  6.         android:layout_height="wrap_content" android:text="@string/hello"  
  7.         style="@style/TextView" />  
  8.     <EditText android:id="@+id/EditText01" android:layout_height="wrap_content"  
  9.         style="@style/EditText" android:layout_width="fill_parent"  
  10.         android:text="类似Button的EditText"></EditText>  
  11.     <EditText android:id="@+id/EditText02" android:layout_height="wrap_content"  
  12.         android:layout_width="fill_parent" android:text="普通的EditText"></EditText>  
  13.     <Button android:id="@+id/Button01" android:layout_height="wrap_content"  
  14.         style="@style/Button" android:layout_width="fill_parent" android:text="类似EditText的Button"></Button>  
  15. </LinearLayout>  


posted @ 2011-07-21 10:04 oathleo 阅读(290) | 评论 (0)编辑 收藏

android中使用2D动画 — SurfaceView

 

通过之前介绍的如何自定义View, 我们知道使用它可以做一些简单的动画效果。它通过不断循环的执行View.onDraw方法,每次执行都对内部显示的图形做一些调整,我们假设 onDraw方法每秒执行20次,这样就会形成一个20帧的补间动画效果。但是现实情况是你无法简单的控制View.onDraw的执行帧数,这边说的执 行帧数是指每秒View.onDraw方法被执行多少次,这是为什么呢?首先我们知道,onDraw方法是由系统帮我们调用的,我们是通过调用View的 invalidate方法通知系统需要重新绘制View,然后它就会调用View.onDraw方法。这些都是由系统帮我们实现的,所以我们很难精确去定 义View.onDraw的执行帧数,这个就是为什么我们这边要了解SurfaceView了,它能弥补View的一些不足。

首先我们先写一个自定义View实现动画效果,AnimateViewActivity.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.android777.demo.uicontroller.graphics;
 
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.View;
 
public class AnimateViewActivity extends Activity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        setContentView(new AnimateView(this));
    }
 
    class AnimateView extends View{
 
        float radius = 10;
        Paint paint;
 
        public AnimateView(Context context) {
            super(context);
            paint = new Paint();
            paint.setColor(Color.YELLOW);
            paint.setStyle(Paint.Style.STROKE);
        }
 
        @Override
        protected void onDraw(Canvas canvas) {
 
            canvas.translate(200, 200);
            canvas.drawCircle(0, 0, radius++, paint);          
 
            if(radius > 100){
                radius = 10;
            }
 
            invalidate();//通过调用这个方法让系统自动刷新视图
 
        }
 
    }
 
}

运行上面的Activity,你将看到一个圆圈,它原始半径是10,然后不断的变大,直到达到100后又恢复到10,这样循环显示,视觉效果上说你将看到一个逐渐变大的圆圈。

上面就是一个简单的自定义View实现的动画效果,它能做的只是简单的动画效果,具有一些局限性。首先你无法控制动画的显示速度,目前它是以最快的 速度显示,但是当你要更快,获取帧数更高的动画呢? 因为View的帧数是由系统控制的,所以你没办法完成上面的操作。如果你需要编写一个游戏,它需要的帧数比较高,那么View就无能为力了,因为它被设计 出来时本来就不是用来处理一些高帧数显示的。你可以把View理解为一个经过系统优化的,可以用来高效的执行一些帧数比较低动画的对象,它具有特定的使用 场景,比如有一些帧数较低的游戏就可以使用它来完成:贪吃蛇、俄罗斯方块、棋牌类等游戏,因为这些游戏执行的帧数都很低。但是如果是一些实时类的游戏,如 射击游戏、塔防游戏、RPG游戏等就没办法使用View来做,因为它的帧数太低了,会导致动画执行不顺畅。所以我们需要一个能自己控制执行帧数的对 象,SurfaceView因此诞生了。

什么是SurfaceView呢?

为什么是SurfaceView呢?Surface的意思是表层,表面的意思,那么SurfaceView就是指一个在表层的View对象。为什么 说是在表层呢,这是因为它有点特殊跟其他View不一样,其他View是绘制在表层外,而它就是充当表层对象。假设你要在一个球上画画,那么球的表层就当 做你的画布对象,你画的东西会挡住它的表层,我们默认没使用SurfaceView,那么球的表层就是空白的,如果我们使用了SurfaceView,我 们可以理解为我们拿来的球本身表面就具有纹路,你是画再纹路之上的,如果你画的是半透明的,那么你将可以透过你画的东西看到球面本身的纹路。SDK的文档 说到:SurfaceView就是在Window上挖一个洞,它就是显示在这个洞里,其他的View是显示在Window上,所以View可以显式在 SurfaceView之上,你也可以添加一些层在SurfaceView之上。

SurfaceView还有其他的特性,上面我们讲了它可以控制帧数,那它是什么控制的呢?这就需要了解它的使用机制。一般在很多游戏设计中,我们都是开辟一个后台线程计算游戏相关的数据,然后根据这些计算完的新数据再刷新视图对象,由于对View执行绘制操作只能在UI线程上, 所以当你在另外一个线程计算完数据后,你需要调用View.invalidate方法通知系统刷新View对象,所以游戏相关的数据也需要让UI线程能访 问到,这样的设计架构比较复杂,要是能让后台计算的线程能直接访问数据,然后更新View对象那改多好。我们知道View的更新只能在UI线程中,所以使 用自定义View没办法这么做,但是SurfaceView就可以了。它一个很好用的地方就是允许其他线程(不是UI线程)绘制图形(使用Canvas),根据它这个特性,你就可以控制它的帧数,你如果让这个线程1秒执行50次绘制,那么最后显示的就是50帧。

 

如何使用SurfaceView?

首先SurfaceView也是一个View,它也有自己的生命周期。因为它需要另外一个线程来执行绘制操作,所以我们可以在它生命周期的初始化阶 段开辟一个新线程,然后开始执行绘制,当生命周期的结束阶段我们插入结束绘制线程的操作。这些是由其内部一个SurfaceHolder对象完成的。 SurfaceHolder,顾名思义,它里面保存了一个队Surface对象的引用,而我们执行绘制方法就是操作这个 Surface,SurfaceHolder因为保存了对Surface的引用,所以使用它来处理Surface的生命周期,说到底 SurfaceView的生命周期其实就是Surface的生命周期,因为SurfaceHolder保存对Surface的引用,所以使用 SurfaceHolder来处理生命周期的初始化。首先我们先看看建立一个SurfaceView的大概步骤,先看看代码:

DemoSurfaceView.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.android777.demo.uicontroller.graphics;
 
import android.content.Context;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
 
public class DemoSurfaceView extends SurfaceView  implements Callback{
 
    public DemoSurfaceView(Context context) {
        super(context);
 
        init(); //初始化,设置生命周期回调方法
 
    }
 
    private void init(){
 
        SurfaceHolder holder = getHolder();
        holder.addCallback(this); //设置Surface生命周期回调
 
    }
 
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
    }
 
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    }
 
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    }
 
}

上面代码我们在SurfaceView的构造方法中执行了init初始化方法,在这个方法里,我们先获取SurfaceView里的 SurfaceHolder对象,然后通过它设置Surface的生命周期回调方法,使用DemoSurfaceView类本身作为回调方法代理类。 surfaceCreated方法,是当SurfaceView被显示时会调用的方法,所以你需要再这边开启绘制的线 程,surfaceDestroyed方法是当SurfaceView被隐藏会销毁时调用的方法,在这里你可以关闭绘制的线程。上面的例子运行后什么也不 显示,因为还没定义一个执行绘制的线程。下面我们修改下代码,使用一个线程绘制一个逐渐变大的圆圈:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package com.android777.demo.uicontroller.graphics;
 
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
 
public class DemoSurfaceView extends SurfaceView  implements Callback{
 
    LoopThread thread;
 
    public DemoSurfaceView(Context context) {
        super(context);
 
        init(); //初始化,设置生命周期回调方法
 
    }
 
    private void init(){
 
        SurfaceHolder holder = getHolder();
        holder.addCallback(this); //设置Surface生命周期回调
        thread = new LoopThread(holder, getContext());
    }
 
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
    }
 
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        thread.isRunning = true;
        thread.start();
    }
 
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        thread.isRunning = false;
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 执行绘制的绘制线程
     * @author Administrator
     *
     */
    class LoopThread extends Thread{
 
        SurfaceHolder surfaceHolder;
        Context context;
        boolean isRunning;
        float radius = 10f;
        Paint paint;
 
        public LoopThread(SurfaceHolder surfaceHolder,Context context){
 
            this.surfaceHolder = surfaceHolder;
            this.context = context;
            isRunning = false;
 
            paint = new Paint();
            paint.setColor(Color.YELLOW);
            paint.setStyle(Paint.Style.STROKE);
        }
 
        @Override
        public void run() {
 
            Canvas c = null;
 
            while(isRunning){
 
                try{
                    synchronized (surfaceHolder) {
 
                        c = surfaceHolder.lockCanvas(null);
                        doDraw(c);
                        //通过它来控制帧数执行一次绘制后休息50ms
                        Thread.sleep(50);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    surfaceHolder.unlockCanvasAndPost(c);
                }
 
            }
 
        }
 
        public void doDraw(Canvas c){
 
            //这个很重要,清屏操作,清楚掉上次绘制的残留图像
            c.drawColor(Color.BLACK);
 
            c.translate(200, 200);
            c.drawCircle(0,0, radius++, paint);
 
            if(radius > 100){
                radius = 10f;
            }
 
        }
 
    }
 
}

上面代码编写了一个使用SurfaceView制作的动画效果,它的效果跟上面自定义View的一样,但是这边的SurfaceView可以控制动 画的帧数。在SurfaceView中内置一个LoopThread线程,这个线程的作用就是用来绘制图形,在SurfaceView中实例化一个 LoopThread实例,一般这个操作会放在SurfaceView的构造方法中。然后通过在SurfaceView中的SurfaceHolder的 生命周期回调方法中插入一些操作,当Surface被创建时(SurfaceView显示在屏幕中时),开启LoopThread执行绘 制,LoopThread会一直刷新SurfaceView对象,当SurfaceView被隐藏时就停止改线程释放资源。这边有几个地方要注意下:

1.因为SurfaceView允许自定义的线程操作Surface对象执行绘制方法,而你可能同时定义多个线程执行绘制,所以当你获取 SurfaceHolder中的Canvas对象时记得加同步操作,避免两个不同的线程同时操作同一个Canvas对象,当操作完成后记得调用 SurfaceHolder.unlockCanvasAndPost方法释放掉Canvas锁。

2.在调用doDraw执行绘制时,因为SurfaceView的特点,它会保留之前绘制的图形,所以你需要先清空掉上一次绘制时留下的图形。(View则不会,它默认在调用View.onDraw方法时就自动清空掉视图里的东西)。

3. 记得在回调方法:onSurfaceDestroyed方法里将后台执行绘制的LoopThread关闭,这里是使用join方法。这涉及到线程如何关闭 的问题,多数人建议是通过一个标志位:isRunning来判断线程是否该停止运行,如果你想关闭线程只需要将isRunning改成false即可,线 程会自动执行完run方法后退出。

 

总结:

通过上面的分析,现在大家应该会简单使用SurfaceView了,总的归纳起来SurfaceView和View不同之处有:

1. SurfaceView允许其他线程更新视图对象(执行绘制方法)而View不允许这么做,它只允许UI线程更新视图对象。

2. SurfaceView是放在其他最底层的视图层次中,所有其他视图层都在它上面,所以在它之上可以添加一些层,而且它不能是透明的。

3. 它执行动画的效率比View高,而且你可以控制帧数。

4. 因为它的定义和使用比View复杂,占用的资源也比较多,除非使用View不能完成,再用SurfaceView否则最好用View就可以。(贪吃蛇,俄罗斯方块,棋牌类这种帧数比较低的可以使用View做就好)

posted @ 2011-07-21 09:45 oathleo 阅读(2919) | 评论 (0)编辑 收藏

Android surfaceView 与View 的区别  

如果你的游戏不吃CPU,用View就比较好,符合标准Android操作方式,由系统决定刷新surface的时机。

  但如果很不幸的,你做不到不让你的程序吃CPU,你就只好使用SurfaceView来强制刷新surface了,不然系统的UI进程很可能抢不过你那些吃CPU的线程。

  当然其实不止这两种方法来刷新Surface的,这两种只是纯Java应用比较常见的方法。

  SurfaceView和View最本质的区别在于,surfaceView是在一个新起的单独线程中可以重新绘制画面而View必须在UI的主线程中更新画面。

  那么在UI的主线程中更新画面 可能会引发问题,比如你更新画面的时间过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应按键,触屏等消息。

   当使用surfaceView 由于是在新的线程中更新画面所以不会阻塞你的UI主线程。但这也带来了另外一个问题,就是事件同步。比如你触屏了一下,你需要surfaceView中 thread处理,一般就需要有一个event queue的设计来保存touch event,这会稍稍复杂一点,因为涉及到线程同步。

  所以基于以上,根据游戏特点,一般分成两类。

  1 被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 因为这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。

  2 主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main UI thread。所以显然view不合适,需要surfaceView来控制。

posted @ 2011-07-21 09:36 oathleo 阅读(288) | 评论 (0)编辑 收藏

Android 1.5 API变更概要:
UI framework
· Framework for easier background/UI thread interaction
· 新SlidingDrawer 组件
· 新HorizontalScrollview 组件
AppWidget framework
· 一些关于创建桌面AppWidget 的API.
· 提供根据自定义的内容创建LiveFolders的API
Media framework
· 原声录音和回放 APIs
· 交互式的MIDI 回放引擎
· 开发者使用的视频录像API (3GP format).
· 视频相片分享 Intents
· 媒体搜索Intent
Input Method framework
· 输入法服务framework
· 文本预测引擎
· 提供具有下载能力的IME给使用者
Android软键盘的隐藏显示研究:
http://winuxxan.blog.51cto.com/2779763/522810
android软键盘出来的时候覆盖底部的tab导航:
http://www.eoeandroid.com/thread-67098-1-1.html
android 软键盘Enter键图标的设置:
http://archive.cnblogs.com/a/1994418/
Application-defined hardware requirements
应用可定义硬件需求,应用程序可以定义  说明此程序需要什么硬件需求.比如是否需要物理键盘或者轨迹球.
Speech recognition framework
· 支持语音识别库.
Miscellaneous API additions
· LocationManager -应用可以接收到位置改变的信息.
· WebView - 触摸start/end/move/cancel   DOM 事件的支持
· 重建Sensor Manager APIs
· GLSurfaceView - 创建OpenGL 应用更加方便的framework .
· 软件升级安装成功的Broadcast Intent - 更加平和优秀的软件升级体验

Android 1.6 API变更概要:
UI framework
· 新的类 android.view.animation 控制动画行为:
o AnticipateInterpolator
o AnticipateOvershootInterpolator
o BounceInterpolator
o OvershootInterpolator
· 新的XML 属性android:onClick ,从一个layout文件描述一个view的 View.OnClickListener.
· 对不同分辨率的屏幕的新的支持. 对于Bitmap和Canvas会执行有针对性的缩放行为.该框架会根据屏幕分辨率和其他内容自动缩放bitmap等.
要在你的应用中使用Android 1.6包含的API的话你必须要设置 &quot;4&quot;属性在manifest的 元素中
Search framework
· 应用程序现在可以公开的有关内容,作为建议放入快速搜索框,新的设备范围内的搜索功能,是可从主屏幕搜索。为了支持这一点,搜索框架增加了新的属性,可搜索的元数据文件。有关完整的信息,请参阅SearchManager
文档。
Accessibility framework
· New android.accessibility package that includes classes for capturing accessibility events and forwarding them to an AccessibilityService handler.
· New AccessibilityService package that lets your application track user events and provide visual, audible, or haptic feedback to the user.
Gesture Input
· 新的gesture API :创建,识别,读取,保存手势.
Text-to-speech
· 新的android.speech.tts 包提供了TTS文本朗读功能,从一个文本生成一个声音文件的回放.
http://blog.csdn.net/CBirdLG/archive/2010/10/10/5931728.aspx
Graphics
· android.graphics 中的类,现在支持为不同的屏幕尺寸进行缩放.
Telephony
· 新的SmsManager 发送和接受短信.
Utilities
· 新的DisplayMetrics 字段决定当前设备屏幕的密度.
Android Manifest elements
o 新的 元素
o 新的 标签
o glEsVersion: 指定最小openGL ES的版本
·
元素的新的属性:
o 目标SDK版本: 应用程序能够指定目标版本. 它能够运行在旧版本(低至minSdkVersion), 他是按照应用程序的指定版本开发的. Specifying this version allows the platform to disable compatibility code that is not required or enable newer features that are not available to older applications.
o maxSdkVersion: 指定设计这个程序运行的最高版本 重要: 当使用  这些属性前请认真阅读文档.
New Permissions
· CHANGE_WIFI_MULTICAST_STATE: 允许应用进入Wi-Fi 多点传送模式.
· GLOBAL_SEARCH: 允许全局搜索系统,以便精确确定 content provider.
· INSTALL_LOCATION_PROVIDER: 允许应用在Location Manager.安装一个location provider.
· READ_HISTORY_BOOKMARKS: 允许应用读取(并不能写) 用户的浏览记录和书签
· WRITE_HISTORY_BOOKMARKS: 允许应用写入 (并不能读) 用户的浏览记录和书签
· WRITE_EXTERNAL_STORAGE: 允许程序写入外部存储器.应用程序使用API级别3下将默认授予此权限 (这对用户可见的); 应用程序使用API level4 或者更高的,必须要明确的宣告此权限.

Android 2.0 API变更概要:
Bluetooth
· 开启关闭蓝牙
· 设备和服务发现
· 使用 RFCOMM连接一个可插拔的设备收发数据
· 公布RFCOMM 服务和监听接收 RFCOMM 连接
Sync adapters
· 新的APIs, 同步桥接器连接任何backend
Account Manager
· 集中的帐户管理器 API ,安全的储存和使用可信的tokens/passwords
Contacts
· 新的通信APIs 允许获取多个账户的数据.
· 新的快速通信framework APIs 允许开发者在他们的应用中创建通信标记, 一键点击标记打开一个新的窗口展示一个如何联系当前人的列表.
WebView
· 不赞成使用的类: UrlInterceptHandler, Plugin, PluginData, PluginList, UrlInterceptRegistry.
Camera
· 颜色模式, 场景模式 闪光模式, 焦点模式, 白平衡 旋转和其他设置的新的特征.
· 当缩放级别改变的时候,会回调新的缩放回调接口.
Media
· MediaScanner现在为所有图片生成缩微图when they are inserted into MediaStore.
· 新的缩微图 API : 检索需要的图片和视频的缩微图.
Other Framework
· android.R.style 中新的系统主题,能够更加简单的显示当前acitivities的系统壁纸或者保持之前的activity在后台.新的壁纸管理器API 取代并且增加了wallpaper APIs ,我们可以允许我们的应用要求设置系统壁纸.
· 新的Service APIs帮助应用准确的处理Service 生命周期 ,在指定的低内存状态下service将会被关闭.
o Service.setForeground() 不推荐使用,并且现在这个方法并没有实际执行. .他被一个新的API所取代, startForeground(), that helps (and requires) associating an ongoing notification with the foreground state.
· MotionEvent 如果设备允许的话,MotionEvent 会返回多点触摸信息.最多可同时获取3点
· KeyEvent 现在有了新的按键发送 APIs,去帮助实现 action-on-up 和长按键行为, 一个新的机制取消按键 (虚拟按键).
· WindowManager.LayoutParams 现在有了新的常量允许窗口能够在被锁或者其他的状况中唤醒屏幕,这个允许程序能够让例如闹钟等的应用实现唤醒设备.
· New Intent APIs 广播设备的对接状态,当这个设备放在桌面或者停车场,允许程序启动特殊的activity.
Key events executed on key-up
Android 2.0能够使用虚拟按键HOME, MENU, BACK和SEARCH,而非物理按键,为了让用户在他们的设备中获得最好的用户体验,android平台现在把这些按键执行加入到了key-up,做了 key-down/key-up 配对,而非只有key-down.,这有助于防止意外按钮事件,并让使用者按下按钮区域,然后拖动而不生成一个事件出来。
这种改变只会影响你的应用程序一点,如果它是拦截按钮事件,最好用key-down,而不是key-up.。特例,如果您的应用程序拦截BACK 键,你应该确保你的应用妥善处理按键事件。

Android 2.0.1 API变更概要:
· 新的快速联系人标记风格(quickContactBadgeStyle)* 属性,让应用的QuickContactBadge 组件接收必要的风格.
· 当在manifest里面宣布了filter,取消了支持 ACTION_CONFIGURATION_CHANGED 广播 ,如果想要去接收这个广播, 这个应用必须注册 registerReceiver(BroadcastReceiver, IntentFilter).
性能上的改变:
Bluetooth
改变了 ACTION_REQUEST_ENABLE 和ACTION_REQUEST_DISCOVERABLE的返回值
· ACTION_REQUEST_ENABLE 如果蓝牙是成功开启的,现在返回RESULT_OK .如果使用者拒绝开启蓝牙的请求,则会返回RESULT_CANCELED .
· ACTION_REQUEST_DISCOVERABLE 如果使用者拒绝启动蓝牙或者蓝牙的可发现功能,则返回 RESULT_CANCELED .
通讯
The ACTION_INSERT Intent returns RESULT_CANCELED in cases where the contact was not persisted (例如剪切保存到一个空的操作里面).
修复错误:
资源
现在framework可以正选择应用资源的根据API等级划分的文件夹(drawable-v4是API level4版本用的资源).现在的版本这个功能不能正常工作的问题已经修复.
Contacts
The ACTION_INSERT Intent now returns the appropriate kind of URI when the request is made using the (now deprecated) Contacts APIs.
Other Framework fixes
· getCallingPackage() 现在正确的报告包名, 而不是进程名.

Android 2.1 API变更概要:
Live Wallpapers 动态桌面
以下增加的API可以提供你开发动态的桌面:
· 新android.service.wallpaper 包.
· 新WallpaperInfo 类.
· 升级的WallpaperManager.

附加说明, 如果你的应用相提供Live Wallpapers的功能, 你必须记得增加一个  元素到你的应用manifest里面. 宣布这个属性android:name=&quot;android.software.live_wallpaper&quot;. 举例:
电话

· 新的SignalStrength 类提供当前网络信号的一些信息这些信息可以从onSignalStrengthsChanged(SignalStrength) 回调.
· 新的onDataConnectionStateChanged(int, int) 回调.
Views
· 新的View 方法isOpaque() 和onDrawScrollBars(Canvas).
· 新的RemoteViews 方法addView(int, RemoteViews) 和removeAllViews(int).
· 新的ViewGroup 方法isChildrenDrawingOrderEnabled() 和setChildrenDrawingOrderEnabled(boolean).

WebKit
· 新的WebStorage 方法操作网页数据缓存.
· 新的GeolocationPermissions 方法获取 Geolocation permissions 的出处, 把他们设置到 WebView上.
· 新的WebSettings 方法管理软件缓存, 网页缓存 和屏幕的缩放.
· 新的WebChromeClient 方法处理视频, 历史记录, 自定义view, 软件缓存限制还有其他

Android 2.2 API变更概要:
对Microsoft Exchange更好的支持。Android的几个新特性使之更适于Exchange企业环境。其中一些新特性列举如下:

基于用户名/密码的Exchange帐号自动检测
支持Exchange日历的同步
改进的安全性,管理员可以跨越设备强制应用安全策略
恢复出场设置——管理员可以将设备重置为出场设置,这样就能在设备被偷或丢失后擦除上面的敏感数据了
全局的地址列表查找——可以根据服务器端返回的列表帮助用户自动填充收件人的邮件地址
设备管理API。Android 2.2改进并新增了大量的设备管理API,开发者可以将其用在应用当中:
应用数据备份API——可以将应用数据备份到云中。如果用户切换到另一个Android设备,他就可以从之前的设备中恢复数据。
Cloud-to-Device消息API。云中的用户/系统可以凭借这种增强在设备上触发动作。该特性可以将移动警告发给手机并且支持双向的推同步服务。
可以直接在外部的内存设备(SD卡)上安装应用,还可以将应用从内部迁移到SD卡上,反之亦然。
网络共享。Android 2.2可以通过一台Android电话提供的热点将多个服务连接到Internet上。

性能。借助于新式的Dalvik JIT编译器,对于CPU密集型应用来说,Android 2.2的速度要比Android 2.1快2~5倍。根据Linpack基准测试结果,安装了Froyo的Nexus
One电话可以达到37.5 MFlops,而同样的电话如果使用Android 2.1的话才有6.5 MFlops。

更快的浏览速度。由于浏览器现在使用了Chrome V8引擎,JavaScript代码的处理速度要比Android 2.1快2~3倍。

从浏览器中访问设备API。现在可以直接从浏览器中访问大量的设备API,如加速器、相机、声音识别、翻译等,这样Web应用就能以前所未有的方式与设备交互了。比如说,用户可以在拍完照后将其上传到网上,而这一切都是在浏览器内完成的。

支持Flash 10.1。Froyo支持最新的Flash 10.1
Beta版。最近,JIT编译器的引入极大地改进了性能,这对Flash应用的运行起到了巨大的帮助作用,因为大家都知道,Flash应用是一种CPU密集型应用。

Android商店。Android 2.2开发者和商店用户会从如下新特性中受益无穷:

可以在Android商店搜索应用,包括应用数据

更新——点击一次按钮后会自动更新所有应用

崩溃与冻结报告。Android
2.2集成了崩溃/冻结报告特性,这样在崩溃时用户就可以将完整的细节信息报告给应用发布者了

从PC上浏览商店并将应用直接下载到设备上。用户可以通过PC选择商店的应用,之后应用就可以发到到加载的设备上。要想使用这个特性,用户需要登录并且设备需要在Android商店注册-
音乐管理。用户可以将Windows Media或Mac iTunes上的所有非DRM音乐转换到Android设备上播放。

Android 2.3 API变更概要:
Android 2.3姜饼发布,代号Gingerbread,包含哪些新特性和改进呢?

   1. 新增android.net.sip包,名为SipManager类,可以轻松开发基于Sip的Voip应用。同时使用时必须至少包含这两个权限 <uses-permission android:name="android.permission.INTERNET"> and <uses-permission android:name="android.permission.USE_SIP">,如果需要在Market上过滤仅显示支持VoIP API的机型,可以在发布时androidmanifest.xml中加入 <uses-feature android:name="android.software.sip" android:required="true"> 和 <uses-feature android:name="android.software.sip.voip"> 这两个标志。

  2. Near Field Communications (NFC) 近距离通讯的支持,NFC可以在不接触的情况下实现数据交换通讯,可以很好的代替RFID SIM卡实现手机支付等扩展功能,当然Android123提示这需要硬件的支持
,新增包在 android.nfc包含NfcAdapter,NdefMessage,NdefRecord等类,类似蓝牙的处理方式,使用该API需要声明权 限<uses-permission android:name="android.permission.NFC"> ,同时在Market上过滤支持NFC的设备需要加入<uses-feature android:name="android.hardware.nfc" android:required="true">这句。

  3. 新增陀螺仪和其他的传感器支持
  Android 2.3加入了一些新的感应器,比如gyroscope陀螺仪, rotation vector旋转向量, linear acceleration线性加速器 gravity和barometer气压计的支持。如果过滤这些功能,发布时加入类似<uses-feature android:name="android.hardware.sensor.gyroscope" android:required="true">到androidmanifest.xml中。

  4. 多摄像头支持
新增 Camera.CameraInfo 可以管理摄像头前置或后置
新增 getNumberOfCameras(), getCameraInfo() 和 getNumberOfCameras() 获取摄像头数量。  
新增 get() 方法,可以获取摄像头配置信息 CamcorderProfile
新增 getJpegEncodingQualityParameter() 获取jpeg编码质量参数可以在 CameraPreview.java 文件从ApiDemos示例程序中查看。

5. 新增拍照API
  比如获取焦距getFocusDistances()获取预览FPS getPreviewFpsRange(), 获取焦距范围 getSupportedPreviewFpsRange() 和设置教育 setPreviewFpsRange()

6. 混响音效
本次Android 2.3框架中加入了对混响音效的支持,比如低音,耳机和虚拟化等效果.
新增 android.media.audiofx 包
新增 AudioEffect 类提供音效控制
新增音频会话ID,设置 AudioTrack 和 MediaPlayer.
新 AudioTrack 新增 attachAuxEffect()、getAudioSessionId()和 setAuxEffectSendLevel()。
新 attachAuxEffect() ,getAudioSessionId(), setAudioSessionId(int), 和 setAuxEffectSendLevel() .
相关音效在 AudioFxDemo.java 的 ApiDemos 示例。

6. 照片EXIF信息改进
新增 经纬度标签在JPG格式的EXIF中,同时可以使用 getAltitude() 方法获取经纬度的EXIF信息
新增setOrientationHint() 可以让程序获取视频录制的方向.

7. 下载管理
在Android 2.3中新增的下载管理支持长时间运行的Http下载服务支持。可以保证在手机重启后仍然重试下载等操作,整个过程在后台执行。
通过 DownloadManager 类使用getSystemService(DOWNLOAD_SERVICE) 来实例化,通过 ACTION_NOTIFICATION_CLICKED 这个Intent来处理。
http://www.android123.com.cn/androidkaifa/723.html

8. 限制模式
  可以帮助开发者监控他的应用的性能,处理线程阻塞,避免ANR的发生。

StrictMode.ThreadPolicy 和 StrictMode.VmPolicy 获取VM相关信息.
使用限制模式优化的Android应用程序可以查看android.os.StrictMode包的具体介绍。

Android 3.0 API变更概要:
Android 3.0 SDK中新增了哪些API呢? 我们总结下平板系统honeycomb中的新特性, 首先需要澄清的是经过Android123发现设置模拟器的分辨率到普通WVGA这样的解析度时平板的特性自动消失和Android 2.3没有什么太大区别,按照这样来看未来Android 3.0除了兼容平板外还继续可以被手机所支持,据称3.0的代码针对A9双核CPU进行了进一步的改进。

  一、Fragments 碎片容器
  有关Android Fragments的内容,Android开发网在前几天已经用几篇文章详细讲解了下,大家可以从Fragment对比Activity - Android碎片介绍 一文开始了解。

  二、Action Bar 活动栏
  活动栏Action Bar可以替换传统的标题栏在Activity窗口中,包括程序图标和一些新接口在activity的选项菜单中,另外Action Bar允许你
  Include select menu items directly in the Action Bar—as "action items"—for quick access to global user actions.
  In your XML declaration for the menu item, include the attribute, android:showAsAction with a value of "ifRoom". When there's enough room in the Action Bar, the menu item appears directly in the bar. Otherwise, the item is placed in the overflow menu, revealed by the icon on the right side of the Action Bar.
  Add interactive widgets to the Action Bar—as "action views"—such as a search box.
  In the XML for the menu item that should behave as an action view, include the android:actionViewLayout attribute with a layout resource for the action view or android:actionViewClass with the class name of the widget. Like action items, an action view appears only when there's room for it in the Action Bar. If there's not enough room, it is placed in the overflow menu and behaves like a regular menu item (for example, an item can provide a SearchView as an action view, but when in the overflow menu, selecting the item activates the search dialog).
  Add an action to the application logo when tapped and replace it with a custom logo
  The application logo is automatically assigned the android.R.id.home ID,
which the system deliveres to your activity's onOptionsItemSelected() callback when tapped. Simply respond to this ID in your callback method to perform an action such as go to your application's "home" activity.
  To replace the icon with a logo,
  Add breadcrumbs for navigating backward through fragments
  Add built in tabs and a drop-down list for navigation
  Customize the Action Bar themes and custom backgrounds
  有关ActionBar的文章,可以参考 Action Bar使用方法 - Android活动栏 系列文章

  三、System clipboard系统剪切板
  Android 3.0中的剪切板进行了增强,本次可以支持除了纯文本外更多的内容,如,URL和Intent,对于剪切板类ClipboardManager仍然通过 getSystemService(CLIPBOARD_SERVICE)来实例化,新增的ClipData类用于管理具体的复制对象,可以在SDK的 android.content.ClipData.Item中找到。 具体的使用Android123将在今后的文章中写道。

  四、拖拽
  开始拖拽内容在你的Activity中可以使用startDrag()方法在一个View中,这里 View.DragShadowBuilder提供了拖拽时的阴影,对于拖拽的过程处理可以通过OnDragListener通过View的 setOnDragListener()来设置,在拖拽的时候系统会自动调用onDrag()方法。

  五、增强的appWidgets
  Android 3.0的appWidget开始支持更丰富的控件,比如GridView, ListView, StackView, ViewFlipper和AdapterViewFlipper.而以前必须通过RemoteView显示一个文本或图片,本次全新的 RemoteViewsService增强了桌面小插件的功能。

  六、增强的状态提示栏
  新增的Notification API可以丰富你的状态栏,新的Notification.Builder类可以帮助你轻松实现,支持大图标提示信息通过setLargeIcon方法, 通常显示一些社交类的软件,比如联系人照片,或相册缩略图,设置自定义状态栏,可以使用setTicker()方法。

  七、内容加载器
  新框架API提供了一个异步加载内容的泪,合并和UI组件和fragment来动态加载数据从工作者现成,使用CursorLoader子类来获取ContentResolver中的数据.

  八、A2DP蓝牙和耳机控制API
  Android honeycomb中没有忘记再次增强蓝牙,你可以通过初始化BluetoothProfile通过调用getProfileProxy()在处理 A2DP或耳机HEADSET设置,BluetoothProfile.ServiceListener可以获取客户端连接或断开的回调。
  九、动画框架
  3.0中Android再次增强动画播放类,ObjectAnimator和LayoutTransition需要大家了解一些。

  十、扩展UI框架
  新增以下UI控件
  AdapterViewAnimator
  AdapterViewFlipper
  CalendarView
  ListPopupWindow
  NumberPicker
  PopupMenu
  SearchView
  StackView

  十一、图形相关
  1. 2D图形硬件加速Hardware accelerated 2D graphics , 在androidmanifest.xml的 元素中添加android:hardwareAccelerated="true" 即可。他可以优化程序运行更平滑高效,在滚动和动画方面。
  2.设置渲染模式,比如 LAYER_TYPE_HARDWARE 硬件加速和 LAYER_TYPE_SOFTWARE 使用 setLayerType() 方法.
  3.渲染脚本对于3D图形方面大家可以看看Renderscript类。

  上面是Android 3.0的主要改进,明天Android开发网将和大家一起说下强大的对于平板电脑比较重要的Action Bar活动栏。

posted @ 2011-07-15 09:32 oathleo 阅读(1177) | 评论 (0)编辑 收藏

在很多地方都有“数据交换”这个概念,本文所说的“数据交换” 是指在计算机网络中,一个系统把数据传递给另外一个系统。这非常类似于一个人要告诉另外一个人一件事情。

当一个人要把一件事情告诉另外一个人的时候,我们可以通过电话、邮件、短信、IM工具或者当面说的方式来交流。这种方式类似于系统数据交换要通过 tcp、udp、管道等等的方式实现。当两个人交流的时候,我们需要一种共同的语言才能明白对方的意思,同样的,两个系统要交换数据,也需要定义一种双方 都明白的协议,我们称为“数据交换协议”。

数据交换协议

数据交换协议的目的是让两个系统进行正确的数据交互。所以几乎各种开发语言都提供了方便使用的数据交换功能。比如说使用JAVA语言的开发的系统使 用 MySQL数据库存储数据,就是通过MySQL数据交换协议跟MySQL做数据交换;通过JAVA的RMI可以方便的做跨机器的分布式数据交换,RMI也 就是一种数据交换协议。

一般我们在不同的系统、不同的语言之间交换数据的时候,我们会选择一种通用的交换协议或者自己定义一种容易使用的交换协议。 WebService曾经非常流行, 在Web 2.0时代,轻量级的REST协议又开始受到追捧。那么究竟在我们的系统中应该选择什么样的协议呢?

如何选择数据交换协议

选择什么样的协议跟我们的应用场景有很大的关系。我们需要考虑我们开发是否方便、接口是否容易发布、是否需要考虑带宽占用成本、序列化和反序列化的性能、接口协议的扩展性等等。下面我们看下几个比较常用的交换协议实现。

协议 实现 跨语言 性能 传输量 RPC
xml 广泛 几乎所有 很大 N(可实现)
json 广泛 大量 一般 一般 N(可实现)
php serialize PHPRPC 大量 一般 一般 Y
hessian hessian 大量 一般 Y
thrift thrift 大量 Y
protobuf protobuf 大量 N(可实现)
ice ice 大量 Y
avro Apache Avro 少量 Y
messagepack messagepack 大量 Y

上面表格列出了一些常用数据交换协议的一些特性的比较。这里并没有比较好坏,只是想说明不同数据交换协议是有区别的,所以我们需要在我们的应用场景中进行选择。

开放式

像微博,SNS这种开放平台、对静态html页面提供javascript接口调用的系统都属于这种类型 。这种类型的特点是:

  • 调用方不完全可控,而且是针对公网的,你可能不知道是谁、是什么语言、是什么方式在调用你提供的数据接口;
  • 接口访问量一般都非常大,要求具有很高的性能和吞吐量;
  • 需要考虑安全问题,外部提交的数据可能不是合法的。

所以在这种情况下,需要考虑数据传输的带宽消耗和数据交换协议的易用性,以及多语言支持程度。以前对于html页面使用的javascript接口 调用一般都使用XML格式,最近几年几乎都转成了json格式了,因为json传输量更小,比XML更加容易使用。 而对于开放平台,由于使用的场景很多,所以需要提供多种交换协议格式。基本上都会提供XML和json。为了提高平台本身的性能和客户端的性能,也可以提 供protobuf这种二进制交换协议并且增加压缩支持,以节省带宽传输和解析的性能消耗。

内部服务

对于一个大型系统来说,内部服务的数据交换无处不在。从最基本和常见的数据库数据交换、memcached缓存数据交换、消息队列的数据交换到系统 之间使用的RPC服务框架等等,都可以算作内部服务的数据交换。内部服务的特点是不用考虑防火墙,不对外开放,速度快(基本无带宽成本)。

内部服务的数据交换协议的选择空间非常大,一般需要考虑:

  • 数据交换协议的性能
  • 是否需要跨语言支持
  • 数据交换协议的消息体大小

持久化存储

对于持久化存储来说,每一种数据交换协议其实都可以实现。一般需要根据应用场景考虑:

  • 是否人工可阅读
  • 存储的空间消耗
  • 序列化和反序列化的性能
  • 是否经过压缩

跨语言

假设我们的网站前端页面展示层使用PHP语言开发,中间业务逻辑使用JAVA语言开发,那么就涉及到跨语言数据交换的问题。只要系统不是单纯的使用一种语言,那么就必须考虑这个问题。事实上,考虑未来的扩展和需求变化问题,也最好考虑跨语言的数据交互协议。

数据交换协议可升级

在选择数据交换协议的时候,我们同样需要考虑类似于数据库表的?schema设计时的扩展问题。比如一个提供用户信息的数据交换协议接口,现在包含 用户名、性别、住址的信息,在升级过程中,增加了一个最后登录的IP信息。如果不考虑数据交换协议升级带来的影响,很可能会导致以前的客户端出现异常或者 旧的数据无法正确解析的问题。

兼容协议的巧用

兼容协议的巧用非常有用,新产品兼容提供现有成熟的数据交换协议,可以降低使用门槛和产品的开发速度。比如新浪开源的memcacheQ就使用了memcached协议。

总结

数据交换协议的各种通用开源实现非常多,数据交换协议只是一个非常宽泛的说法,其实只要实现了数据的序列化和反序列化 ,那么就可以说是一个可以交换数据的协议。数据交换协议的性能其实就是序列化和反序列化的性能,如果加上RPC,那么跟RPC实现本身的性能也有非常大的 关系。

posted @ 2011-05-09 16:41 oathleo 阅读(248) | 评论 (0)编辑 收藏

有这样一群人,他们经常孤独地工作到深夜,漆黑夜里的显示器成为房间中唯一的光源,手边残留着比萨饼和碳酸饮料。繁重的编码任务让他们很少离开座位,即便是周五的深夜,这些人依旧在办公室中奋战。
乍一听,这像是在描述黑客们的工作状态。但实际上,大多数普通的开发人员就是这样生活着。除了工作,他们有家庭、兴趣以及责任,但项目的压力让他们无暇顾及工作以外的事情。工时长、假期短以及与当前社会发展脱节等问题普遍存在于他们当中。

虽然现在社会大力倡导所谓的知识经济,但这群聪明且高度专业化的人员不被重视,因为经理们认为,程序员是替代性很强的群体。这样的观念导致这些潜在的社会精英不得不重新考虑他们的职业规划。最终,他们当中的大多数另谋高就,另一些则踏入到全新的行业之中。

你认为游戏行业真的是一片乐土吗?一名业内人士讲,游戏开发几乎会占据程序员生活的全部,因为产品质量总会有改进的余地。他们工作时间长,没有加班费以及应有的假期。有些员工甚至连续四年薪水都没有调整过。他身边不少同事都是因为工作而导致了离婚。

当工作条件变得无法忍受时,最聪明以及最有天分的员工通常是最先离开的。凭借他们的资质,他们可以在其他领域挖掘到更多的机会。这样势必导致开发团队整体 水平的下降。经理对开发者施加的压力越大,长期来看团队的效率就越低。IT顾问布鲁斯·韦伯斯特将这种情况称为“死海效应”。如果公司发展每况愈下,它就 更难得到真正的人才,也更难留住这些人,这样的恶性循环无疑会拖垮公司。离岸外包的出现则加剧了这种趋势:内部开发团队的效率越低,公司就越希望通过低成 本外包取代这个团队。而内部开发者会强烈地感到他们即将被替代,因此无法集中精力工作。

员工的倦怠会毁掉公司的未来,而经理们是可以降低死海效应的。他们可以设定合理的工作时长并且提供加班费,可以规定公休日并严格地执行,可以设置合理的产 品发布时间以减少过度的压力。他们甚至可以尝试调整项目的开发方法,比如采用敏捷开发等。但是,最重要的一点就是,他们必须重新审视开发人员的价值。在这 样一个与互联网发展速度同步的领域,每一个员工都应该被公平、公正地对待,并且获得应有的尊重,即使他们真地喜欢比萨饼和碳酸饮料。

posted @ 2010-08-10 09:51 oathleo 阅读(1674) | 评论 (0)编辑 收藏


功能很简单:
1.从后台实时取数据展示 Demo 是用socket取,起Task每秒去取
2.把取得数据展示成图表形式
3.把取得数据展示成拓扑图形式
代码很简单,拓扑部分在另个项目中,以后集成进Demo

posted @ 2010-08-04 16:37 oathleo 阅读(1905) | 评论 (3)编辑 收藏

仅列出标题
共17页: First 上一页 6 7 8 9 10 11 12 13 14 下一页 Last