Showing posts with label Android. Show all posts
Showing posts with label Android. Show all posts

2016/07/13

android 中的 Layoutinflator.inflate 的 attachToRoot?

Android 裡的 Layoutinflater 可以用來把 XML 轉換成 ViewGroup

通常拿來用在 Fragment 的 onCreateView() 方法裡
一般來說都是使用下面這個 inflate 方法


inflate
(int resource, ViewGroup root, boolean attachToRoot)
Inflate a new view hierarchy from the specified xml resource.

現在分析兩種情況,

attachToRoot 設為 true 的時候,代表 View 時直接被 attach 到 root group 裡,而且會回傳 root view

inflater.inflate(R.layout.custom_button, mLinearLayout, true);


attachToRoot 設為 false 的時候代表 這個 inflate 出來的 View  不是馬上被 attach 到 ViewGroup,而是指說在未來的某一個時間點才會,這方法會回傳自己的 view。

例如先將 XML inflate 後,到某個時間點在自己加進 layout
Button button = (Button) inflater.inflate(R.layout.custom_button, mLinearLayout, false);
mLinearLayout.addView(button);

最常見的例子就是 ListView (RecyclerView),因為是由 RecyclerView 來控制什麼時間點才要將 View 加入

探討 View.inflate

另外如果我們是直接使用 View.inflate ,他的本質其實就是直接將 inflate 出來的加到 layout 裡
例如下面這樣其實等同於 Layoutinflator.inflate 並且帶 attachRoot = true
LinearLayout layout = (LinearLayout)findViewById(R.id.container);
View view = View.inflate(this, R.layout.layout_menu_item, layout);
後記:如果你的 XML root 是 就只能 attachToRoot = true 否則會出現 InflateException

Caused by: android.view.InflateException: can be used only with a valid ViewGroup root and attachToRoot=true

參考:https://www.bignerdranch.com/blog/understanding-androids-layoutinflater-inflate/

2016/07/08

Android Studio 快速鍵 on MAC

1. Outline of Class  ( Command + 12)

2. Call Hierarchy (Ctrl + Alt + h)

3. Toggle Bookmark (F3)

4. Show bookmarks (Command + F3)

5. Find Action (Command + Shift + a)

6. Move Line (Alt + Shift + Up/Down)

7. Version Control Operation Popup (Ctrl + V)

8. Close All Panel (Shift + F12)

9. Duplicate Line (Command + D)

10. Rename (Shift + F6)

11. Select Multiple Line (Alt + Mouse Selection)

12. Toggle Breakpoint (Alt + F8)

2015/06/01

從 source code 編譯 Android APK 的筆記

以下的 scripts 都在 build/core/ 底下

建置 apk 中會用到的 mk 大致如下
  1. package.mk
  2. package_internal.mk
  3. java.mk
  4. dex_preopt_odex_install.mk
  5. install_jni_libs.mk
  6. install_jni_libs_interal.mk

開頭是 package.mk

package.mk, package_internal.mk 用於打包 apk

在 package.mk 中會引用 package_internal.mk

include $(BUILD_SYSTEM)/package_internal.mk

package_internal.mk 這隻裏頭會看到一堆處理打包事情的指令

例如處理 resource(前置), proguard(前置), compile, signkey, zipalign, include jni

前置設定完成後,開始進行編譯(使用 java.mk 這隻 script)

java.mk 把 source 編譯成 jar 跟 dex (class.dex 就是在這邊產生的),如果是 RenderScript 跟 FilterScript 在中間也會被轉成 .java 和 .bc 檔案, 這隻也會執行 proguard

編譯完成後,最後是很重要的打包動作 ( 此時已跳出java.mk 回到 package_internal.mk)

$(LOCAL_BUILT_MODULE): $(all_res_assets) $(jni_shared_libraries) $(full_android_manifest)
 @echo "target Package: $(PRIVATE_MODULE) ($@)"
 $(create-empty-package)
 $(add-assets-to-package)
ifneq ($(jni_shared_libraries),)
 $(add-jni-shared-libs-to-package)
endif
ifneq ($(full_classes_jar),)
 $(add-dex-to-package)
endif
 $(add-carried-java-resources)
