9/15/2015

Google I/O 2011:: Memory management for Android Apps

It's a bit late to see this.
But it's really a good vedio


Should add more notes here.


GC_CONCURRENT == normal GC behaviour to prevent heap
GC_FOR_MALLOC == GC_CONCURRENT didn't completed and need to allocate more memory for GC
GC_EXTERNAL_ALLOC = wont appear after honeycomb
GC_HPROF_DUMP_HEAP
GC_EXPLICIT

But actually GC wont prevent memory leaks.
Leak: ref to an unused object preventing GC
and it occurs often at the ref to Activity(context), like drawable, icons, ..etc

6/13/2015

Is Java pass by reference?

http://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value

4/20/2015

分析ANR (1)

ANR, Application No Response
對岸稱為 應用無響應
其實就是 軟體不理你
也就是說 app main thread 無法做出反應

通常這時候, 螢幕會秀出這樣的畫面給你看

 

根據官方的說法, 通常會發生這樣的情況都是由於系統判斷你的main thread/UI thread已經過了該做出反應的時限卻仍然沒有做出反應, 因此官方強烈建議避免ANR發生的方法就是請不要什麼事都在main thread上面做, main thread負擔愈少愈好

おすすめ:請善用 AyncTask or Handler 這類方法將你想做的事情開在支線任務

------------------------------------------------------------------------------------------------------------------------------
那麼進入正題
通常ANR發生了以後該怎麼辦?
基本上就是直接調出資料做分析

1. 觀察LogCat 確認ANR發生
2. 抓出 data/anr/traces.txt
3. 針對 traces.txt 進行分析 :找出 Application is not responding 發生位置
4. 確認發生ANR的類型
5. 有譜 --> 回頭確認 code
6. 沒譜 --> 進入 thread analysis 對 stack 抽絲剝繭

因為Android會將ANR的log存在 data/anr/ 下, 因此對開發人員來說算是個福音?
至少跟dump是分開的..某種程度來說, 算是簡單的分類
再來, 從上面的步驟可以知道, ANR的分析從第三步開始
因此, 認識ANR發生的類型極其重要
了解類型之後才能加速分析的過程(知道大概問題出在哪方面), 進一步增加得到答案的成功率, 同時也能防止自己日後做出同樣的事情導致必須分析ANR的苦果

4/17/2015

[Android] 做自己的Spinner (3)

上次已經把Spinner整個元件的建立都講完了
下拉選單中的每個元件細部設定, 除了xml上的設置, 其他都在adapter中的getView()完成
getView()[Android] 做自己的Spinner (1)中有貼到了

所以現在 就剩下Spinner的使用了
首先是在需要的畫面中加入自製的spinner到xml中
<idv.ally.tool.UI.ListSpinner
    android:id="@+id/skillsListSpinner"
    android:layout_width="@dimen/info_spinner_width"
    android:layout_height="match_parent"                               
    android:background="@drawable/info_spinner" />


然後在我們需要加spinner的view裡將spinner設好起始畫面
包括抬頭標題和Listener設置
就像一般的情況一樣, 通常是在onCreate()吧

private ListSpinner mSkillsSpinner;
//.......
//@onViewCreate()
mSkillsSpinner = getViewById("skillsListSpinner");
mSkillsSpinner.setTitle(getActivity(), "spinner_list_item", "SKills");
mSkillsSpinner.setListener(this);
然後再設定好需要的選單樣式跟內容
//@onViewShowed()
int id =getResourceId(ResourceType.Array, "skills");
mSkillsSpinner.setItems(getContext().getResources().getStringArray(id), 
    getResLayout("spinner_dropdown_item"), SpinnerType.RADIO_TOGGLE_SPINNER);
最後就是看你哪時後要show要hide了
mSkillsSpinner.show();
mSkillsSpinner.hide();
Spinner事件觸發時的反應
@Override
public void onCloseSpinner(ListSpinner spinner)
{
  updateBackground();
}

@Override
public void onItemClicked(View holder)
{
  mSkillsType = getSkillsType(holder.getTag().toString());
}

全部就大功告成啦!

4/16/2015

[Android] 做自己的Spinner (2)

既然是同一篇的話 還是趕快完成得好
這麼一想就有動力來更新了

之前講到在Spinner裡面設置了public成員 setTitlesetItems
那麼其實畫面的設置已經完成一半了
剩下的主要功能就是
展開下拉式選單 - show()
和收起下拉式選單 - hide()
再來是提供聽取Lisenter的方法 - setListener()

這些做完後, 就剩下拉式選單的畫面設置
還有Spinner元件本身使用的方式而已了
簡單吧 = =+

