2019年2月9日 星期六

【Python】寫入讀出資料到Google sheet 試算表


今天來介紹如何使用Python寫入Google Sheet的方法


整個流程很單純,只是新手比較常碰到GOOGLE設定上的問題

一、先到 Google Developers Console 建立一個 Project


  • 先於左上方新增專案

  • 為專案命名
  • 啟用完成





二、啟用專案的 Sheet API

  • 點選【啟用API和服務】


  • 搜尋Sheet API並點選啟用



三、為API建立憑證

  • 於上方有提示訊息,直接點選建立憑證

  • 點選後會看到下述畫面


共有4個選項

Q.您目前使用哪個 API?

選擇 Google Sheet API

※假設今天使用其他的API就選其他的(廢話)

Q.API 的呼叫來源為何?
選擇 其他非使用者介面

※因為我們使用Pyhon如今天採用其他的方式呼叫就選別的了

Q.您需要存取什麼資料?
選擇 應用程式資料

使用者資料比較像是登入註冊等等時來使用

Q.您準備搭配 App Engine 或 Compute Engine 使用此 API 嗎?

選擇 否

※如果有搭配到GAE可以選


選擇完成後就點選取得憑證
  • 會跳轉至下列畫面



我們就為服務帳戶命名

※這個服務帳戶就類似你專案的一個帳戶,可以用來管理你的API憑證你也可以設置他的權限等等..

金鑰類型選擇JSON格式

完成後點選下載

將下載的json檔案放入待會Python專案目錄下

  • 檔案打開會有類似資訊,先將client_email複製起來


  • 我們建立一個sheet並且與剛剛複製的client_email一起共用





繁瑣的設定完成 ! 剩下程式的部分 

三、Python透過憑證連線

自訂一個函式為auth_gss_client


import gspread
import time #待會會取時間
from oauth2client.service_account import ServiceAccountCredentials 


auth_json_path = 'auth.json' #由剛剛建立出的憑證,放置相同目錄以供引入
gss_scopes = ['https://spreadsheets.google.com/feeds'] #我們想要取用的範圍
gss_client = auth_gss_client(auth_json_path, gss_scopes) #呼叫我們的函式


def auth_gss_client(path, scopes):
    credentials = ServiceAccountCredentials.from_json_keyfile_name(path, scopes)
    return gspread.authorize(credentials)


#從剛剛建立的sheet,把網址中 https://docs.google.com/spreadsheets/d/〔key〕/edit 的 〔key〕的值代入 
spreadsheet_key_path = '〔key〕'

#我們透過open_by_key這個method來開啟sheet
sheet = gss_client.open_by_key(spreadsheet_key_path).sheet1
#單純取出時間稍後塞入sheet
today = time.strftime("%c")
#透過insert_row寫入值 第二行塞入時間,abc,123的值
sheet.insert_row([today,"abc", 123], 2)


以上完成 !!    有任何問題歡迎留言發問

有錯誤也請提醒  感謝



常見錯誤:

ImportError: cannot import name 'ServiceAccountCredentials'

一開始我不知道為何取用到1.5.2的版本導致他根本找不到ServiceAccountCredentials

解法如下:

●先確認目前OAuth版本

可透過下列程式碼顯示
import oauth2client
print (oauth2client.__version__)

●透過cmd再次更新版本 pip install --upgrade oauth2client





參考文章:

https://city.shaform.com/zh/2016/03/19/gspread/

Python大數據特訓班電子書

2019年1月7日 星期一

【PHP】codeigniter 使用faker libs 自動產生假資料

在製作網頁時,常常需要一些假資料去填滿你的內容,

但要耗費一些時間在生成那些無意義的假資料,

所以我們這次要學習利用faker這個libs去自動產生假資料 !!

需要環境


PHP就不用說,那我們使用的framework是codeigniter

如果沒有使用過的朋友,可以參考我另一篇文章

Composer 這是給PHP使用的一個套件管理系統

如果未來要學PHP那建議要去了解這套系統