ifneq ($(extra_jar_args),)
 $(add-java-resources-to-package)
endif
 $(sign-package)
ifdef LOCAL_DEX_PREOPT
ifneq (nostripping,$(LOCAL_DEX_PREOPT))
 $(call dexpreopt-remove-classes.dex,$@)
endif
endif
 @# Alignment must happen after all other zip operations.
 $(align-package)

順帶一提是很多 function 的定義都是在 definition.mk
下圖簡單的展示整個建置流程

2015/04/27

Android UI AutomatorViewer (開發筆記-3)

來談談 AutomatorViewer 前端顯示的部分 - UIAutomatorViewer.java

最主要的是滑鼠點擊後可選擇特定元素事件,以及滑動時的動態選擇事件

        // 點擊選擇
        mScreenshotCanvas.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseUp(MouseEvent e) {
                if (mModel != null) {
                    mModel.toggleExploreMode();
                    redrawScreenshot();
                }
            }
        });

        // 移動選擇
        mScreenshotCanvas.addMouseMoveListener(new MouseMoveListener() {
            @Override
            public void mouseMove(MouseEvent e) {
                if (mModel != null) {
                    int x = getInverseScaledSize(e.x - mDx);
                    int y = getInverseScaledSize(e.y - mDy);
                    // show coordinate
                    coordinateLabel.setText(String.format("(%d,%d)", x,y));
                    if (mModel.isExploreMode()) {
                        BasicTreeNode node = mModel.updateSelectionForCoordinates(x, y);
                        if (node != null) {
                            updateTreeSelection(node);
                        }
                    }
                }
            }
        });

可以看到重繪 Canvas 的驅動方法有 redrawScreenshot() 跟 updateTreeSelection(node),事實上這是透過註冊 PaintListener 來重繪

