2015年10月22日 星期四

【Java】幾個常見方法的差別String.valueOf() & Object.toString()


一、String.valueOf()  & Object.toString()


  • String.valueOf()
如果你給他String.valueOf("null"),我們得到的會是null這個字串

  •  Object.toString()
但toString()如果你給他null.toString(),則他會丟出 NullPointerException 


二、Integer.valueOf()  & Integer.parseInt()


  • Integer.valueOf()  
他會回傳的是一個Object ,new Integer()

【Android】hax kernel module is not installed ex: Thinkpad t430s


久久沒使用AVD來模擬,開啟時發現跳出這個錯誤,來記錄一下如何解決

Step 1

確認自己的cpu是否有支援

Intel VT(Virtualization Technology虛擬化技術)或XD (Execute Disable Bit)


可以到intel的官網去查詢 http://ark.intel.com 

進去後直接輸入自己cpu的型號並拉到下方找到


  • Advanced Technology
  • Intel Platform Protection Technology
就會顯示是否支援 !!



Step 2

確定有支援後去開啟Android Studio裡的 SDK Manager 去檢查

Intel x86 Emulator Accelerator(HAXM installer)有沒有安裝

沒有的話請安裝他!!!



Step 3

進入自己的BIOS去把Virtualization 開啟

以我的thinkpad t430s為例:

BIOS-->Security -->Virtualization -->Enable 


Step 4

開啟
Android Sdk的路經
以我自己為例:

C:\Users\UserName\AppData\Local\Android\sdk\extras\intel\Hardware_Accelerated_Execution_Manager

安裝!!!!!

也可以直接去Intel 官網下載

Step 5


安裝完成後 基本上就能啟動了!!!!!!!!


參考連結:

2015年9月29日 星期二

【Android】設定Activtiy的主頁 返回箭頭 Navigate Up to Parent Activity

今天介紹一個簡單的,如何設定Activtiy的主頁  Navigate Up to Parent Activity

假設你有三個Activtiy

  • 主頁 Main
  • 設定 Setting
  • 關於 About
當我們由主頁進入Setting,又由Setting進入About ,

你會發現點選Action bar右上箭頭只能由About 返回Setting,

如果希望回到Main,就要利用這個方法,去設定你Activtiy的主頁

 android:parentActivityName="com.example.myfirstapp.MainActivity" 

 <activity
        android:name="com.example.myfirstapp.AboutActivity"
        android:label="@string/title_activity_display_message"
        android:parentActivityName="com.example.myfirstapp.MainActivity" >
        <!-- Parent activity meta-data to support 4.0 and lower -->
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.myfirstapp.MainActivity" />
    </activity>


設定後那麼不管到是由哪個頁面到哪個頁面

按Action bar右上箭頭都將回到你設定的主頁


http://developer.android.com/training/implementing-navigation/ancestral.html#NavigateUp

2015年9月10日 星期四

【Android】jsoup 擷取網頁資訊 台銀匯率


------------------------------2019/01/07  Update !! ---------------------------------------

目前台銀網站有更改html的格式所以以下棄用

  • 幣別  td class = "titleleft"
  • 匯率 td class = "decimal
  • 更新時間 td style ="width:326px;text-align:left;vertical-align:top;color:#0000FF;font-size:11pt;font-weight:bold;"
這邊要做修正哦 !!!!!!
--------------------------------------------------------------------------------------------------------------



這次利用jsoup 這個lib,來練習如何擷取網頁上的資訊

我們以台灣銀行的匯率做一個簡單的範例

一、


先將jsoup.jar下載下來並加入android studio中

http://jsoup.org/download

二、


開始分析我們要擷取的網頁,我們主要要抓的是匯率,所以從台銀的網頁,開啟開發者模式

台銀的網頁:

https://rate.bot.com.tw/xrt?Lang=zh-TW   (新網址)

http://rate.bot.com.tw/Pages/Static/UIP003.zh-TW.htm (舊網址)




以下是我們要抓的資料
  • 幣別
  • 即期匯率 買入 賣出
  • 現今匯率 買入 賣出
  • 更新時間