最後就是Faker這個libs 上面有附上他的github


那我們就開始!!!!

首先


先建立一個codeigniter專案,然後開啟cmd利用指令cd

到你放置codeigniter專案的資料夾

像我是利用iis所以放置在C:\inetpub\wwwroot底下

所以就簡單的 cd C:\inetpub\wwwroot

簡單來講就是兩個步驟
  1.  cd 到codeigniter資料夾下
  2. composer require fzaninotto/faker


然後等待一下  !  要一點時間

我一直以為他當了其實沒有

那他就會幫你把composer.json這個檔案裡加入fzaninotto/faker這個libs

再來

開啟codeigniter專案裡的index.php 拉到最下面加入include_once './vendor/autoload.php';







2015年12月6日 星期日

【心得】2015 JCConf 菜鳥參與心得


2015年12月4日、5日,首次參加JCConf的聚會,收獲很多的,尤其以第一次參加這種盛會的我來說。

那麼我就以個超級菜鳥的身分來談談,JCConf到底是在辦甚麼在講甚麼內容


甚麼是 JCConf ?



字面上來看就是 Java Community Conference Taiwan 


是由社群主辦的 Java 開發者年會,以提供更多機會讓開發人員之間能夠互相交流。


包含了甚麼議題 ?

分享內容的程度不論初階到進階

  •  Java 程式語言
  • 框架
  • JVM 及虛擬化相關技術
  • 移動裝置
  • 開發工具
  • 開發流程
  • 等等...

議程表:

反正只要與Java有關,都包含就對了 !!!

所以對於我這種菜鳥來說,很多東西都是第一次聽到,增廣見聞。

但也就因為包含太多東西,許多議題都是鴨子聽雷,有聽沒有懂啊@@,實在是太菜了


有興趣可以去看看兩天的議程。


議題分享的模式


可以看到基本上每天的第一場,都是在同一個會場,通常就是一個大神來分享,

然後接下來就分為三個會場,去各自選擇自己想要參加的議題,

那如果都想要聽怎麼辦!!  沒關係基本上的議題都會有綠影,可能等會後再去看綠影,

所以可以先參加那些無法錄影的議題。

WorkShop這也是很酷的地方,能夠直接實作帶你認識一項新的技術,

但如果要參加記得要事先報名,不然現場只能等候補了 !!

線上筆記與多人討論

這也是讓我覺得,不愧是工程師的盛會,很多東西都靠網頁就能夠解決。

  • Hackpad 線上多人共同編輯


有時候想要記筆記,但卻來不及,怎麼辦!! 沒關係 會方使用了Hackpad,讓大家能夠一同

去編輯出一份議題的筆記,所以只要你手速夠快,都能夠去協助筆記的建立,

而且是同步建立,非常的酷啊。

這次的Hackpad議題共筆: https://jcconf.hackpad.com/JCConf-2015--9EqN5Txh9yR

裡面就能看到有很多議題講者的重點筆記,這都是每位參與者一起編輯出來的哦 !


  • Giiter 多人討論

議題好深入,根本聽不太懂 怎麼辦 !!!  沒關係 有人與一起線上討論議題,

其實對於菜鳥來講基本上大概70%都聽不懂,不過還好有多人討論,

可以看一下與大家交流一下就能大概知道這個議題到底在說些甚麼,用在哪裡等等...

這個多人討論也讓我多學到很多,不僅僅是鴨子聽雷。

這次的 Giiter多人討論: https://gitter.im/twjug/jcconf




所以參加要帶甚麼?

  • 筆電

 不管是多人共筆或多人討論,

在聽一些議題時也比較能夠快速查相關的資料。

  • 海綿的腦袋   大量吸收吧!!!!


不管到底聽不聽的懂,其實都可以記下一些關鍵字,

大概去了解一下,這到底在做些甚麼,何時會用到,

或許等你長大後的某一天會用到也說不定。


如何參加 ?


大概在前兩個月就會有售票的資訊會出來,

直接購買就可以囉 !!  

提早購買有早鳥優惠



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