mScreenshotCanvas.addPaintListener(new PaintListener() {
            @Override
            public void paintControl(PaintEvent e) {
                if (mScreenshot != null) {
                        .....................

不過到這階段就是 jface 跟 swt 的事情了,跟 Android 沒太大關係就不多談。


Android UI AutomatorViewer (開發筆記-2)

今天來看 AutomatorViewer 的源碼

首先進入點是 UiAutomatorViewer

重要的後端邏輯處裡類別有 DebugBridge、UiAutomatorHelper、UiAutomatorModel ,以及 Action 系列 (在 com.android.uiautomator.actions package 下),而前端操作的邏輯部分為 UiAutomatorView,其中註冊多個 Listener 與 UiAutomatorModel 做溝通

UiAutomatorViewer 在最初開始連結 adb 後,建立基本的操作介面

DebugBridge.init();

ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
toolBarManager.add(new OpenFilesAction(this));
toolBarManager.add(new ScreenshotAction(this,false));
toolBarManager.add(new ScreenshotAction(this,true));
toolBarManager.add(new SaveScreenShotAction(this));
ToolBar tb = toolBarManager.createControl(c);
tb.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mUiAutomatorView = new UiAutomatorView(c, SWT.BORDER);
mUiAutomatorView.setLayoutData(new GridData(GridData.FILL_BOTH));

這邊以 Screenshot Action 做範例解說,當 ScreenshotAction 被觸發後,會執行 Action 介面中定義的 run 方法,可以看到下方的程式中,透過 UiAutomatorHelper 進行畫面擷取,並且從回傳的拿出資訊透過 setModel 設回給 UiAutomatorViewer,其中 model 為給前端使用的邏輯模型,而 uiHierarchy 為模型的 XML 檔案, screenshot 則為螢幕截圖。

if (!DebugBridge.isInitialized()) {
      MessageDialog.openError(mViewer.getShell(),
              "Error obtaining Device Screenshot",
              "Unable to connect to adb. Check if adb is installed correctly.");
      return;
  }
  final IDevice device = pickDevice();
  if (device == null) {
      return;
  }
  
ProgressMonitorDialog dialog = new ProgressMonitorDialog(mViewer.getShell());
try {
    dialog.run(true, false, new IRunnableWithProgress() {
        @Override
        public void run(IProgressMonitor monitor) throws InvocationTargetException,
                                                                InterruptedException {
            UiAutomatorResult result = null;
            try {
                result = UiAutomatorHelper.takeSnapshot(device, monitor, mCompressed);
            } catch (UiAutomatorException e) {
                monitor.done();
                showError(e.getMessage(), e);
                return;
            }
            mViewer.setModel(result.model, result.uiHierarchy, result.screenshot);
            monitor.done();
        }
    });
} catch (Exception e) {
    showError("Unexpected error while obtaining UI hierarchy", e);
}

深入 UiAutomatorHelper 後會發現一些與 Android 系統的互動,在 getUiHierarchyFile() 這個方法中,可以直接取用 IDevice 類別執行一些 shell command,或是擷取畫面、取用 SyncService 來 pull/push 檔案...等等的操作,這就是引入 ddmlib 的目的。

device.executeShellCommand(command,
        new CollectingOutputReceiver(commandCompleteLatch));
device.getSyncService().pullFile(UIDUMP_DEVICE_PATH,
        dst.getAbsolutePath(), SyncService.getNullProgressMonitor());
try {
    rawImage = device.getScreenshot();
} catch (Exception e) {
    String msg = "Error taking device screenshot: " + e.getMessage();
    throw new UiAutomatorException(msg, e);
}

Android UI AutomatorViewer (開發筆記-1)

本文介紹如何在 Eclipse 上引入 Android UI AutomatorViewer 專案

需要 API Level: 16 Android 4.1 (JELLY_BEAN) 才能夠執行該專案

首先是一般的執行方法

接上手機後執行 android-sdk\tools\uiautomatorviewer.bat

每當擷取一次後,會產生出資料在底下
C:\Users\{UserName}\AppData\Local\Temp\

可以發現類似這樣名稱的資料夾
uiautomatorviewer_5344357154835436455

裡面會有一張 png 手機截圖跟一個 XML layout 檔案 uix

程式的原始碼可以在 {android_src}\android\tools\swt\uiautomatorviewer 底下找到

使用 Eclipse 開發需要引入一些 library (jface, eclipse-equinox-common, eclipse-core-commands, ddmlib, guava, common.jar, swt)

其中 swt 會與作業系統有關,看是要引入 32 bit 還是 64 bit
執行的時候需要代 VM 參數,要帶入 tools 的位置 (因為程式裡面透過這個路徑來反查 adb 位置)

-Dcom.android.uiautomator.bindir=D:\android-sdk\tools



2014/09/01

Android Canvas

畫圖到 Canvas 上基本有兩種做法

1. 與 UI Activity 在同一個 Thread ,呼叫 invalidate(0 重製,然後實做 onDraw() 回呼來處理。
2. 在另外一個 Thread 上,你管理 SurfaceView 來繪製 Canvas

創建一個 Canvas 一定需要定義一個 Bitmap

Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
SurfaceView 由於是由另外一個 Thread 繪圖,所以不需要等待其它的 View 就能畫。
使用方法就是建立一個 extends SurfaceView 的類別,該類別也必須要實做 SurfaceHolder.Callback 子類別,該子類別是用來通知 surface 發生 create, change, destroy 事件。
操作 Surface 物件必須要透過 SurfaceHolder,所以當你初始化了 SurfaceView 物件,要透過 getHolder() 方法來取得 SurfaceHolder ,然後再透過 SurfaceHolder.Callback 的 addCallback() 方法來註冊通知。

透過 lockCanvas() 跟 unlockCanvasAndPost() 來達到繪圖效果

OpenGL ES

  • OpenGL ES 1.0 and 1.1 - This API specification is supported by Android 1.0 and higher.
  • OpenGL ES 2.0 - This API specification is supported by Android 2.2 (API level 8) and higher.
  • OpenGL ES 3.0 - This API specification is supported by Android 4.3 (API level 18) and higher.
ES 3.0 需要硬體廠商有實做 graphics pipeline, 而且 Android 4.3 以上的裝置可能不能用...= =

Android 支援 OpenGL ,可透過一般的 API 存取外,也可以透過 NDK (Native Development Kit)。

一般存取方法是透過 GLSurfaceView 跟 GLSurfaceView.Renderer 這兩個類別。
GLSurfaceView 這個類別讓你可以使用 OpenGL API 繪製跟操作物件(藉由建立這個類別物件並加上 Renderer)。

GLSurfaceView.Renderer 是一個讓你必須要實做 onSurfaceCreated(), onDrawFrame(), onSurfaceChanged() 方法的介面


Android 動畫 Property Animation 基本概念

Android 提供了三種動畫系統: Property Animation (從 3.0 開始) 和 View Animation ,另外一種是讀取 drawable 資源來顯示 (Drawable Animation),一般而言通常建議使用 property animation。

Property Animation 系統能夠讓你定義下列幾項功能
Duration, Time interpolation, Repeat count and behavior, Animator sets, Frame refresh delay

啟動動畫的方法:建立一個 ValueAnimator 物件,然後給予它開始和結束的數值。
ValueAnimator 物件持續的追蹤你的動畫物件,它包含了一個 TimeInterpolator 物件來定義動畫的 Interpolation

Property Animation 和 View Animation 的比較

- View Animation 只能對 View 物件進行動畫
- View Animation 只能進行少數的動畫效果
- View Animation 並非真正修改 View 本身,例如將一個按扭進行在畫面上的動畫時,它雖然被繪圖正確,但它實際的位置上並沒有改變(邏輯位置),也就是說事件處發位置仍然不變。

2014/08/31

Android 讀書筆記 (Android Fundamental)

基本概念


* Android 是一個 multi-user linux system
* 每個 app 都有自己的 user id ,每個檔案的存取權限是以 user id 做控管
* 每個 process 都有自己的 virtual machine (VM),所以每個 app 都是獨立隔離的

* 採用最小權限法 (principle of least privilege)
* 仍然有辦法讓不同 app 使用相同的 user id (前提是 app 簽證一樣)

四大 Component

* Activities: 一個活動代表一個 Single Screen 的 user interface。例如 email 有讀信、寫信的活動
* Services: 背景執行的程式(通常for長時間的操作),並沒有提供 user interface
* Content Provider: 管理 APP 資料
* Broadcast Service: 系統通知

啟動 Component

* Activities, Service, Broadcast Service 都是透過 Intent 來啟動 (訊息告知特定目的)
* 在其它 component 的結果也是透過 intent 拿回
* 透過 content resolver 來啟動 content provider

相關方法 startActivityForResult() , startService(), bindService(), sendBroadcast(), sendStickyBroadcast(), sendOrderedBroadcast()

Manifest 設定檔

* 一定要把所有 component 定義在裡面

elements for activities
elements for services
elements for broadcast receivers
elements for content providers

* broadcast 不一定要,可以在程式裡動態註冊
* 透過 的子項 來從別的 app 吃 data 進來處理


參考網址  http://developer.android.com/guide/components/fundamentals.html


2010/08/13

Andoird startActivityForResult

這篇文章可以解決以及瞭解下列問題:
1. 如何從Dialog取得回傳值
2. 如何在兩個Activity之間傳遞訊息
3. 如何使用startActivityForResult
4. 如何使用setResult
5. 如何在Dialog做出等寬的按鈕

假設一個情境:某個MainActivity要叫出一個Login的對話框。使用者輸入後,從Login對話框中取得nickname以及password然後在MainActivity進行登入動作。

※這個方法是用Activity假裝Dialog來取得資料

首先先撰寫LoginActivity部份

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.EditText;

public class LoginActivity extends Activity {

    // UI
    private EditText nickname;
    private EditText password;
    
    private Button okBtn;
    private Button cancelBtn;
    
     /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.login_dialog);
        
        // Width to Fill Parent
        LayoutParams params = getWindow().getAttributes(); 
        params.width = LayoutParams.FILL_PARENT; 
         getWindow().setAttributes((android.view.WindowManager.LayoutParams) params);
        
        // UI Assign
        nickname = (EditText) findViewById(R.id.nickname);
        password = (EditText) findViewById(R.id.password);
        
        okBtn = (Button) findViewById(R.id.okBtn);
        cancelBtn = (Button) findViewById(R.id.cancelBtn);
        
        
        okBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {

                // make intent
                Intent intent = new Intent();
                intent.putExtra("nickname", nickname.getText().toString());
                intent.putExtra("password", password.getText().toString());
                
                // setResult(RESULT_OK, Intent)
                LoginActivity.this.setResult(RESULT_OK ,intent);
                
                // close activity
                LoginActivity.this.finish();
            }
        });
        
        cancelBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                LoginActivity.this.setResult(RESULT_CANCELED);
                LoginActivity.this.finish();
            }
        });
    }
}