從網頁原始碼上可以發現
  • 幣別  td class = "titleleft"
  • 匯率 td class = "decimal
  • 更新時間 td style ="width:326px;text-align:left;vertical-align:top;color:#0000FF;font-size:11pt;font-weight:bold;"


三、


既然知道資料在哪,那麼就可以開始利用jsoup來擷取網頁的資訊

那麼我們可以利用 select這個方法去抓取資料,

以下為一個簡單範例

private static final String url ="http://rate.bot.com.tw/Pages/Static/UIP003.zh-TW.htm";
  public void getInfo(){
  try {
    Document doc = Jsoup.connect(url).get();
    doc.select("td.titleleft").text();
  }catch(Exception e){


  }

  }
     
※注意:

在OnCreate裡不能直接呼叫Jsoup.connect(url).get(),因為在4.0版之後為了避免連線時間過長導致App ANR,所以要利用Thead去執行Jsoup.connect(url).get()這個動作。

※記得:要加入網路連線的權限哦!!!!!!

jsoup的抓取範本:http://jsoup.org/cookbook/extracting-data/selector-syntax

研究一下發現我們要抓取的資料格就分為

  • doc.select("td.titleleft")
  • doc,select("td.decimal")
  • doc.select("td[style=width:326px;text-align:left;vertical-align:top;color:#0000FF;font-size:11pt;font-weight:bold;]")
我們就能夠利用ListView把我們需要的資料裝進去

四、


那我們就開始把擷取出來的資料建立起來

主要的架構分為


  • RateItem 建立一個物件存入我們的資料
  • MainActiviy 執行擷取資料的部分及顯示
  • ListViewAdpater 自訂ListView畫面
  • listview_custom.xml ListView的layout
  • listview.header.xml ListView的header
  • activtiy_main.xml 
以下為程式碼:

  • RateItem

用String去裝匯率資料是比較偷懶的方式,如果有要計算等等,還是建議用double等資料型態去裝

public class RateItem {

    private String Currency;
    private String CashBuyRate;
    private String CashSoldRate;
    private String SpotBuyRate;
    private String SpotSoldRate;

    public RateItem(String Currency,String CashBuyRate,String CashSoldRate,String SpotBuyRate,String SpotSoldRate){

        this.Currency = Currency;
        this.CashBuyRate = CashBuyRate;
        this.CashSoldRate = CashSoldRate;
        this.SpotBuyRate = SpotBuyRate;
        this.SpotSoldRate = SpotSoldRate;

    }
    public RateItem(){
        this.Currency = "";
        this.CashBuyRate = "";
        this.CashSoldRate = "";
        this.SpotBuyRate = "";
        this.SpotSoldRate = "";
    }

    public String getSpotSoldRate() {
        return SpotSoldRate;
    }

    public void setSpotSoldRate(String spotSoldRate) {
        SpotSoldRate = spotSoldRate;
    }

    public String getSpotBuyRate() {
        return SpotBuyRate;
    }

    public void setSpotBuyRate(String spotBuyRate) {
        SpotBuyRate = spotBuyRate;
    }

    public String getCashSoldRate() {
        return CashSoldRate;
    }

    public void setCashSoldRate(String cashSoldRate) {
        CashSoldRate = cashSoldRate;
    }

    public String getCashBuyRate() {
        return CashBuyRate;
    }

    public void setCashBuyRate(String cashBuyRate) {
        CashBuyRate = cashBuyRate;
    }

    public String getCurrency() {
        return Currency;
    }

    public void setCurrency(String currency) {
        Currency = currency;
    }
}


  • MainActiviy

這段為擷取資料並放入容器裡,記得要用Thead去處理,不然會跳出錯誤。

◎小小的提醒引用Thead的時,要選對import android.os.Handler,不要選到java的
public class MainActivity extends AppCompatActivity {
    private ListView mListView;
    private Context mContext;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Toast.makeText(this,"onCreate0",Toast.LENGTH_SHORT).show();
        mListView = (ListView)findViewById(R.id.listView);
        //建立Thread

