Android基礎 Android系統架構 JVM和DVM的不同 區別 1. 基於的架構不同。jvm 基於棧架構,棧是位於記憶體上的一個空間,執行指令操作,需要向cpu定址; dvm 基於寄存器架構,寄存器是cpu的一個組成部分,執行指令操作無需定址直接執行。 2. 執行文件的格式不同,jvm執行的是 ...
Android基礎
Android系統架構
JNI java native interface
1. application:應用層, java
2. application framework: 應用框架層, java + JNI
3. libraries 和 dalvik:函數庫和虛擬機層, c/c++
4. linux kernel: linux 內核驅動層, c
JVM和DVM的不同
區別
- 基於的架構不同。jvm 基於棧架構,棧是位於記憶體上的一個空間,執行指令操作,需要向cpu定址; dvm 基於寄存器架構,寄存器是cpu的一個組成部分,執行指令操作無需定址直接執行。
- 執行文件的格式不同,jvm執行的是多個.class文件。 dvm執行的是一個.dex文件。
art 模式 (android runtime)
雖占用空間略大,但運行速度更快。
在Android 4.4以前,安卓手機系統的應用程式均在Dalvik Java的虛擬機上運行,這種運行模式是還要依靠一個編譯器來實現與應用程式的溝通。應程式每次運行時,都需要將程式內的代碼轉變為機器碼才能運行,這無形中多附加了一道手續,這就造成了耗電相對較快、占用記憶體大的問題。
art: 程式在安裝時需要預編譯讀取,將代碼轉換為機器碼。
- 好處:程式運行時,無需時時轉換,運行速度快 ;
- 缺點:安裝時間稍長,由於轉換機器碼,所以占用略高的存儲空間。
sdk目錄
add-ons:預留的一個附加目錄
build-tools:構建工具目錄
docs: 文檔目錄
extras:開發中額外提供的一些工具比如intelHAXM加速器及jar
platforms: 不同版本android的核心jar包
platforms-tools:平臺一些相關的工具
sources:源碼
system-images:系統鏡像文件
tools:開發中使用的一些工具,如9path,做圖片拉伸適配的。
emulator:模擬器
DDMS(Dalvik Debug Monitor Service)
file explorer: 列出當前設備所有目錄。
/data/app:安裝的第三方apk都在此目錄
/system/app: 系統預裝應用apk在此目錄
/data/data:應用的私有目錄,系統每安裝一個新的應用程式,都會在此目錄創建該應用包名的文件,用來存放該應用的私有數據,當應用卸載時,該包名的文件夾也會被刪除。
/sdcard :外部存儲目錄,一般會鏈接指向到另一個目錄,用來存放大數據。
Android工程目錄結構
applicationId和package
app下的build.gradle
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.example.hello"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
<!--
applicationId: 應用程式的包名,Android設備和應用商店上,applicationId是一個android程式的唯一標示
versionCode:應用程式的版本號
versionName:版本(名)描述
minSdkVersion: 應用最低能安裝的系統版本
compileSdkVersion:編譯時候的版本,始終使用最新版本
targetSdkVersion解釋起來複雜,Android 提供向前相容的主要依據,記住和compileSdkVersion版本號保持一致就好-->
app/src/main/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.hello">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!-- 應用程式的入口,進入app的第一個activity
action : MAIN 主要的
category : LAUNCHER 啟動 發射 -->
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
build.gradle下的applicationId v.s. AndroidManifest.xml下的package。
預設(最好)是兩者保持一致。
在Android Studio中是兩個獨立的東西,可以修改applicationId,與packageName不一致也可以的(不推薦)。
最簡單的MainActivity
oncreate :是Activity啟動時調用 , activity 相當於java web中的servlet(處理業務邏輯), layout 相當於java web中的jsp(負責顯示)
package com.example.helloworld;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity {
//oncreate :是Activity啟動時調用 , activity 相當於java web中的servlet, layout 相當於java web中的jsp
@Override
protected void onCreate(Bundle savedInstanceState) {
// savedInstanceState作用是在acticitypause狀態,被kill掉之前,保存此時的狀態。
// 這樣當activity開始時候調用onCreat時候就能獲得狀態數據savedInstanceState
super.onCreate(savedInstanceState);
//將一個佈局文件作為activity的內容顯示
setContentView(R.layout.activity_main);
}
}
Android的打包過程
.java --(使用jdk)---> .class ---(使用dx.bat)--->.dex(res,assets,androidmanifest.xml)--(使用aapt)-->.apk--(使用jarsigner簽名)--> final apk
ADB指令
ADB (android debug bridge)
建立手機與電腦直接的連接 , adb運行的埠號是5037。
為方便使用,需要將環境變數的配置:\sdk\platform-tools
配置到環境變數。
1. adb devices :列出當前電腦所連接的android設備
2. adb push pc_path phone_path :將電腦端文件放到手機端
3. adb pull phone_paht pc_path :將手機端文件拉到電腦端
4. adb install [-r] apkpath ; 安裝一個電腦端的apk文件。-r可選:強制安裝
5. adb uninstall packagename; 卸載一個應用
//三個指令聯合使用來解決adb被占用,或斷開連接的情況
6. adb kill-server : 結束adb服務的鏈接
7. adb start-server :開啟adb服務的鏈接
8. netstat -oan 查看埠: 查看埠
9. adb shell:進入當前設備linux環境下
10.adb shell下 ls -l :查看當前設備的目錄結構
11.adb shell下 logcat :查看系統運行中的日誌信息
簡單的例子--撥號
- 佈局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="請輸入手機號"
/>
<EditText
android:id="@+id/tel_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="numberDecimal" />
<Button
android:id="@+id/call"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="撥打" />
</LinearLayout>
- 主界面
package com.example.hello;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private EditText editText;
private Intent callIntent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 獲取佈局裡面的控制項
editText = (EditText) findViewById(R.id.tel_number);
Button callButton = (Button) findViewById(R.id.call);
callButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 用戶可能輸入了空格或者製表符,除去
String telnumber = editText.getText().toString().trim();
// ACTION_CALL和ACTION_DIAL的區別在於,前者直接撥打出去,後者彈出撥號界面和號碼,需要用戶手動撥打
callIntent = new Intent(Intent.ACTION_CALL);
// "tel:"指定了協議
callIntent.setData(Uri.parse("tel:" + telnumber));
// 動態申請運行時許可權,傳入的1是一個唯一碼,沒申請到許可權時不能執行後續動作,所以放在else分支里
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CALL_PHONE}, 1);
} else {
startActivity(callIntent);
}
}
});
}
// requestCode對應上面的唯一碼,這個方法根據用戶允許或者拒絕來處理
// PackageManager.PERMISSION_GRANTED表示用戶點擊了允許
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0]==PackageManager.PERMISSION_GRANTED) {
// 用戶允許後立即撥打電話
startActivity(callIntent);
} else {
Toast.makeText(MainActivity.this, "你拒絕了許可權!", Toast.LENGTH_SHORT).show();
}
break;
default:
}
}
}
記得使用permission.CALL_PHONE
時候需要在AndroidManifest.xml裡面註冊。
<uses-permission android:name="android.permission.CALL_PHONE" />
常用的重寫按鈕點擊事件的方法
上面用的匿名內部類的方法,當按鈕多的時候,每一個按鈕就會new出一個類開闢了一片空間。
讓當前Activity實現
implements View.OnClickListener
,對於有多個按鈕時很方便。
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private EditText editText;
private Intent callIntent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText = (EditText) findViewById(R.id.tel_number);
Button callButton = (Button) findViewById(R.id.call);
// 當前類就是一個listener
callButton.setOnClickListener(this);
}
// 將撥打電話功能封裝
private void callPhone() {
String telnumber = editText.getText().toString().trim();
callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:" + telnumber));
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CALL_PHONE}, 1);
} else {
startActivity(callIntent);
}
}
// 可能有多個按鈕,通過getId方法來判斷,id就是佈局文件里定義的
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.call:
callPhone();
break;
default:
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startActivity(callIntent);
} else {
Toast.makeText(MainActivity.this, "你拒絕了許可權!", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}
}
by @sunhaiyu
2017.4.7