顯示具有 Android Studio 標籤的文章。 顯示所有文章
顯示具有 Android Studio 標籤的文章。 顯示所有文章

2015年11月21日 星期六

Android Google Map應用 - 使用Android Studio

這裡展示了在Android中使用Google Map的幾個簡單應用:

  1. 貼圖標 (自定內容不含外框、自定樣式含內容和圖標)
  2. 繪置線
  3. 繪置面(區域)
直接看程式碼:

MainActivity.java :

package com.example.gjun.googlemapmarkerpractice;

import android.graphics.Color;
import android.media.Image;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polygon;
import com.google.android.gms.maps.model.PolygonOptions;
import com.google.android.gms.maps.model.PolylineOptions;

public class MainActivity extends ActionBarActivity {
    private GoogleMap map;
    private LinearLayout info_panel;
    private TextView info;
    private Marker myMarker1;
    private Marker myMarker2;

    //設定地圖中心點
    private static final LatLng mapCenter = new LatLng(25.051234, 121.538315);

    // 繪製線條用的座標
    private static final LatLng station01 = new LatLng(25.04657, 121.51763);
    private static final LatLng station02 = new LatLng(25.044937, 121.523037);
    private static final LatLng station03 = new LatLng(25.042293, 121.532907);
    private static final LatLng station04 = new LatLng(25.051702, 121.532907);
    private static final LatLng station05 = new LatLng(25.05971, 121.533251);

    // 繪製區塊用的座標
    private static final LatLng station06 = new LatLng(25.062354, 121.541061);
    private static final LatLng station07 = new LatLng(25.041671, 121.5378);
    private static final LatLng station08 = new LatLng(25.04136, 121.557713);
    private static final LatLng station09 = new LatLng(25.063054, 121.552048);

    private Marker marker01, marker02, marker03, marker04, marker05;

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

        ///取得GoogleMap物件
        if (map == null) {
            map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
        }
        //移動到地圖中心
        CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(mapCenter, 13);
        map.moveCamera(cameraUpdate);

        //--------------------------繪制圖標--------------------------
        MarkerOptions markerOptions1 = new MarkerOptions();
        markerOptions1.position(station01)
                .icon(BitmapDescriptorFactory.fromResource(R.drawable.train));
        myMarker1 = map.addMarker(markerOptions1);

        MarkerOptions markerOptions2 = new MarkerOptions();
        markerOptions2.position(station05)
                .icon(BitmapDescriptorFactory.fromResource(R.drawable.taipei_101_marker));
        myMarker2 = map.addMarker(markerOptions2);
        myMarker2.setDraggable(true);
        //設置圖標的氣泡顯示訊息樣式
        map.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
            @Override
            //自訂樣式,連外框
            public View getInfoWindow(Marker marker) {
                if (marker.equals(myMarker2)) {
                    //從指定的畫面layout檔建立訊息視窗畫面物件
                    View view = getLayoutInflater().inflate(R.layout.info_window, null);
                    //說定圖示、標題和說明
                    ImageView badge = (ImageView) view.findViewById(R.id.badge);
                    TextView title = (TextView) view.findViewById(R.id.title);
                    TextView snippet = (TextView) view.findViewById(R.id.snippet);

                    badge.setImageResource(R.drawable.roc_flag);
                    title.setText("This is title!");
                    snippet.setText("This is snippet");

                    ///傳回自訂的訊息視窗
                    return view;
                }
                return null;
            }

