Android Tricks
Android Trick 1: 使用View來製作專業的分隔線
如果更高效簡單的實現界麵中的分隔線呢?
- <View
- android:layout_width="fill_parent"
- android:layout_height="1px"
- android:background="?android:attr/listDivider"
- />
這是從Google的某些應用的源代碼中發現的。
Android Trick 2: Android中的透明屬性的設置
ui設計時,需要指定某個元素的drawable時,有時候需要告訴Android我希望設置它為透明,偶然在源碼中發現,就是以下這段代碼:
- android:background="@android:color/transparent"
Android Trick 3: GridView動態加載數據情況下,選中狀態的實現
GridView使用AdapterView動態加載數據情況下,無論是在onCreate、Onstart、OnResume方法中調用getChildCount()均為0,這說明數據並沒有在Activity最初啟動後立即加載為GridView的子View,那如果要把GridView實現為Tab風格的菜單,是必須要調用它的狀態選中的,如果在Activity中調用的話就會拋nullpointerexception了,那要怎麼操作呢?
- /**
- * 構造菜單Adapter
- * @param menuNameArray 名稱
- * @param imageResourceArray 圖片
- * @return FootBarAdapter
- */
- private FootBarAdapter getMenuAdapter(String[] menuNameArray,
- int[] imageResourceArray) {
- ArrayList<HashMap<String, Object>> data = new ArrayList<HashMap<String, Object>>();
- for (int i = 0; i < menuNameArray.length; i++) {
- HashMap<String, Object> map = new HashMap<String, Object>();
- map.put("itemImage", imageResourceArray[i]);
- map.put("itemText", menuNameArray[i]);
- data.add(map);
- }
- FootBarAdapter footbarAdapter = new FootBarAdapter(this, data,
- R.layout.item_menu, new String[] { "itemImage", "itemText" },
- new int[] { R.id.item_image, R.id.item_text });
- return footbarAdapter;
- }
- public class FootBarAdapter extends SimpleAdapter {
- public FootBarAdapter(Context context,
- List<? extends Map<String, ?>> data, int resource,
- String[] from, int[] to) {
- super(context, data, resource, from, to);
- }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = super.getView(position, convertView, parent);
- if (position == TOOLBAR_ITEM_PAGEHOME) {
- v.setBackgroundResource(R.drawable.bg_toolbar_item_pressed);
- }
- return v;
- }
- }
我們繼承了SimplerAdapter,然後Override getView方法,在裏邊進行選中狀態的判斷和置背景色為選中色。
Android Trick 5: 正則匹配任意字符,包括換行符的字符串
這是java正則的知識,最近開發android上也碰到了,
匹配任意字符,包括換行符的字符串,發現使用 [.//n]* 就是不行,查了相關資料,以下可以:
[//s//S]*
[//w//W]*
[//d//D]*
Android Trick 6: PendingIntent的重複問題,當新建的PendingIntent匹配上一個已經存在的PendingIntent時可能不會創建新的。
Android中默認對PendingIntent的創建(如通過PendingIntent.getActivity方式)會進行優化檢測,默認的情況下,新創建的PendingIntent如果和原先的基本一樣,那麼就會使用原先的PendingIntent。
這就導致在目前的項目中,一定間隔的重複給用戶發送某類通知,其中帶的Intent裏的Extra內容不同,但是通知點擊後傳到一個Activity裏的extra消息還是原來的。那麼出現做這種問題可以這樣解決,在創建PendingIntent時,語句改成如下:
- PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
- notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
注意PendingIntent.FLAG_UPDATE_CURRENT這個參數,關鍵就是設置了這個參數,在extra發送變化時確定為新的PendingIntent。其他同類參數的用法可進一步參考API文檔。
附上參考網站上發現的解決方法:
https://stackoverflow.com/questions/4340431/how-can-i-correctly-pass-unique-extras-to-a-pending-intent
https://stackoverflow.com/questions/4472447/confusing-behavior-when-starting-new-activity-with-pendingintent
Android Trick 7: 把TextView中的文字添加陰影效果及Style的使用
- <TextView android:id="@+id/tvText1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="text1"
- android:textSize="28sp"
- android:textStyle="bold"
- android:textColor="#FFFFFF"
- android:shadowColor="#ff000000"
- android:shadowDx="2"
- android:shadowDy="2"
- android:shadowRadius="1"/>
android:shadowColor 陰影顏色
android:shadowDx 陰影的水平偏移量
android:shadowDy 陰影的垂直偏移量
android:shadowRadius 陰影的範圍
大多數情況下,某一類的TextView控件需要統一的風格,如加陰影等,那麼可以使用style。
<TextView
android:
android:text="資訊行情" />
然後在values文件夾下創建styles.xml文件,內容為:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="StyleBarTitle">
<item name="android:layout_gravity">center_vertical</item>
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">1</item>
<item name="android:gravity">center_horizontal</item>
<item name="android:textSize">@dimen/text_size_vlarge</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">#FFFFFF</item>
<item name="android:shadowColor">#ff000000</item>
<item name="android:shadowDx">2</item>
<item name="android:shadowDy">2</item>
<item name="android:shadowRadius">1</item>
<item name="android:background">@null</item>
</style>
</resources>
這樣的最大優點是減低代碼冗餘度,在需要更改某一類控件的樣式時,不用一個一個的改過來,隻需要更改styles文件中即可。
Android Trick 8: ProgressBar的圓形和長條形設置
默認的progresbar是圓形的旋轉動畫:
<ProgressBar
android:
font-size:12px;">progressBarStyleLarge"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
長條型的style設置:
<ProgressBar
android:
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
style還有以下幾個選項:
參考: Android預定義樣式 https://apps.hi.baidu.com/share/detail/31068312
Android Trick 10: 一個Android應用的全局數據變量的訪問..
在一個Android應用中,我們可以定義一個類,然後使用在類中定義靜態成員的方式去創造全局能夠訪問的數據。如下代碼所示:
- public class AERunTime {
- public static String text1 = "example";
- }
在Activity中就可以使用 AERuntime.text1 訪問。這是Java的通用方式,也可以稍微改變一下,使用單例模式getInstance實現。
在Android中,也提供了一種全局數據的訪問方式,可以這樣實現:
- public class AERunTime extends Application {
- public String text1 = "none";
- }
然後在AndroidManifest.xml中的<application>標簽中填入創建的AERunTime:
- <application
- android:name=".buzi.AERunTime">
那麼,在程序的Activity中就可以如下方法調用:
- ((AERunTime)getApplication()).text1
如果在通用的Activity中加入以下方法:
- protected AERunTime getRT() {
- return (AERunTime)getApplication();
- }
那麼就可以使用getRT().text1得到。
Application在每次進程啟動該應用時被創建。這樣,就相當於Android係統中給出的單例模式的封裝。
Android Trick 11: 對Android中的AsyncTask進行函數化的封裝,簡潔調用
為了使UI在數據獲取時不僵死,數據獲取需要在新開Worker線程中進行,然後將返回結果在UI線程中進行讀取並渲染頁麵。麵對這種異步處理,到底如何寫才簡潔,先後麵臨過三種實現方式。
首先是最原始的Java方式,new 一個Thread出來,將處理Runnable進去執行,執行完之後通過handler post到ui線程去更新界麵。然後發現1.5後有了AsyncTask,非常好用,以後的項目中全部改成衍生出一個AsyncTask的子類,類中自然定義了運行前方法、運行中方法和運行後在ui中運行的方法。目前我做的項目中對AsyncTask做了封裝,把它從原本的子類編寫的過程,改成了函數調用方式,這就是目前正使用的第三種方法。
一個Android應用中,Activity通常可以建立以上層次關係。然後,在BaseActivity中對AsyncTask進行了封裝,形成doAsync方法。方法體內創建一個新的AsyncTask並執行,由於AsyncTask是泛型參數,doAsync方法中傳入的接口的參數也對應使用了泛型。至此,一個典型的異步調用的案例如下:
- this.doAsync(new Callable<String>() {
- // 希望異步加載的數據
- public String call() throws Exception {
- String resu = NetworkTool.httpGetURL(
- "https://www.baidu.com", "GBK");
- return resu;
- }
- }, new Callback<String>() {
- // 當加載完成後回調,在UI線程中的操作
- public void onCallback(final String resu) {
- if (null != resu) {
- tv_text1.setText(getRT().text1 + resu);
- } else {
- Tools.ShowNetErr(HomeActivity.this);
- }
- }
- });
這樣,就從本來繼承AsyncTask創建一個子類,然後初始化,然後運行的開發過程轉變為了函數調用的過程。可以看到,調用可是簡潔了很多!
為了實現它,我們附上BaseActivity中如下封裝代碼,需要說明的是這不是我的原創,我借鑒於Andengine引擎的實現代碼進行的修改。
附源碼:
- public class ActivityUtils {
- public static <T> void doAsync(final Context pContext, final int pTitleResID, final int pMessageResID, final Callable<T> pCallable, final Callback<T> pCallback) {
- ActivityUtils.doAsync(pContext, pTitleResID, pMessageResID, pCallable, pCallback, null, false);
- }
- public static <T> void doAsync(final Context pContext, final CharSequence pTitle, final CharSequence pMessage, final Callable<T> pCallable, final Callback<T> pCallback) {
- ActivityUtils.doAsync(pContext, pTitle, pMessage, pCallable, pCallback, null, false);
- }
- public static <T> void doAsync(final Context pContext, final int pTitleResID, final int pMessageResID, final Callable<T> pCallable, final Callback<T> pCallback, final boolean pCancelable) {
- ActivityUtils.doAsync(pContext, pTitleResID, pMessageResID, pCallable, pCallback, null, pCancelable);
- }
- public static <T> void doAsync(final Context pContext, final CharSequence pTitle, final CharSequence pMessage, final Callable<T> pCallable, final Callback<T> pCallback, final boolean pCancelable) {
- ActivityUtils.doAsync(pContext, pTitle, pMessage, pCallable, pCallback, null, pCancelable);
- }
- public static <T> void doAsync(final Context pContext, final int pTitleResID, final int pMessageResID, final Callable<T> pCallable, final Callback<T> pCallback, final Callback<Exception> pExceptionCallback) {
- ActivityUtils.doAsync(pContext, pTitleResID, pMessageResID, pCallable, pCallback, pExceptionCallback, false);
- }
- public static <T> void doAsync(final Context pContext, final CharSequence pTitle, final CharSequence pMessage, final Callable<T> pCallable, final Callback<T> pCallback, final Callback<Exception> pExceptionCallback) {
- ActivityUtils.doAsync(pContext, pTitle, pMessage, pCallable, pCallback, pExceptionCallback, false);
- }
- public static <T> void doAsync(final Context pContext, final int pTitleResID, final int pMessageResID, final Callable<T> pCallable, final Callback<T> pCallback, final Callback<Exception> pExceptionCallback, final boolean pCancelable) {
- ActivityUtils.doAsync(pContext, pContext.getString(pTitleResID), pContext.getString(pMessageResID), pCallable, pCallback, pExceptionCallback, pCancelable);
- }
- public static <T> void doAsync(final Context pContext, final CharSequence pTitle, final CharSequence pMessage, final Callable<T> pCallable, final Callback<T> pCallback, final Callback<Exception> pExceptionCallback, final boolean pCancelable) {
- new AsyncTask<Void, Void, T>() {
- private ProgressDialog mPD;
- private Exception mException = null;
- @Override
- public void onPreExecute() {
- this.mPD = ProgressDialog.show(pContext, pTitle, pMessage, true, pCancelable);
- if(pCancelable) {
- this.mPD.setOnCancelListener(new OnCancelListener() {
- @Override
- public void onCancel(final DialogInterface pDialogInterface) {
- pExceptionCallback.onCallback(new CancelledException());
- pDialogInterface.dismiss();
- }
- });
- }
- super.onPreExecute();
- }
- @Override
- public T doInBackground(final Void... params) {
- try {
- return pCallable.call();
- } catch (final Exception e) {
- this.mException = e;
- }
- return null;
- }
- @Override
- public void onPostExecute(final T result) {
- try {
- this.mPD.dismiss();
- } catch (final Exception e) {
- Log.e("Error", e.toString());
- }
- if(this.isCancelled()) {
- this.mException = new CancelledException();
- }
- if(this.mException == null) {
- pCallback.onCallback(result);
- } else {
- if(pExceptionCallback == null) {
- if (this.mException != null)
- Log.e("Error", this.mException.toString());
- } else {
- pExceptionCallback.onCallback(this.mException);
- }
- }
- super.onPostExecute(result);
- }
- }.execute((Void[]) null);
- }
- public static <T> void doProgressAsync(final Context pContext, final int pTitleResID, final ProgressCallable<T> pCallable, final Callback<T> pCallback) {
- ActivityUtils.doProgressAsync(pContext, pTitleResID, pCallable, pCallback, null);
- }
- public static <T> void doProgressAsync(final Context pContext, final int pTitleResID, final ProgressCallable<T> pCallable, final Callback<T> pCallback, final Callback<Exception> pExceptionCallback) {
- new AsyncTask<Void, Integer, T>() {
- private ProgressDialog mPD;
- private Exception mException = null;
- @Override
- public void onPreExecute() {
- this.mPD = new ProgressDialog(pContext);
- this.mPD.setTitle(pTitleResID);
- this.mPD.setIcon(android.R.drawable.ic_menu_save);
- this.mPD.setIndeterminate(false);
- this.mPD.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
- this.mPD.show();
- super.onPreExecute();
- }
- @Override
- public T doInBackground(final Void... params) {
- try {
- return pCallable.call(new IProgressListener() {
- @Override
- public void onProgressChanged(final int pProgress) {
- onProgressUpdate(pProgress);
- }
- });
- } catch (final Exception e) {
- this.mException = e;
- }
- return null;
- }
- @Override
- public void onProgressUpdate(final Integer... values) {
- this.mPD.setProgress(values[0]);
- }
- @Override
- public void onPostExecute(final T result) {
- try {
- this.mPD.dismiss();
- } catch (final Exception e) {
- Log.e("Error", e.getLocalizedMessage());
- /* Nothing. */
- }
- if(this.isCancelled()) {
- this.mException = new CancelledException();
- }
- if(this.mException == null) {
- pCallback.onCallback(result);
- } else {
- if(pExceptionCallback == null) {
- Log.e("Error", this.mException.getLocalizedMessage());
- } else {
- pExceptionCallback.onCallback(this.mException);
- }
- }
- super.onPostExecute(result);
- }
- }.execute((Void[]) null);
- }
- public static <T> void doAsync(final Context pContext, final int pTitleResID, final int pMessageResID, final AsyncCallable<T> pAsyncCallable, final Callback<T> pCallback, final Callback<Exception> pExceptionCallback) {
- final ProgressDialog pd = ProgressDialog.show(pContext, pContext.getString(pTitleResID), pContext.getString(pMessageResID));
- pAsyncCallable.call(new Callback<T>() {
- @Override
- public void onCallback(final T result) {
- try {
- pd.dismiss();
- } catch (final Exception e) {
- Log.e("Error", e.getLocalizedMessage());
- /* Nothing. */
- }
- pCallback.onCallback(result);
- }
- }, pExceptionCallback);
- }
- public static class CancelledException extends Exception {
- private static final long serialVersionUID = -78123211381435595L;
- }
- }
- public interface AsyncCallable<T> {
- // ===========================================================
- // Final Fields
- // ===========================================================
- // ===========================================================
- // Methods
- // ===========================================================
- /**
- * Computes a result asynchronously, return values and exceptions are to be handled through the callbacks.
- * This method is expected to return almost immediately, after starting a {@link Thread} or similar.
- *
- * @return computed result
- * @throws Exception if unable to compute a result
- */
- public void call(final Callback<T> pCallback, final Callback<Exception> pExceptionCallback);
- }
- public interface Callback<T> {
- // ===========================================================
- // Final Fields
- // ===========================================================
- // ===========================================================
- // Methods
- // ===========================================================
- /**
- * 當加載完成後回調,加載完畢的事後處理
- */
- public void onCallback(final T pCallbackValue);
- }
- public interface IProgressListener {
- // ===========================================================
- // Constants
- // ===========================================================
- // ===========================================================
- // Methods
- // ===========================================================
- /**
- * @param pProgress between 0 and 100.
- */
- public void onProgressChanged(final int pProgress);
- }
- public interface IProgressListener {
- // ===========================================================
- // Constants
- // ===========================================================
- // ===========================================================
- // Methods
- // ===========================================================
- /**
- * @param pProgress between 0 and 100.
- */
- public void onProgressChanged(final int pProgress);
- }
- public class BaseActivity extends Activity {
- /**
- *
- * @param <T> 模板參數,操作時要返回的內容
- * @param pCallable 需要異步調用的操作
- * @param pCallback 回調
- */
- protected <T> void doAsync(final Callable<T> pCallable, final Callback<T> pCallback) {
- ActivityUtils.doAsync(this, null, "內容讀取中,請稍等...", pCallable, pCallback, null, false);
- }
- protected <T> void doAsync(final CharSequence pTitle, final CharSequence pMessage, final Callable<T> pCallable, final Callback<T> pCallback) {
- ActivityUtils.doAsync(this, pTitle, pMessage, pCallable, pCallback, null, false);
- }
- /**
- * Performs a task in the background, showing a {@link ProgressDialog},
- * while the {@link Callable} is being processed.
- *
- * @param <T>
- * @param pTitleResID
- * @param pMessageResID
- * @param pErrorMessageResID
- * @param pCallable
- * @param pCallback
- */
- protected <T> void doAsync(final int pTitleResID, final int pMessageResID, final Callable<T> pCallable, final Callback<T> pCallback) {
- this.doAsync(pTitleResID, pMessageResID, pCallable, pCallback, null);
- }
- /**
- * Performs a task in the background, showing a indeterminate {@link ProgressDialog},
- * while the {@link Callable} is being processed.
- *
- * @param <T>
- * @param pTitleResID
- * @param pMessageResID
- * @param pErrorMessageResID
- * @param pCallable
- * @param pCallback
- * @param pExceptionCallback
- */
- protected <T> void doAsync(final int pTitleResID, final int pMessageResID, final Callable<T> pCallable, final Callback<T> pCallback, final Callback<Exception> pExceptionCallback) {
- ActivityUtils.doAsync(this, pTitleResID, pMessageResID, pCallable, pCallback, pExceptionCallback);
- }
- /**
- * Performs a task in the background, showing a {@link ProgressDialog} with an ProgressBar,
- * while the {@link AsyncCallable} is being processed.
- *
- * @param <T>
- * @param pTitleResID
- * @param pMessageResID
- * @param pErrorMessageResID
- * @param pAsyncCallable
- * @param pCallback
- */
- protected <T> void doProgressAsync(final int pTitleResID, final ProgressCallable<T> pCallable, final Callback<T> pCallback) {
- this.doProgressAsync(pTitleResID, pCallable, pCallback, null);
- }
- /**
- * Performs a task in the background, showing a {@link ProgressDialog} with a ProgressBar,
- * while the {@link AsyncCallable} is being processed.
- *
- * @param <T>
- * @param pTitleResID
- * @param pMessageResID
- * @param pErrorMessageResID
- * @param pAsyncCallable
- * @param pCallback
- * @param pExceptionCallback
- */
- protected <T> void doProgressAsync(final int pTitleResID, final ProgressCallable<T> pCallable, final Callback<T> pCallback, final Callback<Exception> pExceptionCallback) {
- ActivityUtils.doProgressAsync(this, pTitleResID, pCallable, pCallback, pExceptionCallback);
- }
- /**
- * Performs a task in the background, showing an indeterminate {@link ProgressDialog},
- * while the {@link AsyncCallable} is being processed.
- *
- * @param <T>
- * @param pTitleResID
- * @param pMessageResID
- * @param pErrorMessageResID
- * @param pAsyncCallable
- * @param pCallback
- * @param pExceptionCallback
- */
- protected <T> void doAsync(final int pTitleResID, final int pMessageResID, final AsyncCallable<T> pAsyncCallable, final Callback<T> pCallback, final Callback<Exception> pExceptionCallback) {
- ActivityUtils.doAsync(this, pTitleResID, pMessageResID, pAsyncCallable, pCallback, pExceptionCallback);
- }
- }
Android Trick 12: 簡單實現ImageView的加邊框顏色的方法
對於一個ImageView,如果我們要加上邊框,比如寬為3dp的灰色框,我們怎麼做呢?
有種方法,是自己定義一個MyImageView類,繼承自ImageView,在其onDraw方法中畫canvas。
還有設置一個帶有邊框的背景圖片的方法。
這裏給出一種簡單方法,既不需要創建衍生的類,也不需要準備圖片。采用xml定義的方式實現。
背景定義xml: bg_border1.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <shape xmlns:android="https://schemas.android.com/apk/res/android">
- <solid android:color="#EEEEEE" />
- <stroke android:width="3dp" android:color="#EEEEEE" />
- <corners android:radius="0dp" />
- <padding android:left="0dp" android:top="0dp"
- android:right="0dp" android:bottom="0dp" />
- </shape>
在Imageview定義頁麵上使用代碼:
- <ImageView android:id="@+id/iv_thumbnail"
- android:layout_height="63dp"
- android:layout_width="63dp"
- android:background="@drawable/bg_border1"
- android:padding="3dp"
- />
這樣就可以使用了。
效果如下圖所示:
最後更新:2017-04-03 12:55:19