搜尋此網誌

2015年12月11日 星期五

google 地圖搜尋 api 鄰近地點地方資訊搜尋

在之前的
在 Android 上加上搜尋地理位置的功能 Google Places API (地方資訊挑選器 PlacePicker )
這篇我們有提到, PlacesPicker 雖然方便但是有使用上的限制,其實 1,000 次的使用量可是一下子就用完了呢!所以官方也推薦我們直接用 JavaScript 的 API 或是 http 的 API 來使用。

這些也都是有使用限制的,不過 http 的限制額度是算在使用者自己的額度上而不是以我們的 APP 來計算所以相對非常足夠。

API 文件連結

首先我們仍然是要去申請一支api金鑰 (因為和 Android 使用的不同權限所以要另外申請喔)

接著就是重頭戲了:api 輸入和輸出的值就不解釋了,請看官方文件,有超清楚的中文範例。

要注意的有幾點:

  • 這個 API 只有接受 HTTP GET 不接受 POST
  • 經緯度是必填所以在呼叫這支 API 前要搭配 Android 取得經緯度範例 服用
下面是範例:

public class SearchPoi  extends AppCompatActivity {
    AQuery aQuery = new AQuery(this);
    private static final String TAG = "LocationActivity";
    GPSTracker gps;

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

        // 宣告使用 GPSTracker
        gps = new GPSTracker(this);
        if(gps.canGetLocation()){
            //取得經緯度
            double latitude = gps.getLatitude();
            double longitude = gps.getLongitude();
            //設定API
            String ListApi = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?key="+getString(R.string.web_api_key)+"&radius=500&location=" + latitude +","+ longitude;
            
            // 呼叫 API
            aQuery.ajax(ListApi, null, JSONObject.class, new AjaxCallback() {
                @Override
                public void callback(String url, JSONObject object, AjaxStatus status) {
                    super.callback(url, object, status);
                    System.out.println("===url===" + url);
                    System.out.println("==obj==" + object);
                    System.out.println("=status=" + status);


                    try {
                        //取得地理位置名稱
                        for(int i = 0;i<=object.getJSONArray("results").length();i++){
                            Log.e("results name",object.getJSONArray("results").getJSONObject(i).getString("name"));
                        }
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                }
            });
        }else{
            Toast.makeText(this,"error",Toast.LENGTH_SHORT).show();
        }
        

    }

}

2015年12月8日 星期二

Android 取得經緯度範例

這次寫的東西有點偷懶,是從別人家的範例拿下來呼叫的
Android GPS, Location Manager Tutorial

不過這樣可以很快的取得經緯度,所以我們還是介紹一下吧!

首先我們先到上面的網址下載這個檔案



解壓縮以後去找到 GPSTracker.java 這個檔案放到自己的專案底下。


接著就可以開始實作了,我們需要開啟以下的權限:

  • ACCESS_FINE_LOCATION
  • INTERNET

接著只要在自己的 Code 裡面去呼叫


    GPSTracker gps;
        gps = new GPSTracker(this);
        if(gps.canGetLocation()){

            double latitude = gps.getLatitude();
            double longitude = gps.getLongitude();

            
            Toast.makeText(getApplicationContext(), "Your Location is - \nLat: " + latitude + "\nLong: " + longitude, Toast.LENGTH_LONG).show();
        }else{
            Toast.makeText(this,"error",Toast.LENGTH_SHORT).show();
        }

就可以啦!實在是太偷懶啦~~

2015年12月7日 星期一

在 Android 上加上搜尋地理位置的功能 Google Places API (地方資訊挑選器 PlacePicker )

google 擁有大量的店家資料以及地圖的圖資。如果不拿來運用是不是太可惜了呢?
其實 google 有提供 API 給各個平台來做串接的動作


在使用之前我們仍然需要取得憑證簽署 API 金鑰。這個部分官方寫得很詳盡我們直接看即可。
簽署與 API 金鑰

除此資外我們要在 Google Developers Console 申請 Google Places API for Android 的使用權限。這個 API 是有配額的 一天只能接受 1,000 次的查詢,如果是已經綁定信用卡的話可以增加到 150,000 次查詢。接下來應該就是要付費了吧。

開始進入正題:

這篇我們先來一個超簡單的:PlacePicker 他是經由 Intent 動作就可以呼叫的,連 UI 都不用我們自己建立。當我們呼叫後就會自動進入下面這個畫面:

包含了地圖,現在位置,周邊店家 通通都有了




AndroidManifest.xml

增加 ACCESS_FINE_LOCATION 權限
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

Activity上建立進入地圖的動作:

private static final int REQUEST_PLACE_PICKER = 1;


PlacePicker.IntentBuilder intentBuilder = new PlacePicker.IntentBuilder();
                Intent intent;
                try {
                    intent = intentBuilder.build(StoreAdd.this);
                    startActivityForResult(intent, REQUEST_PLACE_PICKER);
                } catch (GooglePlayServicesRepairableException | GooglePlayServicesNotAvailableException e) {
                    e.printStackTrace();
                }

Activity上建立回傳資料後的動作:

   @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_PLACE_PICKER){
            if (resultCode == RESULT_OK){
                Place place = PlacePicker.getPlace(data, this);

                Log.e("place", place.toString());

            }
        }
    }

如此一來當使用者點選地圖頁面上面的地點名稱後,就會回傳該地點的資料到 onActivityResult 的 Log.e 裡面。

雖然這個作法做起來超快速,但是卻不是 google 最推薦的做法。根據 google 文件上面的說法。如果我們只是要取得資料,沒有打算讓使用者在我們的 APP 上面直接建立資料給 google 其實使用 http 的 web-service 就可以摟!不過這樣的話 UI 就要很辛苦的自己做摟。

2015年12月3日 星期四

RecyclerView 加上 OnClickListener 事件監聽

繼上一篇
Android RecyclerView 簡單教學範例 後我們可以順利的顯示出 RecyclerView 的清單畫面。但是顯示出清單總是要被按的吧!應該是。

所以我們要在裡面加上 OnClickListener 的事件監聽動作。

找到 MyAdapter.java 裡面的 onBindViewHolder:


@Override
    public void onBindViewHolder(MyAdapter.ViewHolder holder, final int position) {
//            設定文字 textView 的文字為 itemsData[position].getTitle()
            holder.textView.setText(itemsData[position].getTitle());
//        設定 textView 被點擊監聽
            holder.textView.setOnClickListener(new View.OnClickListener() {
//                被點擊的動作
                @Override
                public void onClick(View v) {
//                    取得是幾個項目
                    Log.e("position", String.valueOf(position));
//                    取得點下去的那個項目的文字內容
                    Log.e("text", itemsData[position].getTitle());
                }
            });
    }


這樣就可以啦!

2015年11月26日 星期四

Android RecyclerView 簡單教學範例

RecycleView是一種進化版的 ListView 詳細的特點因為介紹很多我就先跳過了,我們來實作吧

要準備的材料有:

RecyclerView 範例檔 github 下載

Java檔案

  • MainActivity.java
  • MyAdapter.java
  • ItemData.java

View檔案

  • activity_main.xml
  • item_layout.xml

Gradle

  • compile 'com.android.support:recyclerview-v7:23.1.1'



遊戲開始: 

Layout


activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="match_parent"
    tools:context="com.hmkcode.android.recyclerview.MainActivity" >
 
    <android.support.v7.widget.RecyclerView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity"
    />
</RelativeLayout>


item_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="80dp"
    android:background="@drawable/border"
    >
   <TextView
         android:id="@+id/item_title"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
          />
</RelativeLayout>


JAVA

MainActivity.java
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //  宣告 recyclerView
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        
        // 設定要給 Adapter 的陣列為 itemsData
        ItemData itemsData[] = {
                new ItemData("hello1"),
                new ItemData("hello2"),
                new ItemData("hello3"),
        };
        
        MyAdapter mAdapter = new MyAdapter(itemsData);

        // 將 mAdapter 交給 recyclerView 顯示
recyclerView.setAdapter(mAdapter); recyclerView.setItemAnimator(new DefaultItemAnimator()); }

這邊我們可以發現我們需要用到兩個 class ,分別是 ItemData 和 MyAdapter

ItemData.java
public class ItemData {
    private final String title;

    public ItemData(String title) {
        this.title = title;
    }
    public String getTitle(){
        return title;
    }
}
在上一個動作中,我們將陣列傳進去給 ItemData 。就是在 public ItemData(String title) 這邊去做接取的動作。如果每一個 ItemData 有兩個欄位的話就會是要做成 public ItemData(String key的名稱,String 第二個key的名稱)


MyAdapter.java
public class MyAdapter extends RecyclerView.Adapter {
    private ItemData[] itemsData;
    public MyAdapter(ItemData[] ItemData){ //這邊是接 MainActivity 傳進來的值
        this.itemsData = ItemData;
    }



    @Override
    public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, null);
        ViewHolder viewHolder = new ViewHolder(itemLayoutView);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(MyAdapter.ViewHolder holder, int position) {
            // 設定 textView 的文字由 itemsData 取出,而 itemsData 的內容已經在 ItemData.java 設定好了
            holder.textView.setText(itemsData[position].getTitle());

    }

    @Override
    public int getItemCount() {
        // 顯示的數量
        return itemsData.length;
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        public TextView textView;
        public ViewHolder(View itemView) {
            super(itemView);
        // 設定 textView 為 item_title 這個 layout 物件
textView = (TextView) itemView.findViewById(R.id.item_title); } } }

大功告成!


下一篇我們將會讓這個 RecyclerView 的清單可以執行點擊動作

2015年11月6日 星期五

Android 讀秒後自動執行換頁

這個功能通常我們會用在首頁做歡迎的動作


final android.os.Handler handler = new android.os.Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                startActivity(new Intent(Welcome.this, MainActivity.class));
            }
        },1000);

這個功能包含了使用 Handler 的 postDelayed 執行等待一段時間後進行動作,以及轉頁。
轉頁這個功能就請參閱
http://wolf-android.blogspot.tw/2012/11/android-intent.html


2015年11月5日 星期四

Android 實現 google 登入 (1) 準備 & 版面

官方技術文件網址如下
https://developers.google.com/identity/sign-in/android/

要實現這個功能之前要準備的有:
載入 play-services 

設定 AndroidManifest.xml

        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />





向 google 申請使用權限
https://developers.google.com/mobile/add


我們這次要使用的就是 google Sign-in 這個功能。
原則上就是一步一步走下去即可
到最後他會需要你將自己的 keysotre 中取得sha1的金鑰 ,這個有很多教學就不贅述了。
可以參考下面的連結:
http://nosyandroid.blogspot.tw/2015/10/android-get-keytool-sha1.html

最後面他會請你下載一個  json 的設定檔,我實驗了一下其實沒啥用(沒去管他也可以運作)。

我們這一篇先討論一下版面 要把 google 登入的 icon 放進來

只需要再 layout 裡面放上
<com.google.android.gms.common.SignInButton
        android:id="@+id/sign_in_button"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"/>


就可以長出登入按鈕,順便我們在補個登出的按鈕吧

<Button
        android:id="@+id/sign_out_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:layout_below="@+id/sign_in_button"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignRight="@+id/sign_in_button"
        android:layout_alignEnd="@+id/sign_in_button"
        android:text="sign out btn" />


2015年10月28日 星期三

Android 側邊滑入選單 NavigationView


這個選單功能方便的,可以一次收納很多工具在旁邊又不占空間。
首先要準備的材料有:

gradle 的部份
compile 'com.android.support:design:23.1.0'


版面配置會長這樣:
我們要在 res/layout/mainactivity.xml 裡面設定需要側邊選單然後分別載入側邊選單的上半部和下半部選單部分:

<android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_main"
        app:menu="@menu/activity_main_drawer"
        />


新增 res/layout/nav_header_main.xml (其實沒有也沒差)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="@dimen/nav_header_height"
    android:background="@drawable/side_nav_bar"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:theme="@style/ThemeOverlay.AppCompat.Dark" android:orientation="vertical"
    android:gravity="bottom">

    <ImageView android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:src="@mipmap/ic_launcher"
        android:id="@+id/imageView" />

    <TextView android:layout_width="match_parent" android:layout_height="wrap_content"
        android:text="Android Studio"
        android:textAppearance="@style/TextAppearance.AppCompat.Body1" />

    <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="android.studio@android.com" android:id="@+id/textView" />

</LinearLayout>