        new Thread(runnable).start();

    }
    private static final String url ="http://rate.bot.com.tw/Pages/Static/UIP003.zh-TW.htm";
    private String UpdateTime;
    private List RateList;
    Runnable runnable = new Runnable(){
        @Override
        public void run() {
          try {
                Document doc = Jsoup.connect(url).get();
                RateList = new ArrayList();
                int i = 0;
                for(Element title : doc.select("td.titleLeft")){
                    RateItem mRateItem = new RateItem();
                  //取得幣別並存入
                    mRateItem.setCurrency(title.text());
                  //匯率為一次四筆所以一次抓出並存入
                    if (i < doc.select("td.decimal").size()){
                    //利用eq()可以指定為第幾筆資料
                 mRateItem.setCashBuyRate(doc.select("td.decimal").eq(i).text());
                 mRateItem.setCashSoldRate(doc.select("td.decimal").eq(i+1).text());
                 mRateItem.setSpotBuyRate(doc.select("td.decimal").eq(i+2).text());
                 mRateItem.setSpotSoldRate(doc.select("td.decimal").eq(i+3).text());
                 i+=4;
                  }

                    RateList.add(mRateItem);
                }
             //更新時間的抓取
               String Temp = doc.select("td[style=width:326px;text-align:left;vertical-align:top;color:#0000FF;font-size:11pt;font-weight:bold;]").text();
             //去處裡字串
               UpdateTime = Temp.substring(12);

            } catch (IOException e) {
                e.printStackTrace();
            }
            //利用handler去更新View
            handler.sendEmptyMessage(0);
        }
    };

    @SuppressLint("HandlerLeak")
    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            setListViewAdapter();

        }
    };
    private TextView UpdateTimeText;
    public void  setListViewAdapter(){
        LayoutInflater inflater = LayoutInflater.from(this);
      
     //include的TextView直接find就能找到了不需要透過inflater建立View
        UpdateTimeText = (TextView)findViewById(R.id.UpdateTimeHeader);
        UpdateTimeText.setText("更新時間:"+ UpdateTime);
     
        mListView.setAdapter(new ListViewAdapter(this,RateList));
 //原本是直接加入header但為了固定位置,所以直接在xml中include header
//View header = inflater.inflate(R.layout.listview_header, mListView, false);
        //mListView.addHeaderView(header, null, false);
}


  • ListAdpater

這裡就是我們自訂的ListView樣式並將資料放入,這次使用Viewhodler來增加執行的效率

public class ListViewAdapter extends BaseAdapter {

    private LayoutInflater inflater;
    private Context mContext;
    private List RateLists;
    public ListViewAdapter(Context mContext,List RateList){
        inflater = LayoutInflater.from(mContext);
        this.mContext = mContext;
        this.RateLists = RateList;
    }

    @Override
    public int getCount() {
        return RateLists.size();
    }

    @Override
    public Object getItem(int i) {
        return RateLists.get(i);
    }
    private static  class ViewHolder{
        TextView CurrencyText;
        TextView CashBuyText;
        TextView CashSoldText;
        TextView SpotBuyText;
        TextView SpotSoldText;
        public ViewHolder(TextView CurrencyText, TextView CashBuyText , TextView CashSoldText,TextView SpotBuyText , TextView SpotSoldText ){
            this.CurrencyText = CurrencyText;
            this.CashBuyText = CashBuyText;
            this.CashSoldText = CashSoldText;
            this.SpotBuyText = SpotBuyText;
            this.SpotSoldText = SpotSoldText;
        }
    }
    @Override
    public long getItemId(int i) {
        return RateLists.indexOf(i);
    }

    @Override
    public View getView(int position, View ConvertView, ViewGroup viewGroup) {
        ViewHolder holder = null;
        if(ConvertView == null){
            ConvertView = inflater.inflate(R.layout.listview_custom,viewGroup,false);
            holder = new ViewHolder(
                    (TextView) ConvertView.findViewById(R.id.CurrencyTextView),
                    (TextView) ConvertView.findViewById(R.id.CashBuyTextView),
                    (TextView) ConvertView.findViewById(R.id.CashSoldTextView),
                    (TextView) ConvertView.findViewById(R.id.SpotBuyTextView),
                    (TextView) ConvertView.findViewById(R.id.SpotSoldTextView)
            );
          //保存狀態避免一直重新建立還要find id
             ConvertView.setTag(holder);

        }else{
         //取出狀態
            holder = (ViewHolder) ConvertView.getTag();
        }
        RateItem mRateItem = (RateItem)getItem(position);
        holder.CurrencyText.setText(mRateItem.getCurrency());
        holder.CashBuyText.setText(mRateItem.getCashBuyRate());
        holder.CashSoldText.setText(mRateItem.getCashSoldRate());
        holder.SpotBuyText.setText(mRateItem.getSpotBuyRate());
        holder.SpotSoldText.setText(mRateItem.getSpotSoldRate());
        return ConvertView;
    }

}




  • listview_custom.xml

