Android基礎(chǔ)
Android系統(tǒng)架構(gòu)
JNI java native interface
1. application:應用層, java
2. application framework: 應用框架層, java + JNI
3. libraries 和 dalvik:函數(shù)庫和虛擬機層, c/c++
4. linux kernel: linux 內(nèi)核驅(qū)動層, c
JVM和DVM的不同
區(qū)別
- 基于的架構(gòu)不同偏窝。jvm 基于棧架構(gòu)衬吆,棧是位于內(nèi)存上的一個空間梁钾,執(zhí)行指令操作,需要向cpu尋址逊抡; dvm 基于寄存器架構(gòu)姆泻,寄存器是cpu的一個組成部分,執(zhí)行指令操作無需尋址直接執(zhí)行冒嫡。
- 執(zhí)行文件的格式不同拇勃,jvm執(zhí)行的是多個.class文件。 dvm執(zhí)行的是一個.dex文件孝凌。
art 模式 (android runtime)
雖占用空間略大方咆,但運行速度更快。
在Android 4.4以前蟀架,安卓手機系統(tǒng)的應用程序均在Dalvik Java的虛擬機上運行瓣赂,這種運行模式是還要依靠一個編譯器來實現(xiàn)與應用程序的溝通。應程序每次運行時片拍,都需要將程序內(nèi)的代碼轉(zhuǎn)變?yōu)闄C器碼才能運行钩述,這無形中多附加了一道手續(xù),這就造成了耗電相對較快穆碎、占用內(nèi)存大的問題牙勘。
art: 程序在安裝時需要預編譯讀取,將代碼轉(zhuǎn)換為機器碼。
- 好處:程序運行時方面,無需時時轉(zhuǎn)換放钦,運行速度快 ;
- 缺點:安裝時間稍長恭金,由于轉(zhuǎn)換機器碼操禀,所以占用略高的存儲空間。
sdk目錄
add-ons:預留的一個附加目錄
build-tools:構(gòu)建工具目錄
docs: 文檔目錄
extras:開發(fā)中額外提供的一些工具比如intelHAXM加速器及jar
platforms: 不同版本android的核心jar包
platforms-tools:平臺一些相關(guān)的工具
sources:源碼
system-images:系統(tǒng)鏡像文件
tools:開發(fā)中使用的一些工具横腿,如9path颓屑,做圖片拉伸適配的。
emulator:模擬器
DDMS(Dalvik Debug Monitor Service)
file explorer: 列出當前設(shè)備所有目錄耿焊。
/data/app:安裝的第三方apk都在此目錄
/system/app: 系統(tǒng)預裝應用apk在此目錄
/data/data:應用的私有目錄揪惦,系統(tǒng)每安裝一個新的應用程序,都會在此目錄創(chuàng)建該應用包名的文件罗侯,用來存放該應用的私有數(shù)據(jù)器腋,當應用卸載時,該包名的文件夾也會被刪除钩杰。
/sdcard :外部存儲目錄纫塌,一般會鏈接指向到另一個目錄,用來存放大數(shù)據(jù)讲弄。
Android工程目錄結(jié)構(gòu)
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設(shè)備和應用商店上,applicationId是一個android程序的唯一標示
versionCode:應用程序的版本號
versionName:版本(名)描述
minSdkVersion: 應用最低能安裝的系統(tǒng)版本
compileSdkVersion:編譯時候的版本避除,始終使用最新版本
targetSdkVersion解釋起來復雜媳荒,Android 提供向前兼容的主要依據(jù),記住和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 啟動 發(fā)射 -->
<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啟動時調(diào)用 , activity 相當于java web中的servlet(處理業(yè)務邏輯)蝌借, 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啟動時調(diào)用 昔瞧, activity 相當于java web中的servlet, layout 相當于java web中的jsp
@Override
protected void onCreate(Bundle savedInstanceState) {
// savedInstanceState作用是在acticitypause狀態(tài)菩佑,被kill掉之前自晰,保存此時的狀態(tài)。
// 這樣當activity開始時候調(diào)用onCreat時候就能獲得狀態(tài)數(shù)據(jù)savedInstanceState
super.onCreate(savedInstanceState);
//將一個布局文件作為activity的內(nèi)容顯示
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稍坯。
為方便使用酬荞,需要將環(huán)境變量的配置:\sdk\platform-tools
配置到環(huán)境變量搓劫。
1. adb devices :列出當前電腦所連接的android設(shè)備
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; 卸載一個應用
//三個指令聯(lián)合使用來解決adb被占用混巧,或斷開連接的情況
6. adb kill-server : 結(jié)束adb服務的鏈接
7. adb start-server :開啟adb服務的鏈接
8. netstat -oan 查看端口: 查看端口
9. adb shell:進入當前設(shè)備linux環(huán)境下
10.adb shell下 ls -l :查看當前設(shè)備的目錄結(jié)構(gòu)
11.adb shell下 logcat :查看系統(tǒng)運行中的日志信息
簡單的例子--撥號
- 布局文件
<?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的區(qū)別在于,前者直接撥打出去咧党,后者彈出撥號界面和號碼秘蛔,需要用戶手動撥打
callIntent = new Intent(Intent.ACTION_CALL);
// "tel:"指定了協(xié)議
callIntent.setData(Uri.parse("tel:" + telnumber));
// 動態(tài)申請運行時權(quán)限,傳入的1是一個唯一碼傍衡,沒申請到權(quán)限時不能執(zhí)行后續(xù)動作深员,所以放在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對應上面的唯一碼,這個方法根據(jù)用戶允許或者拒絕來處理
// 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, "你拒絕了權(quán)限蛙埂!", Toast.LENGTH_SHORT).show();
}
break;
default:
}
}
}
記得使用permission.CALL_PHONE
時候需要在AndroidManifest.xml里面注冊倦畅。
<uses-permission android:name="android.permission.CALL_PHONE" />
常用的重寫按鈕點擊事件的方法
上面用的匿名內(nèi)部類的方法,當按鈕多的時候箱残,每一個按鈕就會new出一個類開辟了一片空間滔迈。
-
讓當前Activity實現(xiàn)
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, "你拒絕了權(quán)限盼理!", Toast.LENGTH_SHORT).show(); } break; default: break; } } }
by @sunhaiyu
2017.4.7