天天看點

Android開發 入門篇(一)

文章目錄

    • 序言
      • 建立項目的小問題
      • build.gradle
        • 外層gradle
        • app gradle
      • 日志工具
    • 活動
      • 建立和使用
      • Toast
      • menu
      • Activity跳轉
        • 顯示Intent
        • 隐式Intent
        • 向下傳遞資料
        • 傳回資料給上一級
      • 活動生命周期
        • 活動狀态
        • 活動的生命期
      • 活動啟動模式
      • 活動的應用
        • 找到界面對應的活動
        • 快速直接退出程式
        • 啟動程式的好技巧
    • balabala
    • OK,THANKS FOR READING.BYE BYE~

有些as的使用技巧、活動和部分控件的使用。

出自《第一行代碼(第二版)》,用于自己學(chao)習(shu)記錄

序言

建立項目的小問題

關于AS的一些小問題,如果如下報錯

Error:Execution failed for task ':app:preDebugAndroidTestBuild'.
> Conflict with dependency 'com.android.support:support-annotations' in project ':app'. Resolved versions for app (26.1.0) and test app (27.1.1) differ. See https://d.android.com/r/tools/test-apk-dependency-conflicts.html for details.
           

build.gradleModule:app

檔案中的

dependencies{…}

中添加

androidTestCompile('com.android.support:support-annotations:26.1.0') {
    force = true
}
           

即可,如果版本是其他,按照版本修改相應數值即可。

build.gradle

AS中是用gradle建構項目的,gradle是一個先進的項目建構工具。使用基于Groovy的領域特定語言(DSL)聲明項目配置,摒棄了基于XML的繁瑣配置。

項目中有兩個build.gradle檔案,一個是外層的,一個是内層app目錄下的。

外層gradle

buildscript {
    
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.0'
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

           

repositories中聲明了google()和jcenter(),jcenter()是一個代碼托管倉庫,裡面有很多優秀的安卓開源項目,聲明後可以輕松引用倉庫中的開源項目。dependencies中聲明了一個gradle插件,其實gradle不是專門為Android項目開發的,Java和C++中也可以使用,是以需要使用專門的插件。

app gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "com.example.k.androidpractie"
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    androidTestCompile('com.android.support:support-annotations:26.1.0') {
        force = true
    }
}

           

versionCode表示項目版本号,versionName表示項目的版本名,在後面會說到。

Buildype包用于指定生成安裝檔案的相關配置,通常包括debug和release,debug是測試版安裝檔案,release則為正式版安裝檔案,debug可以忽略不寫的。

minifyEnabled指定是否混淆,proguardFiles則用于指定混淆規則,後面有兩個檔案,一個是SDK目錄下的,有所有項目的混淆規則,第二個檔案是目前項目根目錄下的,可以編寫目前項目特有的混淆規則。

dependencies可以指定目前項目所有的依賴關系。通常一個AS項目一共有3種依賴方式:本地依賴、庫依賴和遠端依賴。本地依賴是對本地Jar包或目錄添加依賴,庫依賴是對庫子產品添加依賴,遠端依賴則可以對jcenter等倉庫中的項目添加依賴。

日志工具

Android中的日志工具類是Log(android.util.Log),提供了五個相關方法:

  • Log.v():列印最為繁瑣、意義最小的日志,對應級别是verbose,級别最低
  • Log.d():列印一些調試資訊,有助于調試或者分析程式,對應級别是debug,比verbose高
  • Log.i():列印一些比較重要的資料,對應級别是info,比debug高
  • Log.w():列印一些警告資訊,提示程式這裡可能會有一些潛在風險,最好修複一下,對應級别是warn,比info進階
  • Log.e(),列印錯誤資訊,比如程式進入到catch中了,級别是error

測試一下,在MainAvtivity.java中的onCreate()方法中添加一行

Log.d("MainActivity","this is a dubug message");
           

就可以輸入debug資訊了,如下圖所示,其中第一個參數是tag,一般寫目前類名,便于過濾,第二個參數就是需要輸出的資訊。

Android開發 入門篇(一)

為了友善使用日志工具,可以在每個類開頭設定一個變量

private static final String TAG="...";
           

之後Log中的第一個參數直接TAG即可。

logcat可以使用過濾功能,AS預設提供了兩個過濾器,也可以自定義。點選

Edit Fliter Configuration