新增  res/menu/activity_main_drawer.xml
這是每個功能的清單:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="single">
        <item android:id="@+id/nav_camara" android:icon="@android:drawable/ic_menu_camera"
            android:title="Import" />
        <item android:id="@+id/nav_gallery" android:icon="@android:drawable/ic_menu_gallery"
            android:title="Gallery" />
        <item android:id="@+id/nav_slideshow" android:icon="@android:drawable/ic_menu_slideshow"
            android:title="Slideshow" />
        <item android:id="@+id/nav_manage" android:icon="@android:drawable/ic_menu_manage"
            android:title="Tools" />
    </group>

    <item android:title="Communicate">
        <menu>
            <item android:id="@+id/nav_share" android:icon="@android:drawable/ic_menu_share"
                android:title="Share" />
            <item android:id="@+id/nav_send" android:icon="@android:drawable/ic_menu_send"
                android:title="Send" />
        </menu>
    </item>
</menu>


接下來就是 activity 的部份了
要呼叫出來只需要:
        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(MainActivity.this);

接著去設定點下去後的行為:
@Override
    public boolean onNavigationItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.nav_camara) {
            // Handle the camera action
            Toast.makeText(MainActivity.this,"carara",Toast.LENGTH_SHORT).show();
        } else if (id == R.id.nav_gallery) {

        } else if (id == R.id.nav_slideshow) {

        } else if (id == R.id.nav_manage) {

        } else if (id == R.id.nav_share) {

        } else if (id == R.id.nav_send) {

        }

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drw_layout);
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }

2015年10月27日 星期二

新增 android 上的浮動按鈕 FloatingActionButton ( Layout篇 )

有些功能我們很常會用到,如果每一個頁面都特別還去主選單裡面點選的話其實挺麻煩。
現在有一種 button 的形式叫做 FloatingActionButton 他可以讓你有個按鈕一直浮在上面
首先,在 gradle 的部份我們要加上

compile 'com.android.support:design:23.1.0'

然後到要加上的頁面 xml上加入:
 <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:src="@drawable/ic_note_add_white_24dp"
        style="@style/floating_action_button"
        app:elevation="6dp"
        app:pressedTranslationZ="12dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentEnd="true" />

styles.xml 也加一下樣式好了:
 <style name="floating_action_button">
        <item name="android:layout_marginLeft">0dp</item>
        <item name="android:layout_marginTop">0dp</item>
        <item name="android:layout_marginRight">16dp</item>
        <item name="android:layout_marginBottom">16dp</item>
    </style>


google 有提供 Marerial icon 的圖檔下載
https://www.google.com/design/icons/

2015年10月23日 星期五

android 儲存使用者設定值 SharedPreferences

有一些簡單的設定資料我們會需要記在 app 的本地端,可是又不需要用到資料庫那麼麻煩。例如簡易的登入,系統環境設定,或是判斷是不是第一次進來之類的。
這時候我沒可以用 SharedPreferences 這個功能來搞定。

儲存
//建立SharedPreferences物件
        SharedPreferences.Editor sh = PreferenceManager.getDefaultSharedPreferences(this).edit();
        sh.putString("PValue", "Hello");
        sh.commit();


讀取
String GetPV = PreferenceManager.getDefaultSharedPreferences(this).getString("PValue","A");

清除記錄
//建立SharedPreferences物件
        SharedPreferences.Editor sh = PreferenceManager.getDefaultSharedPreferences(this).edit();
        sh.clear();
        sh.commit();

2015年10月22日 星期四

關閉 android 的系統通知列(全螢幕模式)

話說
早期的 android 軟體都會有兩個部分很礙眼
其中一個就是一直在最上面顯示時間和通知的系統列
只要加上一小段


getWindow().setFlags(WindowManager.LayoutParams. FLAG_FULLSCREEN ,
                WindowManager.LayoutParams. FLAG_FULLSCREEN);

2015年10月14日 星期三

android 利用 android-query 取得外部API 的 JSON 內容

前端的程式如果需要接外部的資料庫,在 html 中我們通常會用  jQuery 的 ajax 功能來完成。
在 Android 中可以使用 GSON 來接,不過現在要介紹的是 android query 我們簡稱 AQ。

我們可以在這邊看到相關的資料
https://code.google.com/p/android-query/

https://github.com/androidquery/androidquery/releases/tag/0.26.8


AQuery aQuery;

aQuery  = new AQuery(this);
String api_url = "API路徑";
aQuery.ajax(api_url,null, JSONObject.class,new AjaxCallback(){
    @Override
    public void callback(String url, JSONObject object, AjaxStatus status) {
        super.callback(url, object, status);
        Log.e("---------",object.toString());
    }
});

有一件事情很重要,很容易忘記(我是說我)就是要把 Internet 的權限打開,不然什麼事情都不會發生也不會閃退。