然後是layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" android:layout_height="fill_parent"
    android:orientation="vertical">
    <TextView android:layout_height="wrap_content"
        android:layout_width="fill_parent" android:layout_marginLeft="20dip"
        android:layout_marginRight="20dip" android:text="@string/nickname_lbl">
    </TextView>
    <EditText android:id="@+id/nickname" android:layout_height="wrap_content"
        android:layout_width="fill_parent" />
    <TextView android:layout_height="wrap_content"
        android:layout_width="fill_parent" android:layout_marginLeft="20dip"
        android:layout_marginRight="20dip" android:text="@string/password_lbl">
    </TextView>
    <EditText android:id="@+id/password" android:layout_height="wrap_content"
        android:layout_width="fill_parent" />
    <TableLayout android:id="@+id/row1" android:layout_width="fill_parent"
        android:layout_height="wrap_content" android:layout_weight="1">
        <TableRow android:layout_weight="1">
            <Button android:id="@+id/okBtn" android:layout_width="0dip"
                android:layout_height="wrap_content" android:text="@string/ok_lbl"
                android:layout_weight="1" />
            <Button android:id="@+id/cancelBtn" android:layout_width="0dip"
                android:layout_height="wrap_content" android:text="@string/cancel_lbl"
                android:layout_weight="1" />
        </TableRow>
    </TableLayout>