,寫好tag就行,點選OK,可以看到就隻顯示我們需要的log了。

Android開發 入門篇(一)
Android開發 入門篇(一)

等等,日志大概常用的就是這些,剩下的自己捉摸吧。

活動

建立和使用

在此手動建立一個活動。

建立一個項目,不要選擇

Empty Activity

,選擇

Add No Activity

進入後,右鍵

app-java-com.example.k.androidpractice_1 -> New -> Activity -> Empty Activity

,同時取消Generate Layout File(自動建立布局檔案)和Launcher Activity(設定為目前項目主活動)。

Android開發 入門篇(一)
Android開發 入門篇(一)

之後建立一個布局檔案

右鍵

app/res -> New -> Dictory

,建立一個名為layout的檔案夾,然後右鍵layout檔案夾,

New -> Layout resource file

,xml名為

first_layout

,預設為LinearLayout。

在xml中添加一個Button,修改代碼如下

<?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">
    <Button
        android:id="@+id/Button_1"
        android:text="this is a button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>
           

切換到design

Android開發 入門篇(一)

之後需要在Activity中加載布局,在FirstActivity中添加如下一行

setContentView(R.layout.first_layout);

設定布局,傳入布局id即可。

在AndroidManifest.xml中注冊Activity,其實AS已經幫我們注冊了FirstActivity這個活動,代碼如下

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

    <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">
        <activity android:name=".FirstActivity"></activity>
    </application>

</manifest>
           

其中android:name中應為

com.example.k.androidpractice_1.FirstActivity

,因為外部有package,這裡就簡寫了。

但是還是需要設定主活動,否則程式無法知道首先啟動哪個Activity。

将Activity标簽修改如下

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

注意:如果沒有指定一個Activity為主活動,程式還是可以運作的,隻不過無法看到圖示,一般是作為第三方服務提供的,比如支付寶的支付服務。

之後運作可以看到程式正常運作了。

Toast

Toast是一種很友好的提示方式,可以以短小的資訊提示使用者某些資訊,在此對按鈕進行監聽以顯示Toast。

修改MainActivity代碼如下

Button Button=findViewById(R.id.Button_1);
        Button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(FirstActivity.this,"this is a message",Toast.LENGTH_SHORT).show();
            }
        });
           

menu

設定菜單大概需要三步:

  • 建立menu檔案夾和編寫main.xml中的item
  • 重寫onCreateOptionsMenu(),設定我們寫好的main.xml
  • 重寫onOptionsItemSelected(),對菜單選項進行監聽響應

在res檔案夾下建立檔案夾menu,右鍵menu檔案夾,New -> Menuresourcefile,輸入main點ok。在main.xml中添加如下代碼

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/Add_Item"
        android:title="Add"/>
    <item android:id="@+id/Remove_Item"
        android:title="Remove"/>
</menu>
           

這裡建立了兩個菜單選項Add和Remove指定其id和顯示内容。

需要重寫

onCreateOptionsMenu()

方法,按

ctrl+O

重寫方法,找到我們需要的,點選OK。

Android開發 入門篇(一)

修改如下

@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main,menu);
        return true;
    }
           

其中getMenuInflater()方法獲得MenuInflater對象,調用inflater()方法建立菜單。

之後需要定義菜單的響應事件,即監聽菜單,需要重寫onOptionsItemSelected()方法

public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.Add_Item:
                Toast.makeText(this,"這是Add",Toast.LENGTH_SHORT).show();
                break;
            case R.id.Remove_Item:
                Toast.makeText(this,"這是Remove",Toast.LENGTH_SHORT).show();
                break;
                default:break;
        }
        return true;
    }
           

如果想結束一個Activity,在代碼中可以直接通過finish()方法實作,即按傳回鍵的功能

Activity跳轉

在程式啟動之後指揮進入到主活動,如何跳轉到其他活動呢?需要使用intent。

顯示Intent

建立一個Activity,叫SecondActivity,勾選generate不選launcher。

在activity_second.xml中添加Button控件

<Button
        android:id="@+id/Button2"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:text="這是second activity"
        />
           

修改FirstActivity中對Button的監聽,Intent一個重載是第一個參數為啟動活動的上下文,第二個參數為需要啟動的目标活動

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_layout);
        Button Button=findViewById(R.id.Button_1);
        Button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
                startActivity(intent);
            }
        });
    }
           

隐式Intent

