日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

用户界面开发基础

發(fā)布時(shí)間:2025/3/21 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用户界面开发基础 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Activity是Adnroid中唯一可視化的應(yīng)用程序組件。

代碼托管 Github

Activity的使用方法

Activity是Android中最核心的應(yīng)用程序組件,也是大多數(shù)程序必須使用的用于顯示界面的組件。


創(chuàng)建Activity

  • 建立一個(gè)普通的Java類,該類必須從Activity類或者其子類中繼承。
  • 重寫Activity類中的onCreate方法。
  • 在onCreate方法中使用setContentView裝載View。
  • 實(shí)際上一個(gè)類只要繼承Activity類就可以當(dāng)成一個(gè)Activity來(lái)使用了,只是沒(méi)有任何控件,只有屏幕頂端默認(rèn)的標(biāo)題欄。

    想要在Activity中添加控件,最直接的方法就是在onCreate中裝載xml布局文件或者使用Java代碼添加控件。

    如果要重寫onCreate方法,必須要調(diào)用Activity類的onCreate()方法,也就是super.onCreate(savedInstanceState)
    ,否則顯示Activity時(shí)會(huì)拋出異常。
    這是因?yàn)锳ctivity類中沒(méi)有不帶參數(shù)的onCreate().如果不顯示的調(diào)用super.onCreate(savedInstanceState),系統(tǒng)會(huì)試圖調(diào)用super.onCreate()方法,然而在Activity類中并沒(méi)有此方法。


    配置Activity

    在AndroidManifest.xml中配置Activity。

    <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>

    每一個(gè)Activity都會(huì)對(duì)應(yīng)AndroidManifest.xml問(wèn)價(jià)中的一個(gè)<activity>標(biāo)簽。

    必選屬性:android:name ,用于指定Activity類名。

    指定android:name屬性值有三種方式:

  • 指定完整的類名(packagename+classname)
  • 僅指定類名,例如 .Main , 其中前面的 . 是可選的。但是該類的包名需要在mainifest標(biāo)簽的package屬性中指定。 例如 manifest xmlns:android=”http://schemas.android.com/apk/res/android”
    package=”com.turing.base” >
  • 指定相對(duì)類名,這種方式類似第二種,只是在activity標(biāo)簽的android:name屬性中不僅指定列名,還包括部分包名。
  • 其他一些常用的屬性

    android:label

    AndroidMainfest.xml中在application和activity中都可以設(shè)置android:lable。
    android:label用來(lái)設(shè)置應(yīng)用名和標(biāo)題名。
    應(yīng)用名:
    當(dāng)主activity和application中都設(shè)置此值后,應(yīng)用名會(huì)優(yōu)先使用主activity中的值。
    標(biāo)題名:
    當(dāng)application和activity中都設(shè)置android:label時(shí),標(biāo)題名會(huì)優(yōu)先使用各個(gè)activity中的值。當(dāng)存在activity中沒(méi)有設(shè)置值時(shí),會(huì)使用application中的值。

    android:icon

    android:icon 必須指定一個(gè)圖像資源ID,用來(lái)作為應(yīng)用程序列表中的程序圖標(biāo)。 如果沒(méi)有在activity標(biāo)簽中指定,系統(tǒng)這會(huì)使用application標(biāo)簽中的android:icon屬性值來(lái)代替。

    intent-filter

    intent-filter標(biāo)簽的作用就是對(duì)Activity進(jìn)行分類,
    intent-filter標(biāo)簽內(nèi)部的
    action標(biāo)簽表示Activity可以接收的動(dòng)作
    category表示Activity所屬的種類

    實(shí)際上,action和category標(biāo)簽中的android:name屬性值只是一個(gè)普通的字符串。 在Android系統(tǒng)中預(yù)定了一些表中的動(dòng)作和種類。
    例如:
    android.intent.action.Main 和android.intent.action.category.LAUNCHER

    其中android.intent.action.Main需要定義在Main Activity類的activity標(biāo)簽中。

    當(dāng)Android系統(tǒng)運(yùn)行時(shí),會(huì)首先啟動(dòng)包含android.intent.action.Main的Activity。 作為MainActivity必須使用android.intent.category.LAUNCHER 作為其類別,表示該Activity顯示在最頂層。


    顯示其他的Activity(Intent與Activity)

    想要?jiǎng)?chuàng)建和顯示Activity,必須使用android.content.Intent作為中間的代理,并使用startActivity或startActivityForResult方法創(chuàng)建并顯示Activity。

    顯示調(diào)用Intent

    Intent intent = new Intent(this,MyActivity.class); startActivity(intent);

    第一個(gè)參數(shù)指定了Context類型的對(duì)象,第二個(gè)參數(shù)指定需要顯示的Activity類的class對(duì)象。

    如果不想再Intent類的構(gòu)造方法中指定這兩個(gè)參數(shù),也可以通過(guò)Intent類的setClass方法來(lái)指定,代碼如下:

    Intent intent = new Intent(); intent.setClass(this,MyActivity.class); startActivity(intent);

    隱式調(diào)用Intent

    隱式調(diào)用仍然需要使用Intent,但是并不需要指定要調(diào)用的Activity,而只是要指定一個(gè)Action和相應(yīng)的Category即可。 action和category這兩個(gè)標(biāo)簽,不光是提供Android系統(tǒng)使用,我們也可以將他們應(yīng)用到自定義的Activity中。

    如果是自定義的種類(category),category標(biāo)簽的屬性值至少要有一個(gè)android.intent.category.DEFAULT.

    action標(biāo)簽的android:name屬性,可以是任意字符串,但建議使用有意義的字符串,并要在程序中通過(guò)常量來(lái)引用。

    一個(gè)intent-filter標(biāo)簽可以包含多個(gè)action和category標(biāo)簽。
    一個(gè)Activity中可以包含多個(gè)intent-filter標(biāo)簽。

    當(dāng)intent-filter標(biāo)簽中,只有一個(gè)值為android.intent.action.category.DEFAULT的category時(shí),并不需要在Intent對(duì)象中指定這個(gè)category。如果包含了其他的category,必須要使用intent.addCategory方法添加相應(yīng)的category.

    實(shí)例如下:

    <!-- 該Activity未設(shè)置任何intent-filter,用顯式的方式調(diào)用這個(gè)Activity --><activity android:name=".activity.intentAct.XianSiDiaoyongAct"android:label="XianSiDiaoyongAct" /><!-- 隱式調(diào)用Activity --><activity android:name=".activity.intentAct.YinSiDiaoyngAct"android:icon="@drawable/flag_mark_red"android:label="YinSiDiaoyngAct"><intent-filter><action android:name="myAction1" /><category android:name="android.intent.category.DEFAULT" /></intent-filter><!--這個(gè)intent-filter和YinSiSelectAct的intent的相同--><intent-filter><action android:name="myAction2" /><category android:name="android.intent.category.DEFAULT" /><category android:name="mycategory"/></intent-filter></activity><activity android:name=".activity.intentAct.YinSiSelectAct"android:icon="@drawable/flag_mark_yellow"android:label="YinSiSelectAct"><!--這個(gè)intent-filter和YinSiDiaoyngAct的第二個(gè)intent-filter相同,使用這個(gè)intent-filter,屏幕會(huì)彈出一個(gè)列表,供用戶選擇--><intent-filter><action android:name="myAction2" /><category android:name="android.intent.category.DEFAULT" /><category android:name="mycategory"/></intent-filter></activity> switch (position){case 0: // 顯示調(diào)用ActivityToast.makeText(UI_Base.this,String.valueOf(position),Toast.LENGTH_SHORT).show();// 第一種方式Intent intent = new Intent(UI_Base.this, XianSiDiaoyongAct.class);startActivity(intent);// 第二種方式// Intent intent1 = new Intent();// intent1.setClass(UI_Base.this,XianSiDiaoyongAct.class);// startActivity(intent1);break;case 1:// 隱式調(diào)用ActivityIntent intent2 = new Intent("myAction1");startActivity(intent2);break;case 2: // 隱式調(diào)用兩個(gè)符合過(guò)濾條件的ActivityIntent intent3 = new Intent("myAction2");intent3.addCategory("mycategory");startActivity(intent3);break;

    如果在intent-filter標(biāo)簽中使用了默認(rèn)的category(android.intent.category.DEFAULT),在隱式調(diào)用中并不需要在Intent對(duì)象中使用addCategory方法指定。 如果非要指定,使用定義在Intent類中的常量 Intent.CATEGORY_DEFAULT.

    intent.addCategory(Intent.CATEGORY_DEFAULT);

    代碼說(shuō)明:

    第一個(gè)顯示調(diào)用,會(huì)根據(jù)指定的class來(lái)動(dòng)態(tài)創(chuàng)建Activity對(duì)象實(shí)例。
    第二個(gè)隱式調(diào)用,系統(tǒng)會(huì)查找包含myaction1的Activity,如果找到,顯示。否則拋出異常。

    第三個(gè)隱式調(diào)用符合過(guò)濾條件的Activity,由于有兩個(gè)Activity都包含了名為myaction2的動(dòng)作,并且都屬于名為mycategory的種類,系統(tǒng)會(huì)彈出選擇界面,用戶可以選擇其中一個(gè)運(yùn)行,如果勾選了”Use by default for this action”復(fù)選框,下次運(yùn)行會(huì)直接運(yùn)行上次選擇的Activity。


    Activity的生命周期

    整體描述

    從Activity創(chuàng)建到銷毀的過(guò)程中需要在不同的階段調(diào)用7個(gè)生命周期方法。

    procted void onCreate(Bundle savedInstanceState) procted void onStart() procted void onResume() procted void onPause() procted void onStop() procted void onRestart() procted void onDestory()

    上述7個(gè)生命周期方法分別在4個(gè)階段按照一定的順序進(jìn)行調(diào)用,4個(gè)階段分別如下

  • 開(kāi)始Activity
    onCreate—onStart—onResume
  • Activity失去焦點(diǎn)
    onPause—onStop
  • Activity重新獲得焦點(diǎn)
    onRestart—onStart—onResume
  • 關(guān)閉Activity
    onStop—onDestory
  • 如果在這4個(gè)階段執(zhí)行生命周期方法的過(guò)程中不發(fā)生狀態(tài)的改變,系統(tǒng)會(huì)按照上面的藐視依次執(zhí)行這4個(gè)階段的生命周期方法,但是如果執(zhí)行過(guò)程中改變了狀態(tài),系統(tǒng)會(huì)按更加復(fù)雜的方法調(diào)用生命周期方法。

    從上圖中我們可以看出,
    在執(zhí)行的過(guò)程中可以改變系統(tǒng)的執(zhí)行軌跡的生命周期方法是onPause和onStop。

    如果在onPause的過(guò)程中Activity重新獲得了焦點(diǎn),然后又失去了焦點(diǎn),系統(tǒng)將不會(huì)執(zhí)行onStop方法,而是按照如下順序執(zhí)行相應(yīng)的生命周期方法:
    onPause—onResume—onPause

    如果在執(zhí)行onStop方法的過(guò)程中Activity重新獲得了焦點(diǎn),然后又失去了焦點(diǎn),系統(tǒng)將不會(huì)執(zhí)行onDestory方法,而是按照如下的順序執(zhí)行相應(yīng)的生命周期方法:
    onStop—onRestart—onStart—onResume—onPause—onStop


    從官方給出的Activity生命周期圖中不難看出,這個(gè)圖中包含兩層循環(huán),第一層是:onPause—onResume—onPause。
    第二層是onStop—onRestart—onStart—onResume—onPause—onStop.

    第一層稱為焦點(diǎn)生命周期
    第二層稱為可視生命周期

    也就是說(shuō)第一層循環(huán)在Activity焦點(diǎn)的獲得與失去中循環(huán),這一過(guò)程中Activity始終可見(jiàn)。
    第二層循環(huán)在Activity可見(jiàn)與不可見(jiàn)的過(guò)程中循環(huán),在這個(gè)過(guò)程中伴隨著Activity焦點(diǎn)的獲得與失去。也就是說(shuō)Activity首先被顯示,然后會(huì)獲得焦點(diǎn),接著失去焦點(diǎn),最后由于彈出其他的Activity,使當(dāng)前的Activity變得不可見(jiàn)。

    因此Activity有如下三種生命周期:

    • 整體生命周期:onCreate……..onDestory
    • 可視生命周期:onStart…….onStop
    • 焦點(diǎn)生命周期:onResume—onPause

    演示

    public class LifeCircleActivity extends Activity {private static final String TAG = LifeCircleActivity.class.getSimpleName();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_life_circle);Log.e(TAG, "onCreate");}@Overrideprotected void onStart() {super.onStart();Log.e(TAG, "onStart");}@Overrideprotected void onResume() {super.onResume();Log.e(TAG, "onResume");}@Overrideprotected void onPause() {super.onPause();Log.e(TAG, "onPause");}@Overrideprotected void onStop() {super.onStop();Log.e(TAG, "onStop");}@Overrideprotected void onRestart() {super.onRestart();Log.e(TAG, "onRestart");}@Overrideprotected void onDestroy() {super.onDestroy();Log.e(TAG, "onDestroy");} }

    啟動(dòng)應(yīng)用程序: onCreate—onStart—onResume

    按home鍵:(失去焦點(diǎn)) onPause—onStop

    按home鍵后重新進(jìn)入:(重新獲得焦點(diǎn))onRestart—onStart—onResume

    按返回鍵:(退出) onPause–onStop—onDestory


    在不同Activity之間傳遞數(shù)據(jù)

    Activity之間切換時(shí),不可避免的要進(jìn)行數(shù)據(jù)傳遞,例如在單擊列表中的某個(gè)列表項(xiàng)時(shí),小需要編輯與這個(gè)列表項(xiàng)相關(guān)的數(shù)據(jù),這個(gè)時(shí)候就需要在顯示一個(gè)Activity,然后將原始數(shù)據(jù)傳遞個(gè)這個(gè)Activity,這就是一個(gè)典型的數(shù)據(jù)傳遞的過(guò)程。

    在Android中傳遞數(shù)據(jù)的方法很多,介紹4中比較常用的數(shù)據(jù)傳遞方法

    • 通過(guò)Intent傳遞數(shù)據(jù)
    • 通過(guò)靜態(tài)(static)變量傳遞數(shù)據(jù)
    • 通過(guò)剪切板(Clipboard)傳遞數(shù)據(jù)
    • 通過(guò)全局變量傳遞數(shù)據(jù)

    使用Intent傳遞數(shù)據(jù)

    這是最常用的一種數(shù)據(jù)傳遞方法。
    通過(guò)Intent類的putExtra方法可以將簡(jiǎn)單類型的數(shù)據(jù)或者可序列化的對(duì)象保存在Intent對(duì)象中,然后在目標(biāo)Activity中使用getXXX(getInt,getString。。。。)方法獲得這些數(shù)據(jù)。

    關(guān)鍵代碼如下:

    Intent intent5 = new Intent(UI_Base.this,GetIntentActivity.class);//簡(jiǎn)單類型intent5.putExtra("intent_string","通過(guò)Intent傳遞的字符串");intent5.putExtra("intent_int", 20);// 可序列化的對(duì)象Data data = new Data();data.setId(99);data.setName("ZTE");intent5.putExtra("intent_object", data);startActivity(intent5); // 獲取StringString msg = getIntent().getStringExtra("intent_string");LogUtils.d("String:" + msg);// 獲取Intint value = getIntent().getExtras().getInt("intent_int");LogUtils.d("int:" + value);int vaule2 = getIntent().getIntExtra("intent_int" , 0);LogUtils.d("第二種獲取方式:" + vaule2 );// 獲取可序列化對(duì)象Data data = (Data) getIntent().getSerializableExtra("intent_object");LogUtils.d("Data: name" + data.getName() + ",id:" + data.getId());StringBuffer sb = new StringBuffer();sb.append("intent_string:" + msg);sb.append("\n");sb.append("intent_int:" + value);sb.append("\n");sb.append("intent_object: name-"+data.getName());sb.append("\n");sb.append("intent_object: id-"+data.getId());tv_getIntent.setText(sb.toString());

    Data implements Serializable

    public class Data implements Serializable {public int id;public String name;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;} }

    Data類是可序列化的,也就是實(shí)現(xiàn)了java.io.Serializable接口。


    使用靜態(tài)變量傳遞數(shù)據(jù)

    雖然intent可以很方便的在Activity中間傳遞數(shù)據(jù),這也是官方推薦的數(shù)據(jù)傳遞方式。

    但是Intent也有其局限性,Intent無(wú)法傳遞不能序列化的對(duì)象,也即是沒(méi)有實(shí)現(xiàn)java.io.Serializable接口的類的對(duì)象。
    比如Canvas對(duì)象就無(wú)法通過(guò)Intent對(duì)象傳遞,如果傳遞自定義類的對(duì)象,也必須實(shí)現(xiàn)java.io.Serializable接口才可以。 如果沒(méi)有源代碼,而且還沒(méi)有實(shí)現(xiàn)Serializable接口,使用Intent對(duì)象就無(wú)能為力了。

    步驟:
    1.startActivity之前,為靜態(tài)變量賦值
    2.目標(biāo)類定義靜態(tài)變量接收(也可以在其他類中定義)

    Intent intent6 = new Intent(UI_Base.this,StaticTransmitActivity.class); // 賦值 StaticTransmitActivity.msg="通過(guò)static變量來(lái)的"; StaticTransmitActivity.age = 88 ;StaticTransmitActivity.data = new Data();StaticTransmitActivity.data.setName("Jack");StaticTransmitActivity.data.setId(77);startActivity(intent6); public class StaticTransmitActivity extends AppCompatActivity {public static String msg ;public static int age ;public static Data data;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_static_transmit);StringBuffer sb = new StringBuffer();sb.append("msg:" + msg);sb.append("\n");sb.append("age:"+age);sb.append("\n");sb.append("data name:"+data.getName());sb.append("\n");sb.append("data id:"+data.getId());TextView textView = (TextView)findViewById(R.id.id_tv_static);textView.setText(sb.toString());} }

    使用剪切板傳遞變量(String類型和復(fù)雜對(duì)象)

    在Activity之間傳遞對(duì)象還可以利用一些技巧。無(wú)論是windows 還是Linux,都會(huì)支持一種叫做剪切板的技術(shù)。

    String類型

    Intent intent7 = new Intent(UI_Base.this, ClipBoardTransActivity.class);ClipboardManager clipboardManager = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE); // api 11的方法 @TargetApi(Build.VERSION_CODES.HONEYCOMB) clipboardManager.setText("通過(guò)Clipboard傳遞數(shù)據(jù)"); startActivity(intent7); public class ClipBoardTransActivity extends AppCompatActivity {@TargetApi(Build.VERSION_CODES.HONEYCOMB)@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_clip_board_trans);ClipboardManager clipboardManager = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);String msg = clipboardManager.getText().toString();TextView textView = (TextView) findViewById(R.id.id_tv_clipboard);textView.setText(msg);} }

    在上述的代碼中使用了getSystemService方法獲得了一個(gè)系統(tǒng)服務(wù)對(duì)象,也就是ClipboardManager對(duì)象,該對(duì)象用于管理系統(tǒng)剪切板,并使用ClipboardManager.setText方法向剪切板中保存了一個(gè)字符串,通過(guò)getText可以獲取。

    但是ClipboardManager對(duì)象只支持向剪切板讀寫字符串,并不支持其他的類型,更別提復(fù)雜的對(duì)象了。

    當(dāng)然了,如果是其他類型的數(shù)據(jù),比如int ,可以將起轉(zhuǎn)換成字符串。

    復(fù)雜對(duì)象

    如果是對(duì)象類型呢,比如之前的Data對(duì)象能否通過(guò)剪切板傳遞呢?答案是肯定的,只是需要通過(guò)Base64進(jìn)行編碼解碼轉(zhuǎn)換。

    由于Data是可序列化的對(duì)象,因此完全可以將Data抓換成byte[]類型的數(shù)據(jù),然后將byte[]類型的數(shù)據(jù)再進(jìn)行Base4編碼(通過(guò)Email發(fā)送附件就是將附件轉(zhuǎn)換成為Base64格式的字符串發(fā)送的)轉(zhuǎn)換成字符串。
    代碼演示,通過(guò)剪切板傳遞Data對(duì)象。

    Intent intent8 = new Intent(UI_Base.this, ClipboardTransObjectDataAct.class);ClipboardManager cbm = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);// 通過(guò)Clipboard傳遞復(fù)雜對(duì)象Data data3 = new Data();data3.setId(55);data3.setName("Clipboard傳遞復(fù)雜對(duì)象");// 將data2對(duì)象轉(zhuǎn)換成Base64格式的字符串ByteArrayOutputStream baos = new ByteArrayOutputStream();String base64Str = "";try {ObjectOutputStream oos = new ObjectOutputStream(baos);oos.writeObject(data3);// 使用Base64.encodeToString方法將byte[]數(shù)據(jù)轉(zhuǎn)換為Base64字符串base64Str = Base64.encodeToString(baos.toByteArray(),Base64.DEFAULT);oos.close();} catch (IOException e) {e.printStackTrace();}// 向剪切板寫入Base64格式的字符串cbm.setText(base64Str);startActivity(intent8);

    解碼

    public class ClipboardTransObjectDataAct extends AppCompatActivity {@TargetApi(Build.VERSION_CODES.HONEYCOMB)@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_clipboard_trans_object_data);ClipboardManager cbm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);// 從剪切板中獲取Base64編碼格式的字符串String base64Str = cbm.getText().toString();// 將Base64格式的字符串還原為byte[]格式的數(shù)據(jù)byte[] buffer = Base64.decode(base64Str,Base64.DEFAULT);ByteArrayInputStream bais = new ByteArrayInputStream(buffer);try {ObjectInputStream ois = new ObjectInputStream(bais);// 將byte[]數(shù)據(jù)還原為Data對(duì)象Data data = (Data)ois.readObject();// 輸出TextView tv = (TextView)findViewById(R.id.id_tv_clipboard_trans_object);tv.setText(base64Str + "\n\n data.id:" + data.getId() + "\ndata.name:"+data.getName());} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}} }

    說(shuō)明:
    Base64類是從Android2.2開(kāi)始支持的,2.1及其以下版本無(wú)法通過(guò)Android SDK API 進(jìn)行Base64編碼和解碼,因此需要借助第三方的類庫(kù)如common httpclient才可以。


    使用全局對(duì)象傳遞變量

    雖然使用靜態(tài)變量可以傳遞任意類型的數(shù)據(jù),但是官方并不建議這樣做。如果在類中大量使用靜態(tài)變量(尤其是很占用資源的變量,如Bitmap對(duì)象)可能會(huì)造成內(nèi)存溢出異常,而且可能因?yàn)殪o態(tài)變量在很多類中出現(xiàn)而造成代碼難以維護(hù)和混亂。

    我們可以使用一種更優(yōu)雅的數(shù)據(jù)傳遞方式–全局對(duì)象。這種方式可以完全取代靜態(tài)變量。

    步驟:

  • 全局類 必須繼承android.app.Application
  • AndroidManifest.xml中的Application標(biāo)簽的android:name屬性指定這個(gè)類
  • public class AppContext extends Application {/*** 演示使用全局變量傳遞數(shù)據(jù) appName data*/public String appName;public Data data = new Data();@Overridepublic void onCreate() {super.onCreate();/*** 支持直接打印數(shù)據(jù)集合,如List、Set、Map、數(shù)組等全局配置log輸出不需要設(shè)置tag準(zhǔn)確顯示調(diào)用方法、行,快速定位所在文件位置.*/// 配置日志是否輸出(默認(rèn)true)LogUtils.configAllowLog = true;// 配置日志前綴LogUtils.configTagPrefix = "MrYang-";} }

    Manifest.xml指定全局類

    <applicationandroid:name=".AppContext"android:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme"> AppContext context = (AppContext)getApplication();context.appName = "ANDROID BASE";context.data.setId(0000);context.data.setName("通過(guò)全局變量來(lái)傳遞數(shù)據(jù)");Intent intent9 = new Intent(UI_Base.this, ApplicationTransActivity.class);startActivity(intent9); public class ApplicationTransActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_application_trans);// 獲取全局變量AppContext context = (AppContext)getApplication();String name = context.appName;Data data = context.data;StringBuffer sb = new StringBuffer();sb.append("AppContext appname:" + name );sb.append("\n");sb.append("AppContext data.id:" + data.getId());sb.append("\n");sb.append("AppContext data.name:" + data.getName());TextView textView = (TextView) findViewById(R.id.id_tv_app_trans);textView.setText(sb.toString());} }

    全局對(duì)象所對(duì)應(yīng)的類必須是android.app.Application的子類

    全局類中不需要定義靜態(tài)變量,只需要定義成員變量即可
    而且全局類中必須要有一個(gè)無(wú)參的構(gòu)造方法,或者不編寫任何代碼的構(gòu)造方法(系統(tǒng)會(huì)自動(dòng)的建立一個(gè)無(wú)參數(shù)的構(gòu)造方法)。

    這個(gè)類和Activity一樣,由系統(tǒng)自動(dòng)創(chuàng)建,因此,必須要有一個(gè)無(wú)參的構(gòu)造方法。

    只編寫一個(gè)全局類是不會(huì)自動(dòng)創(chuàng)建全局對(duì)象的,因?yàn)锳ndroid系統(tǒng)并不知道哪個(gè)是全局類,因此需要在AndroidManifest.xml中的application標(biāo)簽的android:name屬性來(lái)執(zhí)行這個(gè)類。

    指定全局類后,在程序運(yùn)行后,全局對(duì)象會(huì)被自動(dòng)創(chuàng)建,而且會(huì)一直在內(nèi)存中駐留,直到應(yīng)用程序徹底退出內(nèi)存。

    四種方式比較

    雖然上述始終方法在某些情況下可以相互取代,但是根據(jù)具體情況使用不同的數(shù)據(jù)傳遞方法會(huì)使程序更加便于維護(hù)。

    對(duì)于向其他Activity中傳遞簡(jiǎn)單類型(int 、String、short、bool等)或者可序列化的對(duì)象時(shí),建議使用Intent。

    如果傳遞不可序列化的對(duì)象,可以采用靜態(tài)變量或者全局對(duì)象的方式,不過(guò)按照官方的建議,最好是采用全局對(duì)象的方式。

    另外如果想要使某些數(shù)據(jù)長(zhǎng)時(shí)間駐留內(nèi)存,以便程序隨時(shí)的取用,最好采用全局對(duì)象的方式。當(dāng)然如果數(shù)據(jù)不復(fù)雜,也可以采用靜態(tài)變量的方式

    至于剪切板,如果不是特殊情況,并不建議使用,因?yàn)檫@可能會(huì)影響到其他的程序(其他程序也可能使用剪切板)


    返回?cái)?shù)據(jù)到前一個(gè)Activity

    在應(yīng)用程序中,不僅要向Activity傳遞數(shù)據(jù),同時(shí)也要從Activity中返回?cái)?shù)據(jù),一般建議采用Intent這種方式來(lái)返回?cái)?shù)據(jù),需要使用startActivityForResult方法來(lái)顯示Activity。
    代碼如下

    Intent intent = new Intent(this,XX.class); startActivityForResult(intent,1);

    其中startActivityForResult方法有2個(gè)參數(shù),第二個(gè)參數(shù)是一個(gè)int類型的請(qǐng)求碼,可以是任意的整數(shù),只是為了區(qū)分請(qǐng)求的來(lái)源,以便處理返回結(jié)果。

    大致步驟如下:

    啟動(dòng)一個(gè)ForResult的意圖:
    Intent intent = new Intent(MainAcitvity.this,RequestActivity.class);
    //發(fā)送意圖標(biāo)示為REQUSET=1
    startActivityForResult(intent, REQUSET);

    B Activity處理數(shù)據(jù):

    Intent intent=new Intent();
    intent.putExtra(KEY_USER_ID, et01.getText().toString());
    setResult(RESULT_OK, intent);
    finish();

    代碼演示如下:

    A類

    Intent intent10 = new Intent(UI_Base.this, StarActivityForResultAct.class);startActivityForResult(intent10, 1); // 請(qǐng)求碼1 一定要>=0 @Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);switch (requestCode){ // 請(qǐng)求碼1case 1:switch (resultCode){ // 響應(yīng)碼case 2:Toast.makeText(UI_Base.this,data.getStringExtra("value"),Toast.LENGTH_SHORT).show();break;default:break;}break;default:break;}}

    B類

    public class StarActivityForResultAct extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_star_activity_for_result);}/*** android:onClick="doSomethingThenReturn"* 對(duì)應(yīng)xml中的屬性,記得方法里面的參數(shù),否則報(bào)錯(cuò)* @param view*/public void doSomethingThenReturn(View view){Intent intent = new Intent();intent.putExtra("value","返回給前個(gè)Act的值");// 通過(guò)intent對(duì)象返回結(jié)果,setResult的第一個(gè)參數(shù)是響應(yīng)碼setResult(2, intent);// 關(guān)閉當(dāng)前Activityfinish();} } <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><Button android:id="@+id/id_btn_doSomethingThenReturn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="doSomethingThenReturn"android:text="doSomethingThenReturn"/></RelativeLayout>

    在Button標(biāo)簽中有一個(gè)屬性android:click,可以直接指定按鈕單擊事件的方法名。這樣在Activity中就不用創(chuàng)建按鈕對(duì)象而處理按鈕單擊事件了。 如果在程序中只處理單擊事件,而不直接引用相應(yīng)的對(duì)象,可以采用這種方法。


    視圖(View)

    在Android系統(tǒng)中任何可視化控件都必須從android.view.View類繼承。

    兩種方式創(chuàng)建View對(duì)象:

  • 使用XML來(lái)配置View的相關(guān)屬性,然后再裝載這些View
  • 完全使用Java代碼的方式來(lái)創(chuàng)建View
  • 視圖簡(jiǎn)介

    Android中視圖類可以分為三種

    • 布局類(Layout)
    • 視圖容器(View Container)
    • 視圖類 (例如TextView…)

    使用xml布局文件定義視圖

    注意事項(xiàng):

    • XML布局文件的擴(kuò)展名必須是xml
    • XML布局文件名必須符合Java變量的命名規(guī)則(以為在R類中會(huì)自動(dòng)生成一個(gè)變量),例如不能以數(shù)字開(kāi)頭
    • XML布局文件的根節(jié)點(diǎn)可以是任意的控件標(biāo)簽,比如<LinearLayout> <TextView>
    • XML布局文件的根節(jié)點(diǎn)必須包含android命名控件,且必須是http://schemas.android.com/apk/res/android
    • 為XML布局文件中的標(biāo)簽指定ID時(shí)需要使用這樣的格式:@+id/value ,其中@+ 語(yǔ)法標(biāo)識(shí)如果ID在R.id類中不出在,這產(chǎn)生一個(gè)與ID同名的變量,如果存在,則直接使用。 value表示ID的值。
    • 視圖ID的值也要符合java變量的命名規(guī)則

    在獲得XML布局文件中的視圖對(duì)象需要注意如下幾點(diǎn)

    • finddViewById需要在setContentView之后使用。
    • findViewById只能獲得已經(jīng)裝載的XML布局文件中的視圖對(duì)象。
    • 在不同的XML布局文件中可以存在相同ID的視圖,但是在同一個(gè)XML文件中,雖然也可以有相同ID的視圖,但是通過(guò)ID獲取視圖時(shí),只能夠獲取按照定義的順序的第一個(gè)視圖對(duì)象,其他相同ID值的視圖對(duì)象將無(wú)法回去,因此在同一個(gè)XML布局文件中盡量使視圖ID唯一。

    在代碼中控制視圖

    舉個(gè)例子:

    TextView tv = (TextView)findViewById(R.id.textView1); tv.setText("UUUUU");

    還可以使用字符串資源對(duì)TextView進(jìn)行文本修改

    tv.setText(R.string.hello);

    注意:當(dāng)seText方法的參數(shù)是int型時(shí),會(huì)被認(rèn)為這個(gè)參數(shù)值是一個(gè)字符串資源ID,因此,如果要將TextView的文本設(shè)置為一個(gè)整數(shù),需要將這個(gè)整數(shù)抓換位String類型。例如 tv.setText(String.valueOf(200));將TextView的文本設(shè)置為200

    在更高級(jí)的Android應(yīng)用中,往往需要?jiǎng)討B(tài)的添加視圖,要實(shí)現(xiàn)這個(gè)功能,最重要的是要獲得被添加的視圖所在的容器對(duì)象,這個(gè)容器對(duì)象所對(duì)應(yīng)的類需要繼承ViewGroup類。

    將其他的視圖添加到當(dāng)前的容器視圖中的步驟如下:

  • 獲得當(dāng)前容器視圖對(duì)象
  • 獲得或者創(chuàng)建待添加的視圖對(duì)象
  • 將相對(duì)應(yīng)的視圖對(duì)象添加到容器視圖中。
  • 場(chǎng)景:
    假設(shè)有兩個(gè)xml布局文件:test1.xml test2.xml
    這兩個(gè)xml的根節(jié)點(diǎn)都是<LinearLayout>, 目的獲取test2.xml中的LinearLayout對(duì)象,并將該對(duì)象作為test1.xml文件中的<LinearLayout>標(biāo)簽的子節(jié)點(diǎn)添加到test1.xml的LinearLayout對(duì)象中。

    第一種方式:

    // 獲得test1.xml中的LinearLayout對(duì)象 LinearLayout l1 = (LinearLayout)getLayoutInflater().inflate(R.layout.test,null); // 將test1.xml中的LinearLayout對(duì)象設(shè)置為當(dāng)前容器視圖 setContentView(l1); // 獲取test2.xml中的LinearLayout對(duì)象,并將該對(duì)象添加到test1.xml中的LinearLayout中 LinearLayout l2 = (LinearLayout)getInflater().inflater(R.layout.test2,l1);

    參數(shù)解釋: inflate()方法第一個(gè)參數(shù)標(biāo)識(shí)XML布局資源文件的ID,
    第二個(gè)參數(shù)標(biāo)識(shí)獲得容器對(duì)象后,要將該對(duì)象添加到哪個(gè)視圖對(duì)象中。

    如果不想添加到任何其他的容器中,設(shè)置為null即可。

    第二種方式:

    // 獲得test1.xml中的LinearLayout對(duì)象 LinearLayout l1 = (LinearLayout)getLayoutInflater().inflate(R.layout.test,null); // 將test1.xml中的LinearLayout對(duì)象設(shè)置為當(dāng)前容器視圖 setContentView(l1); // 獲取test2.xml中的LinearLayout對(duì)象,并將該對(duì)象添加到test1.xml中的LinearLayout中 LinearLayout l2 = (LinearLayout)getInflater().inflater(R.layout.test2,null);l1.addView(l2);

    inflate方法第二個(gè)參數(shù)設(shè)置為null, 通過(guò)addView方法添加

    第三種方式

    完全使用Java代碼創(chuàng)建一個(gè)視圖對(duì)象,并將該對(duì)象添加到容器視圖中

    TextView tv = new TextView(this); l1.addView(tv)

    注意事項(xiàng):

    • 如果使用setContentView方法將試圖容器設(shè)置為當(dāng)前視圖后,還想要向試圖容器中添加新的視圖或者進(jìn)行其他操作,setContentView方法的參數(shù)值應(yīng)直接使用容器視圖對(duì)象,因?yàn)檫@樣可以向容器視圖對(duì)象中添加新的視圖。
    • 一個(gè)視圖只能有一個(gè)父視圖。也就是說(shuō)一個(gè)視圖只能被包含在一個(gè)容器視圖中。因此,在向容器視圖中添加其他視圖時(shí),不能將XML布局文件中非根節(jié)點(diǎn)的視圖對(duì)象添加到其他的容器視圖中。

    布局(Layout)


    框架布局FrameLayout

    最簡(jiǎn)單的布局方式,FrameLayout 以層疊放方式顯示,第一個(gè)添加到框架布局中的視圖顯示在最底層,最后一個(gè)放在最頂層。
    上一層視圖會(huì)覆蓋下一層視圖,類似于堆棧,因此也被稱為堆棧布局。


    線性布局LinearLayout

    最常用的布局方式。

    線性布局可以分為水平線性布局和垂直先行布局。
    android:orientation ,兩個(gè)字 horizontal 、vertical。 默認(rèn)horizontal。

    一個(gè)非常重要的屬性 gravity,用于控制布局中視圖的位置。
    設(shè)置多個(gè)屬性,需要使用“|”分隔,在屬性值和“|”之間不能有其他符號(hào)(例如空格和制表符等)。

    屬性值描述
    top將視圖放到屏幕頂端
    bottom將視圖放到屏幕底端
    left將視圖放到屏幕左側(cè)
    right將視圖放到屏幕右側(cè)
    center_vertical將視圖按垂直方向居中顯示
    center_horizontal將視圖按水平方向居中顯示
    center將視圖按垂直和水平方向居中顯示

    LinearLayout標(biāo)簽中的子標(biāo)簽還可以使用layout_gravity和layout_weight屬性來(lái)設(shè)置每一個(gè)視圖的位置

    layout_gravity 屬性的取值和gravity的取值相同,表示當(dāng)前視圖在布局中的位置。

    layout_weight屬性是一個(gè)非負(fù)整數(shù),如果該屬性值大于0,線性布局會(huì)根據(jù)水平或者垂直方向以及不同視圖的layout_weight屬性值占所有視圖的layout_weight屬性值之和的比例為這些視圖分配自己說(shuō)占用的區(qū)域,視圖將按相應(yīng)比例拉伸。


    相對(duì)布局RelativeLayout

    設(shè)置某一個(gè)視圖相對(duì)于其他視圖的位置。

    表格布局TableLayout

    一個(gè)表格布局由一個(gè)<TableLayout>標(biāo)簽和若干個(gè)<TableRow>標(biāo)簽組成

    絕對(duì)布局AbsoluteLayout

    android:layout_x 和android:layout_y設(shè)置橫縱坐標(biāo)。

    重用XML布局

    布局重用

    <inclued>

    ??include標(biāo)簽可以實(shí)現(xiàn)在一個(gè)layout中引用另一個(gè)layout的布局,這通常適合于界面布局復(fù)雜、不同界面有共用布局的APP中,比如一個(gè)APP的頂部布局、側(cè)邊欄布局、底部Tab欄布局、ListView和GridView每一項(xiàng)的布局等,將這些同一個(gè)APP中有多個(gè)界面用到的布局抽取出來(lái)再通過(guò)include標(biāo)簽引用,既可以降低layout的復(fù)雜度,又可以做到布局重用(布局有改動(dòng)時(shí)只需要修改一個(gè)地方就可以了)。

    inclued標(biāo)簽,首字母要小寫,只有l(wèi)ayout屬性是必選的。

    ?include標(biāo)簽的使用很簡(jiǎn)單,只需要在布局文件中需要引用其它布局的地方,使用layout=”@layout/child_layout”就可以了:

    <include layout="@layout/titlebar"/>

    如果要覆蓋布局的尺寸,必須同時(shí)覆蓋android:layout_weight和android:layout_height . 不能只覆蓋一個(gè),否則無(wú)效

    建議將給include標(biāo)簽調(diào)用布局設(shè)置寬高、位置、ID等工作放在調(diào)用布局的根標(biāo)簽中,這樣可以避免給include標(biāo)簽設(shè)置屬性不當(dāng)造成的各種問(wèn)題(之前遇到過(guò)給include標(biāo)簽設(shè)置android:id屬性后,程序?qū)嵗硬季种薪M件失敗的現(xiàn)象):

    ?應(yīng)該這樣:<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/bottomBarLayoutId"android:layout_width="match_parent"android:layout_height="61dp"android:orientation="horizontal"android:layout_alignParentBottom="true">。。。 </LinearLayout><include layout="@layout/include_voice_ctrl_bar_layout" />而不是這樣:<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal">。。。 </LinearLayout><include android:id="@+id/bottomBarLayoutId"android:layout_width="match_parent"android:layout_height="61dp"android:layout_alignParentBottom="true"layout="@layout/include_voice_ctrl_bar_layout"/>

    優(yōu)化XML布局

    減少視圖層級(jí)
    <merge />

    <merge />標(biāo)簽在UI的結(jié)構(gòu)優(yōu)化中起著非常重要的作用,它可以刪減多余的層級(jí),優(yōu)化UI。<merge />多用于替換FrameLayout或者當(dāng)一個(gè)布局包含另一個(gè)時(shí),<merge />標(biāo)簽消除視圖層次結(jié)構(gòu)中多余的視圖組。例如你的主布局文件是垂直布局,引入了一個(gè)垂直布局的include,這是如果include布局使用的LinearLayout就沒(méi)意義了,使用的話反而減慢你的UI表現(xiàn)。這時(shí)可以使用<merge />標(biāo)簽優(yōu)化

    <merge xmlns:android="http://schemas.android.com/apk/res/android"><Button android:layout_width="fill_parent" android:layout_height="wrap_content"android:text="@string/add"/><Button android:layout_width="fill_parent" android:layout_height="wrap_content"android:text="@string/delete"/></merge>

    現(xiàn)在,當(dāng)你添加該布局文件時(shí)(使用<include />標(biāo)簽),系統(tǒng)忽略<merge />節(jié)點(diǎn)并且直接添加兩個(gè)Button。更多<merge />介紹可以參考《Android Layout Tricks #3: Optimize by merging》

    需要時(shí)使用<ViewStub />

    <ViewStub />標(biāo)簽最大的優(yōu)點(diǎn)是當(dāng)你需要時(shí)才會(huì)加載,使用他并不會(huì)影響UI初始化時(shí)的性能。各種不常用的布局想進(jìn)度條、顯示錯(cuò)誤消息等可以使用<ViewStub />標(biāo)簽,以減少內(nèi)存使用量,加快渲染速度。<ViewStub />是一個(gè)不可見(jiàn)的,大小為0的View。<ViewStub />標(biāo)簽使用如下:

    <ViewStub android:id="@+id/stub_import"android:inflatedId="@+id/panel_import"android:layout="@layout/progress_overlay"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_gravity="bottom" />

    當(dāng)你想加載布局時(shí),可以使用下面其中一種方法:

    ((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE); // or View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();

    當(dāng)調(diào)用inflate()函數(shù)的時(shí)候,ViewStub被引用的資源替代,并且返回引用的view。 這樣程序可以直接得到引用的view而不用再次調(diào)用函數(shù)findViewById()來(lái)查找了。
    注:ViewStub目前有個(gè)缺陷就是還不支持 <merge /> 標(biāo)簽。

    更多<ViewStub />標(biāo)簽介紹可以參考《Android Layout Tricks #3: Optimize with stubs》


    查看APK文件中的布局

    AXMLPrinter2工具

    總結(jié)

    以上是生活随笔為你收集整理的用户界面开发基础的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。