</LinearLayout>

接下來開始寫主程式

public class MainActivity extends Activity {

    // Sub Activity Code
    protected static final int LOGIN_ACTIVITY_CODE = 1;

    private Button connectBtn;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        connectBtn = (Button) findViewById(R.id.connectBtn);

        connectBtn.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View arg0) {

            // Start Login Activity
            Intent intent = new Intent(MainActivity.this, LoginActivity.class);
            startActivityForResult(intent, LOGIN_ACTIVITY_CODE);
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode,
            Intent data) {
        if (requestCode == LOGIN_ACTIVITY_CODE) {
            if (resultCode == RESULT_OK) {
                // Log
                Log.d(TAG, "Get Result From Login Activity");
                Log.d(TAG, data.getStringExtra("nickname"));
                Log.d(TAG, data.getStringExtra("password"));
                
                // Login Setting
                cManager.setNickname(data.getStringExtra("nickname"));
                cManager.setPassword(data.getStringExtra("password"));
                
                // Connect
                connectToServer();
            }
        }
    }
}


記得要在AndroidManifest.xml加入這個才能以Dialog形式顯示Activity

<activity android:name=".LoginActivity"
          android:label="@string/login_activity"
          android:theme="@android:style/Theme.Dialog">
</activity>

其他我就不想多說了,有問題再說。

2010/07/01

Android SDcard寫入檔案

用adb工具請參考

http://blog.csdn.net/ligaoyang/archive/2009/08/25/4481846.aspx


這邊要處理的是可能有FileNotFound的Exception或是無法寫入的Exception

在AndroidManifest.xml檔案裡加入下面這句,就能寫入。

Android 將Canvas寫成圖片以及透明

搜尋用關鍵字:"Canvas to Bitmap","Canvas to PNG","Canvas to JPEG","Canvas Transparent","Transparent","圖片透明"

以來源方式取得轉成Bitmap
Bitmap viewBgrnd = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.blackBgrnd);

更詳細看這邊
http://www.brighthub.com/mobile/google-android/articles/64048.aspx

自行產生新的Bitmap作為Canvas附帶
Bitmap  bitmap = Bitmap.createBitmap( view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); 
Canvas canvas = new Canvas(bitmap); 
view.draw(canvas);  
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);  

Config.ARGB_8888 似乎是透明圖片、高畫質的意思,但是實際上用了也沒有什麼感覺。

要透明的話

Canvas c = new Canvas(bitmap);
c.drawColor(Color.TRANSPARENT);

不行的話再用
c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);


