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文档。
附上参考网站上发现的解决方法:
http://stackoverflow.com/questions/4340431/how-can-i-correctly-pass-unique-extras-to-a-pending-intent
http://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 style="@style/StyleBarTitle"
android:id="@+id/txBarTitle1"
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:id="@+id/progress1"
style="?android:attr/progressBarStyleLarge"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
长条型的style设置:
<ProgressBar
android:id="@+id/progress1"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
style还有以下几个选项:
style="?android:attr/progressBarStyleHorizontal"
style="?android:attr/progressBarStyleLarge"
style="?android:attr/progressBarStyleSmall"
style="?android:attr/progressBarStyleSmallTitle"
参考: Android预定义样式 http://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(
- "http://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="http://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"
- />
这样就可以使用了。
效果如下图所示: