編輯:關於Android編程
作為Android App,給人第一印象的就是用戶界面(UI),簡潔友好的UI,自然會給用戶優秀的體驗,自然很容易就得到用戶的認可和贊許,這樣App才變得真正的有價值。所以作為開發App的第一步,UI尤為重要,構建UI有很多種方式:xml靜態布局、java動態代碼、HTML構建(借助WebView)和第三方開源框架等。
在Android中絕大部分的UI組件都是存放在android.widget包及其子包、android.view包及其子包,其中所有的UI視圖組件都是繼承自View類,其實View有點類似Swing編程的JPanel,代表著一個空白的矩形區域。View類還有一個重要的子類ViewGroup,所以它也具有View的特性,但它主要用來充當View的容器,將其中的View視作自己的孩子,對它的子View進行管理,當然它的孩子也可以是ViewGroup類型。但是ViewGroup並不難單獨使用往往是作為其他的組件的容器。值得注意的是Android中的View與我們以前理解的“視圖”不同。在Android中,View比視圖具有更廣的含義,它包含了用戶交互和顯示,更像Windows操作系統中的window。ViewGroup(根節點)和它的孩子們(View和ViewGroup)以樹形結構形成了一個層次結構,View類有接受和處理消息的功能,android系統所產生的消息會在這些ViewGroup和 View之間傳遞。
由上圖可見,作為容器的ViewGroup可以包含作為葉子節點的View,也可以包含作為更低層次的子ViewGroup,而子ViewGroup又可以包含下一層的葉子節點的View和ViewGroup。事實上,這種靈活的View層次結構可以形成非常復雜的UI布局,我們也可以據此設計並開發非常精致的UI界面。
一般來說,開發Android應用程序的UI時我們都不是直接使用View和ViewGroup,而是使用他們各種的派生類。
View的直接子類:AnalogClock,ImageView,KeyboardView,
ProgressBar,SurfaceView,TextView,ViewGroup,ViewStub
View的間接子類:AbsListView,AbsSeekBar, AbsSpinner, AbsoluteLayout,
AdapterView,AdapterViewAnimator,
AdapterViewFlipper, AppWidgetHostView,
AutoCompleteTextView,Button,CalendarView, CheckBox, CheckedTextView,
Chronometer, CompoundButton
ViewGroup的直接子類:AbsoluteLayout,AdapterView,FragmentBreadCrumbs,FrameLayout,LinearLayout,RelativeLayout,SlidingDrawer
ViewGroup的間接子類:AbsListView,AbsSpinner, AdapterViewAnimator,
AdapterViewFlipper, AppWidgetHostView, CalendarView, DatePicker,
DialerFilter, ExpandableListView, Gallery,
GestureOverlayView,GridView,HorizontalScrollView,
ImageSwitcher,ListView
以上這些所有基類、派生類都是Android framework層集成的標准系統類,開發者在應用開發中可直接引用SDK中這些系統類及其API。當然在很多時候,直接使用這些系統類並不能滿足應用開發的需要,我們還得自己去開發自定義控件來滿足自己的項目需求(這是後話了,以後再總結)。
在Android中組件的幾乎所有屬性都提供了兩種方式來控制其行為,所以我們既可以在xml布局中直接靜態賦值,也可以在代碼中通過對應的方法進行動態控制,關系如下:
ViewGroup是一個特殊的View類,它繼承於android.view.View。它的功能就是裝載和管理下一層的View對象和ViewGroup對象。而ViewGroup是布局管理器(layout)及View容器的基類。而且ViewGroup中,還定義了2個內部類:ViewGroup.LayoutParams、ViewGroup.MarginLayoutParams。這兩個內部類定義了一個顯示對象的位置、大小等屬性,View還可以通過LayoutParams中的這些屬性值來管理控制布局
ViewGroup.MarginLayoutParams繼承自ViewGroup.LayoutParams
LinearLayout:以單一方向對其中的顯示對象進行排列顯示,如以垂直排列顯示,則布局管理器中將只有一列;如以水平排列顯示,則布局管理器中將只有一行。同時,它還可以對個別的顯示對象設置顯示比例。
TableLayout:以擁有任意行列的表格對顯示對象進行布局,每個顯示對象被分配到各自的單元格之中,但單元格的邊框線不可見。
RelativeLayout:允許通過指定顯示對象相對於其它顯示對象或父級對象的相對位置來布局。如一個按鈕可以放於另一個按鈕的左邊,或者可以放在布局管理器的中央。
AbsoluteLayout:允許以坐標的方式,指定顯示對象的具體位置,左上角的坐標為(0, 0),向下及向右,坐標值變大。這種布局管理器由於顯示對象的位置定死了,所以在不同的設備上,有可能會出現最終的顯示效果不一致,基本不用。
xml布局最常用,如果可以的話優先考慮xml靜態布局,官方也十分推薦使用這種方式,因為他減弱了代碼和視圖的耦合。
先定義xml布局文件<code class=" hljs handlebars"><linearlayout 3e--=""> xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity" android:orientation="vertical"> <com.crazymo.costompopwindow android:id="" ...=""> <com.crazymo.costompopwindow> <framelayout android:id="@+id/id_content_layout" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> </framelayout></com.crazymo.costompopwindow></com.crazymo.costompopwindow></linearlayout></code>然後再在Activity裡的onCreate方法裡調用setContentView(layoutId)設置即可
通過布局構造方法創建一種布局對象
把布局設置到Activity裡,相當於是把布局對象添加到Activity裡
再設置布局的相關屬性
根據業務需求設置View對象及位置
再把View對象add至布局中
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout layout=new LinearLayout(this);
super.setContentView(layout);
layout.setOrientation(LinearLayout.VERTICAL);
TextView show=new TextView(this);
show.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
layout.addView(show);
}
}
又如可以在Activity中動態添加和刪除控件
/*1 取到那個Layout*/
ViewGroup viewGroup = (ViewGroup)findViewById(R.id.layout);
/*2添加時,先創建對象,然後添加*/
ImageView newImageView = new ImageView(
Animation2Activity.this);
newImageView.setImageResource(R.drawable.an);
viewGroup.addView(newImageView,
new LayoutParams(
LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
/*3 刪除時,直接刪除。*/
viewGroup.removeView(imageView);
public class PicBrowserActivity extends Activity {
private ImageView mImg;
private int[] imgs=new int[]{
R.mipmap.ic_blue_launcher,
R.mipmap.ic_green_launcher,
R.mipmap.ic_red_launcher,
R.mipmap.pool_balls_05,
R.mipmap.ic_toy,
R.mipmap.ic_launcher
};
private int curIndex=0;//當前圖片的id
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
mImg= (ImageView) findViewById(R.id.id_show_img);
final Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what==0x123){
mImg.setImageResource(imgs[curIndex++]);
if(curIndex>=5){
curIndex=5;
}
}
}
};
new Timer().schedule(new TimerTask() {
@Override
public void run() {
Message msg=new Message();
msg.what=0x123;
handler.sendMessage(msg);
}
},0,1000);
}
}
其實這一種嚴格來說應該不算是全新的方式,主要原理就是借助了WebView來實現javascript和java代碼的互相交互,所以我們還可以通過HTML/HTML5的方式來構建自己的UI。
首先,定義WebView,既然我們要借助WebView,肯定要先在xml布局文件中定義(當然也可以在代碼中去構建)布局很簡單我就只定義了一個WebView
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingleft="@dimen/activity_horizontal_margin" android:paddingright="@dimen/activity_horizontal_margin" android:paddingtop="@dimen/activity_vertical_margin" android:paddingbottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <webview android:id="@+id/id_table_webview" android:layout_width="match_parent" android:layout_height="match_parent"> </webview></relativelayout> </code>然後編寫我們的html文件(也可以在代碼中通過字符串的形式拼接成)
<!DOCTYPE html> <head> <meta http-equiv="Content-Type" context="text/html;charset=UTF-8"> <title>HTML UI FOR Andoid</title> <script type="text/javascript"> /**此方法是提供給java代碼調用的,和其他的js方法沒有什麼不同,就像我們在web開發下用js動態生成table一樣**/ function show(datas){ var jsonobjs=eval(datas); var table=document.getElementById("table"); for(var i=0;i<jsonobjs.length;i++){ var tr=table.insertRow(table.rows.length); var td=tr.insertCell(0); var td2=tr.insertCell(1); td2.align="right"; var td3=tr.insertCell(2); td3.align="center"; td.innerHTML=jsonobjs[i].id; td2.innerHTML=jsonobjs[i].name; td3.innerHTML=jsonobjs[i].phone; } } </script> </head> <!--此employee為我們自己定義的js 對象,對應我們從Activity傳遞過來的js 自定義對象--> <body onload="javascript:employee.showcontacts()"> <table border="1" width="100%" id="table" cellspacing="1"> <tr> <td width="35%">姓名</td> <td width="30%">工號</td> <td width="35%">電話</td> </tr> </table> <a href="javascript:window.location.reload()">刷新</a> </body>
單獨的HTML界面效果是這樣的
public class ContactsService {
/**
* 模擬獲取信息
* @return
*/
public List getContactsImf(){
List contacts=new ArrayList();
contacts.add(new Contacts(2009,"CrazyMO",9389281));
contacts.add(new Contacts(2010,"Jim",5641021));
contacts.add(new Contacts(2011,"Winds",897512));
contacts.add(new Contacts(2012,"Jack",4524323));
return contacts;
}
}
最後我們的重頭戲就是在清單中申請訪問網絡的權限和實現在WebView中實現java和javascript代碼的交互,其實在這裡有很多細節都需要注意我都在代碼中一一注明,都是使用webView的相關知識點,這裡不便擴展,否則跑偏啦。
package com.crazymo.htmlui;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.webkit.JavascriptInterface;
import android.webkit.WebSettings;
import android.webkit.WebView;
import com.crazymo.entity.Contacts;
import com.crazymo.service.ContactsService;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.List;
public class MainActivity extends Activity {
private WebView mWebview;
private ContactsService mContactsService;
private final String url = "file:///android_asset/index.html";
@SuppressLint("JavascriptInterface")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebview = (WebView) findViewById(R.id.id_table_webview);//獲取WebVIew
mWebview.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);///一系列的初始化設置
mWebview.getSettings().setAllowFileAccess(true);// 設置允許訪問文件數據
mWebview.getSettings().setSupportZoom(true);//支持放大網頁功能
mWebview.getSettings().setBuiltInZoomControls(true);//支持縮小網頁功能
mWebview.getSettings().setJavaScriptEnabled(true);
mWebview.addJavascriptInterface(new JSObject(), "employee");//前面對象,後面js中的調用名(我們可以看成這個JSObject類的實例是employee,用於給javascript裡調用
mWebview.setWebViewClient(new MyWebViewCient());//設置打開i時不用系統浏覽器。使用本地WebView打開
mWebview.loadUrl(url);
mContactsService = new ContactsService();
}
private final class JSObject {
/**
* html中通過自定義的js 對象調用
* 高能預警:If you've set your targetSdkVersion to 17 or higher, you must add the @JavascriptInterface
即在一切需要在JS中調用的對象方法前加上@JavascriptInterface, 在api 17 即 Android 4.2.2 之後
*/
@JavascriptInterface
public void showcontacts() {
List contactses = mContactsService.getContactsImf();
JSONArray jsonArray = new JSONArray();
try {
for (Contacts contact : contactses) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("id", contact.getId());
jsonObject.put("name", contact.getName());
jsonObject.put("phone", contact.getPhone());
jsonArray.put(jsonObject);
}
} catch (JSONException e) {
e.printStackTrace();
}
final String json = jsonArray.toString();
/**
* A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread
* 簡單來說就是html裡調用java方法和java調用js方法必須在同一線程
*/
mWebview.post(new Runnable() {
@Override
public void run() {
mWebview.loadUrl("javascript:show('" + json + "')");//通過webview調用js 方法
}
});
}
}
}
一. Mac OS X(10.11.4)編譯環境設置1.1 創建大小寫敏感的磁盤鏡像可以通過磁盤管理工具進行設置,也可以通過以下命令生成70g的鏡像文件sudo hdiu
既然本節是學習如何使用多線程下載,那我們先要明白什麼是多線程下載,在搞明白什麼是多線程下載之前,需要先知道什麼是單線程下載。上圖就是說明了單線程下載的原來,因此單線程下載
Android App框架設計之編寫基類BaseActivity編寫基類BaseActivity- OOP裡面子類裡面能夠共享父類的方法,提高代碼的可復用性- 基類的編寫
先看看效果圖:activity_main.xml <RelativeLayout xmlns:android=http://schemas.android