※還沒找到一個簡單的方案可以放XML所以都用-取代,抱歉= =!!!!
-?xml version="1.0" encoding="utf-8"?-
-TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:stretchColumns="*"
    android:layout_width="match_parent"
    android:layout_height="match_parent"-

    -TableRow
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="5dp"-

        -TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:text="Text"
            android:padding="3dp"
            android:textSize="12sp"
            android:gravity="left"
            android:id="@+id/CurrencyTextView" -

        -TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:text="Text"
            android:padding="3dp"
            android:gravity="center"
            android:id="@+id/CashBuyTextView" -

        -TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:text="Text"
            android:padding="3dp"
            android:gravity="center"
            android:id="@+id/CashSoldTextView" -

        -TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:text="Text"

            android:padding="3dp"
            android:gravity="center"
            android:id="@+id/SpotBuyTextView" -

        -TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:text="Text"
            android:padding="3dp"
            android:gravity="center"
            android:id="@+id/SpotSoldTextView" -
    -/TableRow-

-/TableLayout-



  • listview.header.xml 

-?xml version="1.0" encoding="utf-8"?-
-TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:stretchColumns="*"-

    -LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="3dp"-

        -TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:text="更新時間:"
            android:gravity="center"
            android:padding="3dp"
            android:id="@+id/UpdateTimeHeader" /-

    -/LinearLayout-

    -TableRow
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="3dp"
        android:padding="5dp"-

        -TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:text=""
            android:padding="3dp"
            android:id="@+id/textView" /-

        -TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:text="現金匯率"
            android:id="@+id/CashRateHeader"
            android:layout_span="2"
            android:layout_gravity="center" /-

        -TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:text="即期匯率"
            android:layout_span="2"
            android:layout_gravity="center"
            android:id="@+id/SpotRateHeader" /-

    -/TableRow-

    -TableRow
        android:layout_width="match_parent"
        android:layout_height="match_parent"-

        -TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:text="幣別"
            android:layout_gravity="center"
            android:id="@+id/CurrencyHeader" /-

        -TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:text="買入"
            android:layout_gravity="center"
            android:id="@+id/CashBuyHeader" /-

        -TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:text="賣出"
            android:layout_gravity="center"
            android:id="@+id/CashSoldHeader" /-

        -TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:text="買入"
            android:layout_gravity="center"
            android:id="@+id/SpotBuyHeader" /-

        -TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:text="賣出"
            android:layout_gravity="center"
            android:id="@+id/SpotSoldHeader" /-

    -/TableRow-

-/TableLayout-



  • activity_main.xml

※這部分最重要就只有固定header所使用的include
-LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
   tools:context=".MainActivity"-
    -include layout="@layout/listview_header"/-
    -ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/listView"
       /-
-/LinearLayout-


最後完成的樣子


























參考連結:
jsoup的範例

http://swind.code-life.info/posts/jsoup.html

http://zhaohaiyang.blog.51cto.com/2056753/735346

透過jsoup解析、抓取網頁上的資料,顯示在APP中http://laeudora.com/iwebinfo/?p=4742

Jsoup Parser HTML Exampleshttp://pclevin.blogspot.tw/2015/03/jsoup-parser-html-examples.html

2015年8月29日 星期六

【Android】簡單實作分享ShareActionProvider

這次利用ShareActionProvider來完成一個簡單的分享,雖說是一個簡單的實作,

但也讓我學了好幾天,先分享一點心路歷程給大家,本來要使用
android.widget.ShareActionProvider,

