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