<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    咖啡伴侶

    呆在上海
    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 閱讀(700) | 評論 (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 閱讀(474) | 評論 (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 閱讀(201) | 評論 (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 閱讀(301) | 評論 (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 閱讀(2929) | 評論 (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 閱讀(296) | 評論 (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 閱讀(1189) | 評論 (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 閱讀(262) | 評論 (0)編輯 收藏

    有這樣一群人,他們經常孤獨地工作到深夜,漆黑夜里的顯示器成為房間中唯一的光源,手邊殘留著比薩餅和碳酸飲料。繁重的編碼任務讓他們很少離開座位,即便是周五的深夜,這些人依舊在辦公室中奮戰。
    乍一聽,這像是在描述黑客們的工作狀態。但實際上,大多數普通的開發人員就是這樣生活著。除了工作,他們有家庭、興趣以及責任,但項目的壓力讓他們無暇顧及工作以外的事情。工時長、假期短以及與當前社會發展脫節等問題普遍存在于他們當中。

    雖然現在社會大力倡導所謂的知識經濟,但這群聰明且高度專業化的人員不被重視,因為經理們認為,程序員是替代性很強的群體。這樣的觀念導致這些潛在的社會精英不得不重新考慮他們的職業規劃。最終,他們當中的大多數另謀高就,另一些則踏入到全新的行業之中。

    你認為游戲行業真的是一片樂土嗎?一名業內人士講,游戲開發幾乎會占據程序員生活的全部,因為產品質量總會有改進的余地。他們工作時間長,沒有加班費以及應有的假期。有些員工甚至連續四年薪水都沒有調整過。他身邊不少同事都是因為工作而導致了離婚。

    當工作條件變得無法忍受時,最聰明以及最有天分的員工通常是最先離開的。憑借他們的資質,他們可以在其他領域挖掘到更多的機會。這樣勢必導致開發團隊整體 水平的下降。經理對開發者施加的壓力越大,長期來看團隊的效率就越低。IT顧問布魯斯·韋伯斯特將這種情況稱為“死海效應”。如果公司發展每況愈下,它就 更難得到真正的人才,也更難留住這些人,這樣的惡性循環無疑會拖垮公司。離岸外包的出現則加劇了這種趨勢:內部開發團隊的效率越低,公司就越希望通過低成 本外包取代這個團隊。而內部開發者會強烈地感到他們即將被替代,因此無法集中精力工作。

    員工的倦怠會毀掉公司的未來,而經理們是可以降低死海效應的。他們可以設定合理的工作時長并且提供加班費,可以規定公休日并嚴格地執行,可以設置合理的產 品發布時間以減少過度的壓力。他們甚至可以嘗試調整項目的開發方法,比如采用敏捷開發等。但是,最重要的一點就是,他們必須重新審視開發人員的價值。在這 樣一個與互聯網發展速度同步的領域,每一個員工都應該被公平、公正地對待,并且獲得應有的尊重,即使他們真地喜歡比薩餅和碳酸飲料。

    posted @ 2010-08-10 09:51 oathleo 閱讀(1686) | 評論 (0)編輯 收藏


    功能很簡單:
    1.從后臺實時取數據展示 Demo 是用socket取,起Task每秒去取
    2.把取得數據展示成圖表形式
    3.把取得數據展示成拓撲圖形式
    代碼很簡單,拓撲部分在另個項目中,以后集成進Demo

    posted @ 2010-08-04 16:37 oathleo 閱讀(1910) | 評論 (3)編輯 收藏

    僅列出標題
    共17頁: First 上一頁 6 7 8 9 10 11 12 13 14 下一頁 Last 
    主站蜘蛛池模板: 中文字幕永久免费视频| 在线看片v免费观看视频777| 亚洲AV无码国产精品色午友在线 | 亚洲精品午夜久久久伊人| 成人女人A级毛片免费软件| 国产av无码专区亚洲av毛片搜| 亚洲日韩精品射精日| 成人黄动漫画免费网站视频| 日韩精品视频在线观看免费 | 亚洲乱码在线播放| 亚洲M码 欧洲S码SSS222| 99精品视频在线视频免费观看| 亚洲AV无码一区二区三区牲色| 亚洲精品午夜无码专区| 免费精品国偷自产在线在线| 99麻豆久久久国产精品免费| 国产成人亚洲合集青青草原精品| 亚洲色偷拍区另类无码专区| 老司机在线免费视频| 国产午夜无码片免费| 亚洲AV无码国产精品永久一区| 亚洲嫩模在线观看| 亚洲一区二区三区乱码A| 国产人成免费视频网站| 成人免费一区二区三区| 激情小说亚洲图片| 亚洲成人黄色网址| 亚洲爆乳无码一区二区三区| 亚洲 综合 国产 欧洲 丝袜| 在人线av无码免费高潮喷水| 香蕉成人免费看片视频app下载| 国产亚洲综合久久| 亚洲中文字幕一二三四区| 亚洲成色在线影院| 国产成人亚洲精品狼色在线| 国产真人无遮挡作爱免费视频| 亚洲日本在线免费观看| 国内精品免费在线观看| 中国内地毛片免费高清| 免费看一级一级人妻片 | 美女被免费喷白浆视频|