後來改用android.support.v7.widget.ShareActionProvider的版本,因為我extends ActionBarActivity,使得只能使用support.v7的版本。


  • 首先於meun_main.xml,新增一個item並於item中加入下面這行app:actionProviderClass="android.support.v7.widget.ShareActionProvider"




  • 幾段簡單的code如下,先將 mShareActionProvider建立起來並取得R.id.menu_item_share

private ShareActionProvider mShareActionProvider;
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);

        // Set up ShareActionProvider's default share intent
        MenuItem shareItem = menu.findItem(R.id.menu_item_share);
        mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(shareItem);

        setShareIntent(setIntent());

        return true;
    }



  • setIntent()則是要送出的分享Intent,我們用最簡單傳遞文字來測試

private Intent setIntent(){

        Intent sendIntent = new Intent();
        sendIntent.setAction(Intent.ACTION_SEND);
        sendIntent.setType("text/plain");
        sendIntent.putExtra(Intent.EXTRA_TEXT, "分享的文字");

        
        return sendIntent;
      
    }


  • setShareIntent()這段可以直接搬去上面的onCreateOptionsMenu,來確認mShareActionProvider是否為null並設置ShareIntent

private void setShareIntent(Intent shareIntent) {
      if (mShareActionProvider != null) {
           mShareActionProvider.setShareIntent(shareIntent);
        }
    }


  • 如果想更改icon則要利用以下這段code,actionModeShareDrawable才能更改share icon




結果如下:


























※你會發現ShareActionProvider會將你選取過的app,放置在你的icon右邊,如果想避開目前找到的解答都不是相當完整,後來我用createChooser改變顯示的方式,也希望有找到解答的高手大大們能分享一下。

※在給大家一個關於上面問題的關鍵方法:

  • mShareActionProvider.setShareHistoryFileName("custom_share_history.xml");
只要設為null,其實就會取消上面那個效果,但分享的功能就會產生問題。

google一下會找到幾個方法去解決,一個為下面的 OnShareTargetSelectedListener

http://whutec.sinaapp.com/2012/12/how-do-you-turn-off-share-history-when-using-shareactionprovider/

這也是一個解法,但我資質駑鈍,實在不是很了解 = =!!

http://stackoverflow.com/questions/13395601/android-shareactionprovider-with-no-history

如果哪天找到解法,會再跟大家分享的!!

參考連結:
官網其他範例
http://developer.android.com/intl/zh-tw/training/building-content-sharing.html

ActionBarCompat with ShareActionProvider
http://android-er.blogspot.tw/2013/12/actionbarcompat-with-share.html

如何取得 Android app 的 Package Name 並透過 Intent 發送訊息
http://cloudchen.logdown.com/posts/159965/how-to-find-android-app-package-name-use-to-sent-message-through-intent

How to change icon
http://stackoverflow.com/questions/23846127/android-custom-icon-shareactionprovider

2015年8月7日 星期五

【Android】無法更改action bar backgroud問題


想要更改action bar backgroud的顏色,在google上能夠找到簡單的範例

在style裡利用下面這段code,通常就能夠改變action bar的顏色,但你編譯後會發現並沒有改變,問題出在哪?




答案是:AppCompat
因為使用了AppCompat這個library,所以有版本上的問題

兩個版本的寫法分別是

  • item name = "android:actionBarStyle"
  • item name = "actionBarStyle"
所以我們只要在style中加入,兩種版本的寫法就能夠成功運行

























參考連結:

http://developer.android.com/guide/topics/ui/actionbar.html (官方 請找Example theme有詳細說明)


http://stackoverflow.com/questions/27556031/cant-change-background-colour-of-actionbar

2015年7月11日 星期六

【Android】Android studio 如何新增drawable

如何在Android Studio 中 新增drawable


首先

右鍵點選drawable資料夾 --> new --> Image Asset





















然後

點選進入,並選擇你要新增的圖片檔案



















在drawable的資料夾就會新增你剛剛新增的圖檔了,並且會分別製成不同大小的圖檔,供你使用。


官方所製作的圖檔:
https://www.google.com/design/icons/index.html
官方提供製作圖檔的工具:
http://romannurik.github.io/AndroidAssetStudio/index.html