            //自訂樣式,不連外框,只有內容
            @Override
            public View getInfoContents(Marker marker) {
                if (marker.equals(myMarker1)) {
                    //從指定的畫面layout檔建立訊息視窗畫面物件
                    View view = getLayoutInflater().inflate(R.layout.info_content, null);
                    //說定圖示、標題和說明
                    ImageView badge = (ImageView) view.findViewById(R.id.badge);
                    TextView title = (TextView) view.findViewById(R.id.title);

                    badge.setImageResource(R.drawable.train);
                    title.setText("This is title!");

                    ///傳回自訂的訊息內容
                    return view;
                }
                return null;
            }
        });
        //--------------------------------------------------------------------

        // --------------------------繪製點連成的線--------------------
        PolylineOptions polylineOptions = new PolylineOptions();
        polylineOptions.add(station01, station02, station03, station04, station05);
        polylineOptions.width(10);
        polylineOptions.color(Color.BLUE);
        map.addPolyline(polylineOptions);
        //--------------------------------------------------------------------

        //--------------------------繪製點連成的面--------------------
        PolygonOptions polygonOptions = new PolygonOptions();
        polygonOptions.add(station06, station07, station08, station09);
        Polygon polygon = map.addPolygon(polygonOptions);
        polygon.setStrokeWidth(5);
        polygon.setStrokeColor(Color.rgb(102, 153, 0));
        polygon.setFillColor(Color.argb(200, 255, 255, 0));
        polygon.setZIndex(1);
        //--------------------------------------------------------------------

        //--------------------------繪制圓形--------------------------
        CircleOptions circleOptions = new CircleOptions();
        circleOptions.center(mapCenter)
                .radius(2500)
                .zIndex(2)
                .strokeWidth(0)
                .strokeColor(Color.argb(200, 255, 0, 0))
                .fillColor(Color.argb(50, 255, 0, 0));
        map.addCircle(circleOptions);
        //--------------------------------------------------------------------
    }

    @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);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <fragment
        android:id="@+id/map"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>


info_content.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >

    <!-- 圖示 -->
    <ImageView
        android:id="@+id/badge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="5dp"
        android:adjustViewBounds="true"
        android:src="@drawable/train" >
    </ImageView>

    <!-- 標題 -->
    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:ellipsize="end"
        android:singleLine="true"
        android:textColor="#ffff0000"
        android:textSize="14dp"
        android:textStyle="bold" />

</LinearLayout>

info_window.xml :
<?xml version="1.0" encoding="utf-8"?>
<!-- 設定背景為自己設計的外框圖形info_bubble -->
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/info_bubble"
    android:orientation="horizontal" >

    <!-- 圖示 -->
    <ImageView
        android:id="@+id/badge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="5dp"
        android:adjustViewBounds="true" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <!-- 標題 -->
        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:ellipsize="end"
            android:singleLine="true"
            android:textColor="#ff000000"
            android:textSize="14dp"
            android:textStyle="bold" />

        <!-- 說明 -->
        <TextView
            android:id="@+id/snippet"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:singleLine="true"
            android:textColor="#ff7f7f7f"
            android:textSize="14dp" />
    </LinearLayout>

</LinearLayout>

build.gradle(Module.app):
apply plugin: 'com.android.application'