首先 show(), hide(), setListener()全都放在Spinner裡
都是他的成員
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
  View row = convertView;
  
  if (row == null)
  {
    LayoutInflater inflater = mActivity.getLayoutInflater();
    row = inflater.inflate(mLayoutResource, parent, false);
  }
  String desList = list[position];
  updateListBackground(row, position);
  
  RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(400, LayoutParams.MATCH_PARENT);
  rlp.setMargins(10, 0, 0, 0);
  
  TextView name = (TextView) row.findViewById(mHolderViewId);
  name.setLayoutParams(rlp);
  name.setText(desList);
  name.setTag(desList);
  
  updateListTriggerByType(row, this.mSpinnerType, desList);      
  
  return row;
}    



/**
 * show drop-down list.
 * */
public void show(View parent)
{
  mAttachedParent = (ViewGroup) parent;
  
  Animation animax = new AlphaAnimation(0.0f, 0.1f);
  animax.setDuration(200);
  
  mSpinnerList.setAnimation(animax);
  mAttachedParent.addView(mSpinnerList);
  
  animax.start();
  mIsExpanding = true;
}

/**
 * Show your drop-down list at pointed position with pointed width. 
 * @param parent Parent view of your spinner.
 * @param left The left position of spinner's left upper corner.
 * @param top The top position of spinner's left upper corner.
 * @param width Spinner's list width.
 * */
public void showAtPosition(View parent, int left, int top, int width)
{
  LayoutParams params = new LayoutParams(width, LayoutParams.MATCH_PARENT);
  params.setMargins(left, top, 0, 0);
  mSpinnerList.setLayoutParams(params);
  
  show(parent);
}

/**
 * hide drop-down list
 * */
public void hide()
{
  Animation animax = new AlphaAnimation(1.0f, 0.0f);
  animax.setDuration(200);
  
  mSpinnerList.startAnimation(animax);
          
  mAttachedParent.removeView(mSpinnerList);
  mIsExpanding = false;
  mSpinnerListener.onCloseSpinner(this);
}

我因為需要設置好作為下拉式選單的ListView的位置
因此增加了一個成員 showAtPosition()
透過 LayoutParams.setLayoutParams(params); 去做位置的調整

再來, 下拉式選單"滑出"的效果則透過動畫Animation來實現
基本上我試過, "移動"跟"淡入/淡出"的效果, 做起來都不錯
另外我設置了一個private boolean variable: mIsExpanding
用來存選單開啟與否的狀態

再來是Listener
Listener的好處應該不用多說了
我用 Interface 來實現, 放在Spinner下
其中只設置了兩個方法, 都是用來確認Spinner的狀態
名稱都跟Android本身提供的Listener幾乎一樣, 所以應該很好懂
public interface ListSpinnerListener
{
  /** Will be called after the spinner hiding its drop-down list.*/
  public void onCloseSpinner(ListSpinner spinner);
  /** Will be called if user click the spinner's row item. Current supported with spinner type STRING_SPINNER. */
  public void onItemClicked(View holder);
}
然後為Spinner新增 setListener() 這個方法
讓外部使用者透過他就能設好該Spinner的Listener
/**
 * ListSpinner provide listener to check the action movement of listened spinner.
 * */
public void setListener(ListSpinnerListener listener)
{
  mSpinnerListener = listener;
}
最後, 簡單看一下 layout到底長什麼樣子
上一篇提過 layout 只需要兩個就好, 一個是 title 用, 一個 item用

title長這樣


item長這樣


因為item每行的結構都一樣, 當然也是寫一行就好, 其他都交給程式來做
擴充型的item長這樣
    

    

  
    

所以現在回去看就能知道, 需要什麼樣的title與item
只要畫好單一的layout
再使用 setItem, setTitle, 一切就都沒問題了!

時間不夠了, 剩下的放第三篇吧

4/15/2015

[Android] 做自己的Spinner (1)

Spinner簡單來說是Android提供的下拉式選單元件
因為drop-down的功能基本上提供於 Android 3.0以上的平台
因此Spinner也必須是在3.0以上的平台才能直接使用
                                              
這篇之所以會產生是因為當初開發的平台不到 3.0
又需要下拉式選單的功能, 也不考慮使用一些知名library如 ActionBarSherlock
因此只好自行觀察原理, 然後刻一個

依照本篇的作法, 可以做出像是Android Spinner的元件跟擴充型Spinner
製作spinner首先需要三個檔案

Spinner.java //Spinner object 本身
spinner_title_layout.xml
spinner_item_layout.xml

