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

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

2015年7月7日 星期二

【Android】Android Studio assets資料夾& fonts 新增外部字型


這次要解決一個簡單的小問題,以前使用Eclipce時有一個assets資料夾,
但使用Android studio時要如何建立這個資料夾?

並且新增完assets資料夾後新增外部字型。


首先

assets資料夾在Android studio中以Android 專案顯示方式來看,是與Manifiest & Java 在同一層


所以

我們直接於 app 右鍵-->new --> folder --> assets 
就能夠找到。


建立起來之後就能在新增fonts資料夾來使用外部字型


將字型檔案放入後就能夠以下面的code來使用外部字型

TextView WebTitleText;
WebTitleText = (TextView) Custom.findViewById(R.id.WebTitleText);
//設定字型
Typeface face = Typeface.createFromAsset(FragmentContext.getAssets(),"fonts/Roboto-Bold.ttf");
WebTitleText.setTypeface(face);


參考網址:
http://stackoverflow.com/questions/18302603/where-to-place-assets-folder-in-android-studio

2015年5月29日 星期五

【Android】ListView 自訂畫面 簡易電話簿

這次要利用ListView來製作一個簡單的電話簿,
主要會用到這兩項知識:
  • ListView
  • BaseAdapter
我的範例主要是搭配fragment_navigation_drawer,所以我會建立在fragment裡,如果你是要寫在Activtiy裡就稍作修改就可以了 ! !

那我們會建立出:
  • myFragmet.java:用於顯示listview
  • PhoneNumberAdpater.java:listview的資料轉接器
  • myfragmet_layout.xml:fragment的layout
  • phonenumber_listview.xml:因為我們要自訂畫面所以要額外使用一個xml來設定我們要的畫面
  • listview_header.xml:來建立出listview的標頭header
  • item_select.xml:放置在drawable底下,用於點選後變色的設定
  • color.xml:放置在value底下用於建立要變的顏色

完成後的畫面:
























以下是code的部分

  • myFragment.java
先建立出需要的資料
String [] Name = new String[]{"陳oo","林oo","溫oo","施oo","胡oo"};
String [] Number = new String[]{"0970135531","0937232323","0928123456","0987987789","0988123423"};

用setAdapter這個方法去將資料送給BaseAdapter
PhoneNumberListView.setAdapter(new PhoneNumberAdapter(getActivity(),Name,Number));

public class Meun1Fragment extends Fragment {

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

}
View RootView;
private ListView PhoneNumberListView;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
RootView = inflater.inflate(R.layout.meun1_fragment,container,false);
//自己塞的資料
String [] Name = new String[]{"陳oo","林oo","溫oo","施oo","胡oo"};
String [] Number = new String[]{"0970135531","0937232323","0928123456","0987987789","0988123423"};
PhoneNumberListView = (ListView) RootView.findViewById(R.id.listView);
//取得header layout
View header = inflater.inflate(R.layout.listviewsms_header, PhoneNumberListView, false);
PhoneNumberListView.addHeaderView(header, null, false);
//自訂layout頁面並利用Baseadater來轉接
PhoneNumberListView.setAdapter(new PhoneNumberAdapter(getActivity(),Name,Number));

//用android本身設計得好的樣式
//ArrayAdapter aa= new ArrayAdapter(getActivity(),android.R.layout.simple_expandable_list_item_1,value);



return RootView;
}
}




  • PhoneNumberAdpater.java
建立出一個轉接器來讓我們能夠自訂listview的呈現方式以及將資料丟給listview


public class PhoneNumberAdapter extends BaseAdapter {
    private LayoutInflater inflater;
    String [] Name;
    String [] Number;
    private Context FragmentContext;
    //建構子
    public  PhoneNumberAdapter (Context FragmentContext, String[] Name, String [] Number){
        inflater = LayoutInflater.from(FragmentContext);
        this.Name = Name;
        this.Number = Number;
        this.FragmentContext = FragmentContext;
    }
    @Override
    public int getCount() {
        return Name.length;
    }

    @Override
    public Object getItem(int i) {
        return null;
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        //利用view去設定我們自訂的layout
        view = inflater.inflate(R.layout.phonenumber_listview,viewGroup,false);
        TextView NameText,NumberText;
        NameText = (TextView) view.findViewById(R.id.textView4);
        NumberText = (TextView) view.findViewById(R.id.textView3);
        NameText.setText(Name[i]);
        NumberText.setText(Number[i]);
        //設置監聽
        view.setOnClickListener(new OnClickListener(Name[i],Number[i]) {});
        return view;
    }
    class OnClickListener implements View.OnClickListener{
        private String Name;
        private String Number;
       //利用建構子取得內容
        public OnClickListener(String Name,String Number){
            this.Name = Name;
            this.Number = Number;
        }
        @Override
        public void onClick(View view) {
            AlertDialog.Builder builder = new AlertDialog.Builder(FragmentContext);
            builder.setTitle(FragmentContext.getString(R.string.callphone_yes_no))
                   .setMessage(Name +"\n"+ Number)
                    .setPositiveButton("撥打", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            Intent call = new Intent(
                                    Intent.ACTION_CALL, Uri.parse("tel:" + Number));
                            FragmentContext.startActivity(call);
                        }
                    })
                    .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {

                        }
                    });
            AlertDialog PhoneCallDialog = builder.create();
            PhoneCallDialog.show();
        }
    }
}




  • item_select.xml
主要用於設定click後變色的狀態,android:state_pressed="true"只要有按下則會去改變畫面的顏色


selector xmlns:android="http://schemas.android.com/apk/res/android">
item android:drawable="@color/lightskyblue" android:state_pressed="true">
item android:drawable="@android:color/transparent">
/item>


並且要記得在phonenumber_listview.xml上增加 android:background="@drawable/item_select"才會改變


linearlayout
xmlns:android="http://schemas.android.com/apk/res/android">
android:background="@drawable/item_select"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="horizontal"

參考連結:

ListView+BaseAdapter應用 I ─ onLongClick與Clipboard

http://a6350202.pixnet.net/blog/post/241188445-%E3%80%90android%E3%80%91listview%2Bbaseadapter%E6%87%89%E7%94%A8-i-%E2%94%80-onlongclick%E8%88%87














2015年5月10日 星期日

【JAVA】String的內容值不可變

我們來探討一下關於String的內容指與比較



String s = "DOG";
s ="CAT";

在我們看來值好像改變了,但其實他並不是改變值,

因為String是一個參考類別,賦予他值後,他是將 s 指向 "DOG"這個這個實體,

當你又賦予了一個新的值"CAT", s 是直接重新指向"CAT"的實體,並非將DOG實體改為CAT


改變的是位址並不是實體!!!!



這就是所謂 String的內容值不可變 的意思。


延伸思考一:



既然String s 是指向位置

那麼當

String str1 = new String("Dog");
String str2 = new String("Dog");

System.out.println(str1 == str2);

會回傳甚麼?

答案是:false
因為他們指向的是不同的位置,用 == 是在比較str他們的值,而他們的值都是位置並非字串,所以當你使用 == 來做比較字串會發生錯誤!!!!

要利用equals()這個方法才能比較字串。



延伸思考二:

那麼當


String str1 = "Dog";
String str2 = "Dog";

System.out.println(str1 == str2);

會回傳甚麼?

答案是:true


因為我們是直接指向相同的字串,而在Java中有一個
StringPool他會先去找是否有相同的字串,有的話直接指向,不在重新創造實體出來。

如果你想先檢查是否在
StringPool有相同字串,你可以利用intern()這個方法。


範例:(取自良葛格blog)

public class StringIntern { 
    public static void main(String[] args) { 
        String str1 = "fly"; 
        String str2 = "weight"; 
        String str3 = "flyweight"; 
        String str4; 

        str4 = str1 + str2; 
        System.out.println(str3 == str4); 
        //false
        str4 = (str1 + str2).intern(); 
        System.out.println(str3 == str4); 
       //true
    } 
} 


參考連結:http://openhome.cc/Gossip/JavaGossip-V1/ImmutableString.htm

2015年3月30日 星期一

【Android】Widget製作時鐘

這次要來用Widget來製作一個小時鐘,主要會用到下面幾個項目知識

  • Widget
  • Handler
  • Service
我們的目標是顯示現在的時刻
Ex : 2015/05/12 17:00

需要在code裡不斷的重新更新時間,下面這段code就是new出一個新的時間並設定我們需要的格式。

new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss" ).format( new Date())

在Widget的部分主要是要intent Service交由Service去處理我們的每秒更新與背景。

Widget.java

public class SmsWidget extends AppWidgetProvider {
   
    Context context_main ;
    AppWidgetManager app_manager;
    int []appWidgetId;
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
       
        
        app_manager = appWidgetManager;
        context_main = context;
        appWidgetId = appWidgetIds;

       //new出一個 intent並將Widget的context傳入
        Intent intent = new Intent(context_main,WidgetService.class);
 //Intent執行service服務
context_main.startService(intent);


    }

    @Override
    public void onEnabled(Context context) {
       
    }

    @Override
    public void onDisabled(Context context) {
        //當WidgetDisable時關閉service服務
        Intent intent = new Intent(context_main,WidgetService.class);
        context_main.stopService(intent);
    }
}


那我們要如何不斷的new出新的時間並更新widget的view ?
其實只要用handler來處理即可,並搭配Service讓code在背景執行,執行一次就更新一秒。


Service.java

public class WidgetService extends Service {
    private Handler mHandlerBoss = null;
    private HandlerThread mHandlerEmployee = null;
    private String EmployeeName = "John";
    public WidgetService() {
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //service結束,結束handler
        mHandlerBoss.removeCallbacks(mRunnable);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //建立Handler
        //Handler簡單來說就是需要老闆、員工、工作
        //建立一個員工
        mHandlerEmployee = new HandlerThread(EmployeeName);
        //員工上班
        mHandlerEmployee.start();
        //建立一個老闆,老闆聘員工上班
        mHandlerBoss = new Handler(mHandlerEmployee.getLooper());
        //老闆指派工作給員工
        mHandlerBoss.post(mRunnable);
        return super.onStartCommand(intent, flags, startId);
    }
    private Runnable mRunnable = new Runnable() {
        @Override
        public void run() {
            //更新Widget畫面
            buildUpdate();
            //每秒跑一次
            mHandlerBoss.postDelayed(this,1000);
        }
    };
    private void buildUpdate()
    {
        
        RemoteViews view = new RemoteViews(getPackageName(), R.layout.sms_widget);
        view.setTextViewText(R.id.appwidget_text, new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss" ).format( new Date()));

        ComponentName thisWidget = new ComponentName(this, SmsWidget.class);

        AppWidgetManager manager = AppWidgetManager.getInstance(this);

        manager.updateAppWidget(thisWidget, view);
    }
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

編譯成功後就能夠在,手機裡將Widget拉出來使用。

參考連結:
Widget Update http://stackoverflow.com/questions/4866305/android-widget-update
背景執行 http://cooking-java.blogspot.tw/2010/04/android-service.html



【Android】如何新增分隔線於layout中


在html中常見的分隔線,於android layout中要如何設置



相當簡單於xml檔中加入以下的code即可顯示出一條分隔線

<view
   android:background="#000000"
   android:layout_height="2dp"
   android:layout_width="fill_parent"
</view>






參考:

2015年3月28日 星期六

【Android】Widget 簡單範例



Widget就是在手機上常看到的小工具,可以放入主頁,使用Android Studio就可以簡單的建立一個Widget。

一、

建立一個project就照之前的方式建立起來,在選擇Activity的地方可以選擇add no ,就是不建立Activity。


二、

在java->你的package上點選右鍵,找到New新建一個Widget,











其中分別有
  • Class Name (名稱)
  •  Placement(放置位置)
    • Home screen (手機畫面位置) 
    • Keyguard(手機解鎖位置) 
    •  Home screen & Keyguard (兩者皆可)
  •  Resizable (是否能夠調整大小)
         ※放置桌面後是否能夠調整大小
  •  Width&Height(桌面佔用大小)

就依造自己的需求選擇,完成後按下FINSH,Android Studio就會幫你建立起來。



三、

建立後會看到新增了三項東西,分別是:
  • NewAppWidget.java 
  • NewAppWidget.xml (Widget介面設計)
  • NewAppWidget_Widget.info.xml (Widget的資訊)


參考連結:







【Android_Error】error: Handler is abstract; cannot be instantiated


在使用Android Studio寫Handler時,一直出現這個錯誤,後來發現是Android Studio自動import錯誤的package。



Android Studio import

  • import java.util.logging.Handler;
但應該是要使用
  • import android.os.Handler;
所以將import修正一下錯誤就消失了

大家參考參考


參考連結:

2015年3月4日 星期三

【Android】XML中android:layout_gravity與android:gravity的差別


android:layout_gravityandroid:gravity這兩者的區別在於,一個影響的是物件對layout的反應,另一個則是物件對自身text的反應

舉例來說:
現在我們有一個Linearlayout及一個button,分別為layout與view


  • android:layout_gravity="center"
當你對button寫這個code代表,他會以Linearlayout為主,整個button對Linearlayout置中。
  • android:gravity="center"
這個code則是會使button內的text置中。

所以當我們想要讓view在layout裡置中則使用

  • android:layout_gravity="center"

當我們希望是button裡text置中則使用
  • android:gravity="center"

所以在android裡
android:layout_xxxxx屬性,是使view與layout做控制
android:xxxxx屬性,則是針對view內部的屬性做控制








參考:http://fecbob.pixnet.net/blog/post/39312567-android%3Agravity-%E5%92%8C-android%3Alayout_gravity