android {
    compileSdkVersion 21
    buildToolsVersion "23.0.1"

    defaultConfig {
        applicationId "com.example.gjun.googlemapmarkerpractice"
        minSdkVersion 15
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:21.0.3'
    compile 'com.google.android.gms:play-services:+'
}

AndroidManifest.xml :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.gjun.googlemapmarkerpractice" >

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" >

        <meta-data
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="AIzaSyCBRZamFCDSFNgkk4CKbUBoePEgYvf87FE"/>

        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

</manifest>

成品:


源碼下載:
GoogleMapMarkerPractice.7z

2015年11月7日 星期六

Google Play Service的Google Map - 使用Android Studio

這裡記錄在Android Studio中使用Google Map的方法:
  1. 設定Google Map的相依性(gradle dependency):

  2. 在module層級的build.gradle中,其dependencies中多加一行如下設定:

    compile 'com.google.android.gms:play-services:+'

     
  3. 設定權限及API Key:
    1. 在AndroidManifest.xml中設定權限,如下:
    2. 
      
      
      
      <uses-permission android:name="android.permission.INTERNET" />
      <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
      
      
      
      
    3. <application>節點內設定API Key:
    4. 
      
      <meta-data    android:name="com.google.android.maps.v2.API_KEY"    android:value="Your_API_Key"/>
這樣就可以開始使用Google Map了,例如下面是一個簡單的顯示Google Map的例子,使用了SupportMapFragment (API level 12(Android 3.1) 以上可使用 MapFragment):


  1. 首先是Layout, activity_main.xml :
  2. <?xml version="1.0" encoding="utf-8"?>
     <RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin"    
       android:paddingRight="@dimen/activity_horizontal_margin"    
       android:paddingTop="@dimen/activity_vertical_margin"    
       android:paddingBottom="@dimen/activity_vertical_margin" 
       tools:context=".MainActivity">
          <fragment android:id="@+id/map" 
         android:name="com.google.android.gms.maps.SupportMapFragment" 
         android:layout_width="match_parent"       
         android:layout_height="match_parent" />    
    </RelativeLayout>
    
    
    
    
  3. 其實這樣就可以了,在不打程式碼的情況下,足以在畫面上顯示一個地圖版面。

2015年6月28日 星期日

Android-使用單例模式(Singleton Pattern)關閉所有開啟過的Activity

在開發Android的App時,常會發生進入後台的Activity沒有正確的被關閉,還停留在後台繼續耗用系統的資源及消耗電量,或是按Back鍵時後台的Activity又回到前台畫面中,無法順利地離開App。
經過一翻搜尋方法後,找到了這篇文:
Android之完美退出方法(2.1-2.2-2.3SDK版本測試通過)

其中提到了一個個覺得蠻不錯的方法,特在此紀錄下來。主要是利用單例模式(Singleton Pattern)的方式,利用一個生命週期與App週期一樣長的唯一類別來管理所有開啟過的Activity,在要離開App時利用此單例的類別將所有開啟過的類別全部關掉,再把自己關掉,確保所有的Activity都關掉。

此例中有三個Activity,分別為MainActivity、Activity2、Activity3,三個Activity的Layout如下,在畫面正中央都有一個TextView顯示現在的頁面,而右下角都有一個Button可跳轉到下一個Activity,而在MainActivity按下Back鍵後,會關掉曾開啟的Activity並將整個App關掉。

此例中建立了一個單例類別,名為ActivityManager,在整個App的生命週期這個類別只會存在一個,裡面有一個LinkedList<Activity>用來存放所有開啟過的Activity,在每個Activity的onCreate()方法裡取得ActivityManager的物件實體並呼叫addActivity()方法來將Activity交由ActivityManager管理。最後在MainActivity的onBackPressed()中取得ActivityManager的物件實體並呼叫closeAllActivity()方法關掉所有曾開啟的Activity並結束App應用程式。

以下為程式碼,相關說明都已寫在註解中;

2015年6月9日 星期二

Android Studio更改專案套件(package)名稱的方法

當Android開發者要把自己寫的APK上架到Google Play Store時(記得先產生Signed APK,在Android Studio裡為Build-->Generate Signed APK),有時會碰到Google因package name為「com.example」的前綴而不接受。

這是因為「com.example」的package name是Android Studio一開始就給的預設專案套件名稱,必須要修改成自己設定的,Google才會接受上架此APK。這裡介紹在使用Android Studio開發時,如何更改專案的套件名稱。

在Android Studio中,如果對著專案套件按右鍵選擇Refactor-->Rename的話,是沒有辦法更改其前綴名稱的,也就是「com.example」。

經過上網搜尋找到了方法,在此介紹,可以參考這篇Android Studio Rename Package


  1. 在選示專案的數狀結構圖的右上角,有一個Gears icon的符號,如下圖,按下它之後,將其中的「Compact Empty Middle Packages」的勾勾給勾選掉,這時所有的套件階層就不會用一行來表示,而是用一個樹狀階層的方式顯示,這樣就可以自行訂義套件各層的名字和位置了。



  2. 只有這樣是不夠的,我們會發現如果這時想要把產生的Signed APK上架的話,Google還是不會讓你過的,對它來說套件還是沒有真正改成功。必須再到Gradle Scripts下的build.gradle(Module:app)裡面,把defaultConfig裡的applicationId也一併修改成新的專案套件名稱,最後對build.gradle(Module:app)按右鍵選擇Synchronize 'build.gradle'才算真正修改成功,這樣產生的Signed APK的專案套件名稱才有真正的被改到,Google Play Store才會接受。