即為不明确啟動某個Activity,而是指定一系列action或者category等資訊,然後由系統找到合适的Activity啟動。

修改AndroidManifest.xml中的SecondActivity标簽

<activity android:name=".SecondActivity">
            <intent-filter>
                <action android:name="con.example.k.androidpractice_1.ACTION_START"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>
           

其中action指明了該活動可以響應的action,category具體包含了一些附加資訊。

修改FirstActivity中的按鈕監聽

Button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent("con.example.k.androidpractice_1.ACTION_START");
                startActivity(intent);
            }
        });
           

隻有當action和category同時比對的時候才能正确響應活動,由于此時的category是DEFAULT,是以不寫的話會預設為DEFAULT。

每個Intent隻可以指定一個action,但是可以指定多個category。

然後一個例子,啟動浏覽器,代碼如下

Button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent(Intent.ACTION_VIEW);
                intent.setData(Uri.parse("http://www.baidu.com"));
                startActivity(intent);
            }
        });
           

如下所示,可以打開網頁了,要注意網址一定要正确,比如必須要加http://,否則報錯。其中INTENT.ACTION_VIEW是系統中的常量,值為android.intent.action.VIEW。

Android開發 入門篇(一)

通過setData()傳入資料,标簽中可以添加标簽,更加精确配置響應什麼類型的資料,主要可以配置如下内容

  • android:sheme 資料的協定部分,如http
  • android:host 資料的主機部分,如www.baidu.com
  • android:port 資料的端口部分,一般跟在主機名後
  • android:path 用于指定主機名和端口之後的部分,如一段網址中跟在域名之後的内容
  • android:mimeType 指定可處理資料的類型,允許使用通配符方式指定。

隻有标簽中指定的内容和Intent中攜帶的資料一緻的時候才能正确響應。

一個簡單示例,以響應http協定。建立Third_Activity,添加一個Button3,修改AndroidManifest.xml

<activity android:name=".ThirdActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="http"/>
            </intent-filter>
        </activity>
           

之後啟動程式,點選按鈕,可以看到已經識别到我們自定義的Activity了。

Android開發 入門篇(一)

向下傳遞資料

大緻思想就是先将資料存儲到Intent中,再目标活動中取出資料即可。主要用到了

putExtra()和getStringExtra()

方法。

filename:FirstActivity.java
Button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String data="this is a data string";
                Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
                intent.putExtra("extra_data",data);
                startActivity(intent);
            }
        });

filename:SecondActivity.java
setContentView(R.layout.activity_second);
        Intent intent=getIntent();
        String data=intent.getStringExtra("extra_data");
        Toast.makeText(SecondActivity.this,data,Toast.LENGTH_SHORT);
           

可以看到由Toast生成了,說明成功了。

Android開發 入門篇(一)

傳回資料給上一級

大緻步驟為三步:

  • 調用startActivityForResult()啟動Intent
  • 在待銷毀活動中建立一個Intent,把資料放入其中,調用setResult()傳回結果
  • 在上一級活動中重寫onActivityResult()方法,從Intent中擷取資料

需要使用到這麼一個方法,startActivityForResult(),這個方法在銷毀活動的時候會傳回一個結果給上一級,有兩個參數,第一個參數為Intent,第二個參數為一個請求碼,保證其唯一即可。

在待銷毀活動中建立一個Intent,不需要有參數,隻是用來傳遞資料,通過putExtra把資料傳入Intent中,調用setResult()傳回Intent,有倆各個參數,第一個一般為RESULT_OK或者RESULT_CANCELED,之後調用finish()銷毀。同時需要重寫上一級活動中的onActivityResult()方法以得到資料,因為活動銷毀後會調用上一級活動的這個方法。

修改代碼

filename:FirstActivity.java
...
Button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String data="this is a data string";
                Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
               startActivityForResult(intent,1);
            }
        });
...
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode){
            case 1:
                if (resultCode==RESULT_OK){
                    String string=data.getStringExtra("data_return");
                    Toast.makeText(FirstActivity.this, string, Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }

filename:SecondActivity.java
...
Button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent();
                intent.putExtra("data_return","hello,firstactivity");
                setResult(RESULT_OK,intent);
                finish();
            }
        });
           

可以看到成功擷取到了資料。

Android開發 入門篇(一)