Spinner.java 本身控制 Spinner 的主體
也就是上圖裡藍藍的 top object, 對應到的 layout 就是 spinner_title_layout.xml
碰觸主體後可以展開/收起下拉式選單, 選單的 layout 是 sppiner_item_layout.xml
再透過ListView實作
從這裡可以看出, 將主體跟選單的畫面分開做就是為什麼可以做擴充型 Spinner 的原因, 丙且, 選擇的結果可以在主體作相對應的變化
因此主體本身也是一個View, View本身包含需要的Listener還有一些基本功能
基於個人喜好, 我使用RelativeLayout去做設置
簡單來說長成這樣

public class ListSpinner extends RelativeLayout
{
  public enum SpinnerType
  {
    STRING_SPINNER,
    RADIO_TOGGLE_SPINNER //with toggle button + single selection
  }


  private class ListAdapter extends ArrayAdapter
  {
    String[] list;
    int mHolderViewId;
    int mLayoutResource;
    
    SpinnerType mSpinnerType;
    
    @SuppressWarnings("unchecked")
    public ListAdapter(Context context, int resource, String[] list, SpinnerType type)
    {
      super(context, resource, list);
      this.list = list;
      this.mLayoutResource = resource;
      this.mSpinnerType = type;
      this.mHolderViewId = getResourceIDByName(mActivity, ResourceType.Id,"dropdownTxt");
      getListButtonByType(type);
    }
    
    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
      View row = convertView;
      
      if (row == null)
      {
        LayoutInflater inflater = mActivity.getLayoutInflater();
        row = inflater.inflate(mLayoutResource, parent, false);
      }
      String desList = list[position];
      updateListBackground(row, position);
      
      RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(400, LayoutParams.MATCH_PARENT);
      rlp.setMargins(10, 0, 0, 0);
      
      TextView name = (TextView) row.findViewById(mHolderViewId);
      name.setLayoutParams(rlp);
      name.setText(desList);
      name.setTag(desList);
      
      updateListTriggerByType(row, this.mSpinnerType, desList);      
      
      return row;
    }    
  }

  public ListSpinner(Context context, AttributeSet attrs)
  {
    super(context, attrs);
    mActivity = null;
    mContext = context;    
    
    mSpinnerTitle = DynamicViewUtil.getViewById(this, "spinnerTitle");    
    
    mIsExpanding = false;
  }
}

首先定義之後可以使用的Type
並且完成下拉式選單用的Adapter
為了讓使用這個元件可以更快速地加入每個選項的文字, 我選擇ArrayAdapter
然後做出簡單的建構子

考慮到在實用上, 不同的spinner會需要有不同的 top column 和 item
因此需要再加入兩個函數:setTitlesetItems

public void setTitle(final Activity activity, String titleLayout, String title)
{
  mActivity = activity;
  
  int id = getResourceIDByName(mActivity, ResourceType.Layout, titleLayout);
  View view = inflate(mContext, id, null);
  addView(view);
  
  ListSpinner.LayoutParams llp = new ListSpinner.LayoutParams(400, LayoutParams.MATCH_PARENT);
  llp.setMargins(10, 0, 0, 0);
  
  mSpinnerTitle = getViewById(this, "spinnerTitle");
  mSpinnerTitle.setLayoutParams(llp);
  mSpinnerTitle.setText(title);
  
  mSpinnerList = new ListView(mContext);    
}

/**
 *  set up your spinner row content with provided listItems, layout, and pointed spinner type.
 * @param listItem The String list for spinner row item.
 * @param layoutResource Layout for spinner itself.
 * @param type Spinner presenting style.
 * */
public void setItems(String[] listItems, int layoutResource, SpinnerType type)
{
  mListAdapter = new ListAdapter(mContext, layoutResource, listItems, type);
  mSpinnerList.setAdapter(mListAdapter);        
}

可以看到我在 setTitle 的地方才去實作下拉式選單 mSpinnerList
在 setItem 的時候, 就能產生不同類型的 spinner

基本上Spinner的主體大約就是長這樣
當然我刪掉了很多不需要講解的source 因此看起來有些缺東缺西
接下來會繼續補上 Spinner其他的函式成員, 作為Listener的Interface, 兩個Spinner Layout簡單Demo最後的使用方法

2/03/2015

Becoming a Android Developer

不知不覺寫Android已經一年多了
完成了許多feature
也學習主導案子
算是有做了些有趣的東西
但都沒有記錄下來....實在是很可惜
blog就被我這懶人給荒廢掉了

列一下該補齊的重點
1. 如何在GingerBread (Android 2.3 / before Android 3.0) 自刻spinner
2. 分析ANR