參考文章
http://www.eoeandroid.com/redirect.php?tid=8573&goto=lastpost
http://androidforums.com/android-developers/36122-saving-png-transparency.html

2010/02/09

Android隨便教(1)

環境準備

到官網下載SDK安裝平台
http://developer.android.com/

下載完打開,到Setting裡勾選「Force https://...」選項
然後到Available Packages裡按Refresh後,勾選最新版本的Android SDK,Google APIs跟Documents下載

與Eclipse整合

新增網址「https://dl-ssl.google.com/android/eclipse/」然後安裝。

Eclipse再啟動之後[Window]-[Preferences],選[Android],[SDK Location]設定為最開始解壓的SDK安裝平台資料夾下。

Android介紹

Android的應用程式是在Java的VM上動作,但是不是平常用的Java VM,而是一個叫做DalvikVM的低記憶體環境VM。

DalvikVm並沒有支援所有Java標準的Library。

建立一個應用程式的固定步驟

  1. 編譯Java原始碼為.class檔
  2. Java類別檔、(.class、.jar)再編譯成可執行檔.dex
  3. 包裝後產生應用程式檔.apk

流程大概就是,使用生成的apk檔來安裝應用程式,被展開的.dex檔來執行應用程式。

Activity

首先最基本的要素「Activity」,通常是「1 Activity = 1 畫面」,Layout和使用者的事件、Activity的狀況回應的紀錄。

一個Activity的Life Cycle通常是

Activity開始 -> OnCreate() -> OnStart() -> OnResume() -> Activity啟動 -> onPause() -> OnStop() -> onDestroy -> Activity終了

Intent

Intent是擔當Activity和Application間的互動訊息角色,藉由intent的傳送來遷移Application的畫面或是呼叫其他的Applicaiton。

Intent分成「明示」、「暗示」兩種,明示有指定對象,暗示則沒有,要怎樣處理是由Intent filter來決定。

作成範例「名片管理Applicaiton」

先規劃幾項功能

  • 顯示名片內容
  • 名片的新增和更新
  • 從名片的內容顯示地圖
  • 利用名片的內容使用外部電話或是郵件的Applicaiton

作成專案

首先先作成專案。因為要使用Google Map,所以在Google APIs的地方打勾。

理解專案的構造

AndroidManifest.xml:定義Application的構造的最重要檔案,以後要加入Activity的話都要在這裡定義。
src資料夾: source code資料夾
res資料夾: resource資料夾,放圖片、Layout等等。

res的子資料夾

res/anim/ : Frame Animation和Tweened Animation用的xml檔案
res/drawable/ : 圖片檔案,.png,.9.png,.jpg,
※.9png是可resize的png檔,從SDK裡的tool\draw9patch.bat可以啟動編輯工具
在預設下會建立出drawable-hdpi、drawable-ldpi、drawable-mdpi的預設資料夾,這是根據解析度分類。
更多請參考:http://developer.android.com/guide/topics/resources/resources-i18n.html
res/layout : layout用xml檔
res/menu : menu用的xml檔
res/values : source檔利用的xml值檔案,例如可以用來做國際化、創造value-en、value-zh-tw資料夾
res/xml : 任意的xml檔案
res/raw : 任意的檔案,音樂資料等、沒編譯的檔案等

assets資料夾: 什麼檔案都能放,但是跟res/raw差不多,所以沒啥在用
gen資料夾:自動生成index檔案的資料夾,打開R.java看就知道。

Andorid的Layout作成法,

「用XML定義」以及「從程式下手」這兩種方法。XML定義的話比較容易修改閱讀,所以通常都用XML,如果是動態的Layout時,則只能在程式裡面下手了。

Layout的作成就使用「Android Developer Tools」裡有的編輯器,滑鼠右鍵方才作成的專案的「res/layout/main.xml」,「Open with」-「Android Layout Editor」來打開編輯器。

接下來介紹View的配置Layout。

LinearLayout,將任意的View縱\橫的方向來配置。就好像網頁單純的幾欄式。不過是有橫的而已。

TableLayout, 跟HTML裡的Table一樣的Layout。

FrameLayout, 就一個框一個框的表示,在子畫面的時候使用。