由于可能會有多個Activity傳回到同一個活動,是以需要在onActivityResult()中首先判斷requestCode的值确定其來自于哪個活動(即為最開始的請求碼),然後根據resultCode判斷是否成功,之後從data中擷取資料。

==============

如果是通過傳回鍵傳回的呢,重寫待銷毀活動的onBackPressed()方法即可。

活動生命周期

安卓中是通過任務來管理活動的,一個任務是一組存放在棧裡的活動的集合,即傳回棧。每當啟動一個新的活動的時候,活動入棧處于棧頂位置,按下傳回鍵或者調用finish()方法銷毀一個方法的時候,棧頂的活動會出棧。系統總是顯示棧頂的活動給使用者。

活動狀态

每個活動在生命周期最多有四個可能的活動狀态

  • 運作狀态:處于傳回棧棧頂的活動處于運作狀态
  • 暫停狀态:活動不處于棧頂但是仍然可見的時候,處于暫停狀态,不是所有活動都必須占滿全部螢幕,比如彈出的對話框就隻占據部分螢幕。
  • 停止狀态:活動不處于棧頂且完全不可見的時候就處于停止狀态,系統會保留相應狀态和成員變量,但是不可靠,如果記憶體不夠用的時候,這部分将被回收。
  • 銷毀狀态:當一個活動從棧頂移除後變成銷毀狀态,系統會優先回收這種狀态的活動。

活動的生命期

Activity類中定義了七個回調方法,覆寫了生命周期中的每一個環節

  • onCreate():在活動第一次被建立的時候調用,實作布局的加載、事件綁定等
  • onStart():在活動由不可見變為可見的時候調用
  • onResume():在活動準備好和使用者進行互動的時候調用,此時活動一定處于棧頂,且處于運作狀态
  • onPause():在系統準備啟動或恢複另一個活動時調用。一般在這裡需要釋放一些消耗cpu的資源,儲存一些關鍵資料,要快,否則可能會影響新活動
  • onStop():在活動完全不可見的時候調用。若啟動新活動是類似對話框的活動,使用onPause(),onStop()不會執行
  • onDestroy():在活動被銷毀之前調用,之後活動會變為銷毀狀态
  • onRestart():活動由停止狀态變為運作狀态的時候調用該方法,即活動被重新啟動

還可以分為三種生存期

  • 完整生存期:即onCreate()和onDestroy()之間所經曆的是完整生命期,在onCreate()中進行初始化操作,在onDestroy()中進行記憶體的釋放
  • 可見生存期:在onStart()和onStop()之間所經曆的是可見生命期。在這個期間活動都是可見的,即便某些無法互動的時候也是可見的。應在onStart()中完成資源的加載,onStop()中進行資源的釋放
  • 前台生存期:在onResume()和onPause()之間所經曆的是前台生存期。在這個期間活動總是處于運作狀态,可以和使用者進行互動
Android開發 入門篇(一)

當一個活動進入停止狀态的時候,可能會被回收。如在活動A上啟動活動B,此時A進入停止狀态,但是由于記憶體不足,A被回收,從活動B傳回之後,仍會正常顯示活動A,隻不過不會調用onRestart()方法,而是會調用onCreate()方法。比如正在文本框中輸入了文字,然後啟動了另一個活動,傳回之後,打的字沒了,就是說這個活動被重新建立了。

Activity類中提供一個onSaveInstanceState()回調方法,可以保證在活動被回收之前一定會被調用

可以在此時臨時儲存資料避免資料消失的問題。重寫該方法,參數是一個Bundle,Bundle提供了一系列方法用于儲存資料,如putString(),putInt()等,這些方法都有兩個參數,第一個是鍵值,第二個是儲存的内容值。

protected void onSaveInstanceState(Bundle outState){
	super.onSaveInstanceState(outState);
	String tempData="this is s temp data";
	outState.putString("data_key",tempData);
}
           

如何取出資料呢?onCreate()的參數也為Bundle,在該方法中從Bundle中取出資料

protected void onCreate(Bundle savedInstancedState){
	super.onCreate(saveInstanceState);
	Log.d(TAG,"onCreate);
	if (savedInstancedState != null){
		String tempData=savedInstancedState.getString("data_key");
		Log.d(TAG,tempData);
	}
}
           

Intent和Bundle有些類似,當然Intent可以和Bundle結合使用,把資料先儲存到Bundle中,在把Bundle傳入Intent中。

活動啟動模式

在實際項目中需要根據需求合理設定不同的啟動模式,一共有四種standard、singleTop、singleTask和singleInstance。

通過AndroidManifest.xml中中的android:launchMode屬性進行設定。

  • standard:每當standard模式啟動的活動,不會在意是否已啟動,即不會在意是否處于傳回棧,每次啟動都會建立一個新的活動,而且打開幾個活動就需要按幾次傳回
  • singleTop:在啟動的時候如果發現傳回棧棧頂就是該活動,則不會建立新的活動,不管啟動幾次活動都隻需要按一次傳回,因為棧頂始終是該活動。但是如果該活動不處于棧頂位置,再次啟動的話則仍會建立新的執行個體
  • singleTask:使用singleTop可以解決重複建立棧頂活動的問題,但是如果該活動不處于棧頂,則會建立很多活動。而singleTask模式會在傳回棧中先檢查是否存在待啟動活動的執行個體,不存在的建立一個執行個體,如果存在則将其置為棧頂,并彈出所有該活動之上的活動
  • singleInstance:啟動活動的時候會直接建立一個新的傳回棧。假設有一個活動是需要共享的,如果使用前三種啟動模式,均會建立新的執行個體,由于需要共享,是以不可能建立執行個體,是以使用單獨的傳回棧管理這個活動。(eg:設定second為singleInstance模式,在first啟動second,在second啟動third,則first和third處于同一個棧,second處于一個棧,此時棧頂活動為third,按傳回會回到first而不是second,因為first和third處于同一個棧,再次按傳回之後才會回到second,因為該棧已空,再次傳回後會退出

活動的應用

找到界面對應的活動

在實際中可能并不确定哪個界面對應的是哪個Activity。這時候需要進行一點修改就好了。

建立一個名為BaseActivity的普通java class,不需要注冊為Activity,編寫代碼如下

public class BaseActivity extends AppCompatActivity{
	protected void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		Log.d("BaseActivity",getClass().getSimpleName());
	}
}
           

之後将項目中Activity類中繼承的AppCompatActivity改為繼承BaseActivity,此時項目中的Activity類依然繼承AppCompatActivity,因為BaseActivity繼承于AppCompatActivity。

之後再運作程式,每當啟動一個活動日志就會列印出該活動對應的類名。

快速直接退出程式

當啟動多個程式的時候需要直接退出程式,直接按傳回鍵的話可能需要多次,要想一次退出的話可以使用一個集合作為Activity管理器來儲存目前所有活動進行處理。

public class ActivityCollector{
	public static List<Activity> acticities=new ArrayList<>();
	public static void addActivity(Activity activity){
		acticities.add(activity);
	}
	public static void removeActivity(Activity activity){
		activities.remove(activity);
	}
	public static void finishAll(){
		for (Activity activity:activities){
			if (!activity.isFinishing()){
				activity.finish();
			}
		}
		activities.clear();
	}
}
           

之後需要修改一下上面的BaseActivity代碼

public class BaseActivity extends AppCompatActivity{
	protected void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		Log.d("BaseActivity",getClass().getSimpleName());
		ActivityCollector.addActivity(this);
	}
	protected void onDestroy(){
		super.onDestroy();
		ActivityCollector.removeActivity(this);
	}
}
           

之後如果需要一次退出程式的話隻需要調用ActivityCollector.finishAll()方法即可。

啟動程式的好技巧

在啟動另一個活動的時候,需要傳遞參數的話,如果不是我們寫的活動,不太容易知道都需要什麼參數之類的,是以修改一下代碼,結構就會很清晰明了。

filename:SecondActivity.java
public class SecondActivity extends BaseAvtivity{
	public static void actionStart(Context context,String Data1,String Data2){
		Intent intent=new Intent(context,SecondActivity.class);
		intent.putExtra("param1",Data1);
		intent.putExtra("param2",Data2);
		context.startActivity(intent);
	}
	...
}
           

然後

filename:FirstActivity.java
public void onClick(View v){
	SecondActivity.actionActivity(FirstActivity.this,"123","456");
}
           

這樣就很清楚了。

balabala

安卓隻寫過幾個小程式,雖然現在隻把活動看完了,但是感覺真的認識了不少東西和方法,比如生命周期生存期,之前隻是知道現象但是具體不知道是什麼,現在有了一個系統的總結。幾句這樣,明天繼續。

OK,THANKS FOR READING.BYE BYE~