Android 开发技巧2(待整理)

1、UI方面:

1. 所有Activity可继承自BaseActivity,便于统一风格与处理公共事件,构建对话框统一构建器的创建,万一须要总体变更,一处修改处处有效。html

2. 若是数据没有必要加载,数据请务必延迟初始化,谨记为用户节省内存,总不会有坏处。java

3. 作以前先考虑那些能够公用,资源,layout,类,作一个结构、架构分析以加快开发,提高代码可复用度。android

4. listview在数据未满一屏时,setSelection函数不起做用;ListView批量操做时各子项和视图正确对应,可见即所选。c++

5. setSelection不起做用,尝试smoothScrollToPosition。ListView的LastVisiblePosition(最后一个可见子项)会随着getView方法执行位置不一样变更而变。git

6. 控制Activity的代码量,保持主要逻辑清晰。其余类遵照SRP(单一职能),ISP(接口隔离)原则。github

7. 与Activity通信使用Handler更方便; 若是你的框架回调链变长,考虑监听者模式简化回调。sql

8. Handler在子线程线程使用Looper.prepare,或者new的时候给构造函数传入MainLooper来确保在主线程run。数据库

9. timepicker 点击肯定后须要clearFocus才能获取手动输入的时间。api

10.ExpandableListView的子列表不能点击(禁用)要把Adapter的isChildSelectable方法返回true。数组

11.UI显示注意内容过长的情形要提早使用ScrollView不然在小手机上尴尬。

12.注意按钮的感应范围不小于9mm不然不易点击;输入框注意光标的位置更易用户输入。

13.常常须要用ListView或者其它显示大量Items的控件实时跟踪或者查看信息,而且但愿最新的条目能够自动滚动到可视范围内。经过设置的控件transcriptMode属性能够将Android平台的控件(支持ScrollBar)自动滑动到最底部。

14. EditText在setText时不要忘记是否须要setSelection。在大多数状况下是须要设置的。

15. 输入控件注意对空格、换行等符号的控制;输入框里内容注意和左右控件的空间,防止误点击。

16.XML两种状况要注意:1 属性名字时候有重复;2 注意文本是否包含非法字符,注意使用CDATA包裹。

17.当咱们的页面变得复杂,XML文件内容过多时,<include />标签能够有效地帮助咱们整理文件内容,同时提升了XML文件的可读性。同时,它的用法也与Fragment相似。

18.ViewStub是一个极佳的延迟加载视图资源的方式。只要你设计的视图是依赖于上下文来改变其可见性的,就利用ViewStub类吧。也许当你只将其应用在一个简单的页面当中时,并不会感受到在性能上有任何提高,可是在复杂页面中,它的效果是极佳的。
ViewStub是一个不可见、不占空间(zero-sized)的控件,它能够用来在运行时延迟加载视图资源。只有当咱们将ViewStub的可见性设为true,或者调用inflate()方法,它的视图资源才会被加载。

main.xml
<RelativeLayout xmlns:android = "http://schemas.android.com/apk/res/android"  
    android:layout_width= "fill_parent"  
    android:layout_height= "fill_parent" >  
  
    <Button  
        android:layout_width ="fill_parent"  
        android:layout_height ="wrap_content"  
        android:layout_gravity ="center_vertical"  
        android:onClick ="onShowMap"  
        android:text ="@string/show_map" />  
  
    <ViewStub  
        android:id ="@+id/map_stub"  
        android:layout_width ="fill_parent"  
        android:layout_height ="fill_parent"  
        android:inflatedId ="@+id/map_view"  
        android:layout ="@layout/map" />  
</RelativeLayout>  
map.xml
<com.google.android.maps.MapView xmlns:android ="http://schemas.android.com/apk/res/android"  
    android:layout_width= "fill_parent"  
    android:layout_height= "fill_parent"  
    android:apiKey= "my_api_key"  
    android:clickable= "true" />  
//MainActivity
public class MainActivity extends MapActivity {  
  
  private View mViewStub;  
  
  @Override  
  public void onCreate (Bundle savedInstanceState ) {  
    super. onCreate( savedInstanceState );  
    setContentView( R. layout. main);  
    mViewStub = findViewById( R. id. map_stub);  
  }  
  
  public void onShowMap (View v) {  
    mViewStub. setVisibility (View .VISIBLE );  
  }    
}  

19.如何将一个Button放置在布局中间并将其宽度设为其parent的50%?
在此咱们将weightSum属性与layout_weight属性一块儿利用。

<LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"  
    android:layout_width= "fill_parent"  
    android:layout_height= "fill_parent"  
    android:background= "#ffffff"  
    android:gravity= "center"  
    android:orientation= "horizontal"  
    android:weightSum= "1" ><!--1.添加android:weightSum属性-->  
  
    <Button  
        android:layout_width ="0dp"<!--2.将Button的layout_width设为0dp-->  
        android:layout_height ="wrap_content"  
        android:layout_weight ="0.5"<!--3.确保其占用了50%的可用空间-->  
        android:text ="@string/activity_main_click_me" />  
</LinearLayout>  

能够注意到,在第2步将Button的layout_width设为了0dp,会不会与layout_weight有冲突?答案是不会:
  一个控件的宽度是这样计算出来的:
  Widget's width + Widget's weight*Parent's width/Parent's weightSum

20.如何处理须要填充的数据为空的状况?
ListView及其余继承自AdapterView的类都有一个简便的处理这种状况的方法:setEmptyView(View)。
当ListView的Adapter为空或者Adapter的isEmpty()方法返回true的时候,它将会把设置的emptyview绘制出来。

<FrameLayout xmlns:android = "http://schemas.android.com/apk/res/android"  
   android:layout_width= "fill_parent"  
   android:layout_height= "fill_parent"  
   android:orientation= "vertical" >  
  
   <ListView  
       android:id ="@+id/my_list_view"  
       android:layout_width ="fill_parent"  
       android:layout_height ="fill_parent" />  
  
   <ImageView  
       android:id ="@+id/empty_view"  
       android:layout_width ="fill_parent"  
       android:layout_height ="fill_parent"  
       android:src ="@drawable/empty_view" />  
  
</FrameLayout>

再来看自定义的drawable/empty_view文件:

<shape xmlns:android = "http://schemas.android.com/apk/res/android"  
    android:shape= "rectangle" >  
    <solid android:color= "#AA00FF00" />  
</shape> 

是一个自定义的shape,当ListView没数据的时候才展示出来.

public class MainActivity extends Activity {  
  
  private ListView mListView;  
  
  @Override  
  public void onCreate (Bundle savedInstanceState ) {  
    super. onCreate( savedInstanceState );  
    setContentView (R .layout .main );  
  
    mListView = (ListView ) findViewById (R .id .my_list_view );  
    mListView. setEmptyView (findViewById (R .id .empty_view ));  
    /*String[] strs=new String[]{"1","2"}; 
    ArrayAdapter<String> adapter=new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,strs); 
    mListView.setAdapter(adapter);*/  
     
  }  
  
}  

21.咱们能够利用两个TextView来显示,第一个TextView显示LED屏上默认不发光的88:88:88,另外一个显示实时的时间并添加发光及阴影效果。可是咱们还须要解决显示的字体问题,让它看起来更像是一个真实的LED数字时钟。
解决步骤:
    (1)自定义一个LedTextView类,继承自TextView,这个类主要用来设置和显示字体;
    (2)在MainActivity中新开启一个线程用来更新LedTextView显示的时间;
    (3)为LedTextView添加阴影效果,看起来更真实。
在assets文件夹下放入一个咱们须要用到的字体文件:digital-7.ttf

public class LedTextView extends TextView {  
  
       private static final String FONTS_FOLDER = "fonts";  
       private static final String FONT_DIGITAL_7 = FONTS_FOLDER + File.separator  
                   + "digital-7.ttf";  
        private void init(Context context) {  
             AssetManager assets = context. getAssets();  
             final Typeface font = Typeface . createFromAsset( assets, FONT_DIGITAL_7);  
            setTypeface (font );// 设置字体  
       }  
       public LedTextView (Context context) {  
             super(context );  
             init( context);  
       }  
  
       public LedTextView (Context context, AttributeSet attrs) {  
             super(context , attrs );  
             init( context);  
       }  
  
       public LedTextView (Context context, AttributeSet attrs, int defStyle) {  
             super(context , attrs , defStyle );  
             init( context);  
       }  
}
<merge xmlns:android ="http://schemas.android.com/apk/res/android" >  
    <com.vectoryi.hack011.view.LedTextView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_gravity="center"  
        android:text="@string/default_time"  
        android:textColor="#3300ff00"  
        android:textSize="80sp" />  
  
    <com.vectoryi.hack011.view.LedTextView  
        android:id="@+id/main_clock_time"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_gravity="center"  
        android:textColor="#00ff00"  
        android:textSize="80sp" />  
</merge>  

22.判断EditView值为空
TextUtils.isEmpty(edit.getText()) //为空的判断  
TextUtils.isEmpty(edit.getText().toString().trim()) //去掉空格   

2、数据处理:

1. 全局变量放全局类中,模块私有放本身的管理类中,让常量清晰且集中。

2. 码块/常量/资源能够集中公用的必定共用,即便共用逻辑稍复杂一点也会值得,修改起来很轻松,修改一种,处处有效。

3. 数据库表段字段常量和SQL逻辑分离,更清晰。

4. 有序队列操做add、delete操做时注意保持排序,不然你会比较难堪喔。

5. 数据库删除数据时,要注意级联操做避免出现永远删不掉的脏数据喔。

6. 多线程操做数据库时,db关闭了会报错,也极可能出现互锁的问题,推荐使用事务。

7. 完整型数据必定要用Sqlite的Transaction,大数据必定要用。粗略测试插入100个数据有20倍的提速,插入1000个数据就有100多倍的提速。

8. 存在多个不一样的dbhelper实例状况下,sqlitedatabase对象必然存在不一样的实例,多线程同时写入数据,轮流写入数据时会不定时的报db is locked,引发崩溃,无论是操做同张表仍是异表。读和写能够同时并发,轮流无规律的交替执行。同时写入数据时解决方案是用并发的每一个线程都用事务,db则不会lock,按次总体写入。
9.建议整个应用维护一个dbhelper实例,只要db没有关闭,全局就只有一个db实例,多线程并发写入db不会lock,严格交替进行写入:123123123。。。(123表明不一样线程,轮流插入一个记录),读和写均不会锁住db,读写交替并无规律,执行次数和程度看cpu分配给哪一个线程的时间片长。
10.一个任务使用事务嵌套N个事务,N个事务中有一个失败,这个任务总体失败,所有成功后,数据才写入,具备安全性,总体性。而且事务写入大批量数据的效率经实际测试成百上千倍的高于通常的单个写入。数据库大量数据、多线程操做建议使用LiteOrm数据库框架,更稳定简单。

11.推荐使用的数据库框架:

    LiteOrm库:超级清晰且重心能够放在业务上不用关心数据库细节,自动化。使用方法:https://github.com/litesuits/android-lite-orm

    ORMLite:鸿洋推荐,使用方法:http://blog.csdn.net/lmj623565791/article/details/39121377

12. 信息同步:无论是数据库仍是网网络操做,新插入的数据注意返回ID(若是没有赋予惟一ID),不然至关于没有同步。

13. arraylist执行remove时注意移除int和Integer的区别。

14.避免String=”null”的状况出现String = null,=””均可以。避免出现title=”无主题”这样的数据提交到数据库浪费空间。

15.编码遇到读写、出入等逻辑要双向考虑,文件导入导出,字符字节相互转换都要两边转码。

16. 一个 int 值与一个 Integer 对象(能包含 int 值的最小对象)的大小比率约为 1:4(32位和64位机器有不一样)。额外的开销源于 JVM 用于描述 Java 对象的元数据也就是 Integer,(Long、Double等也是)。

17. 对象由元数据和数据组成。元数据包括类(指向类的指针,描述了类的类型),标记(描述了对象状态,如散列码、形状等),锁(对象同步信息)。数组对象还包括大小的元数据。

18. 一个在 32 位 Java 运行时中使用 1GB Java 堆的 Java 应用程序在迁移到 64 位 Java 运行时以后,一般须要使用 1.7GB 的 Java 堆。

19. Hash 集合的访问性能比任何 List 的性能都要高,但每条目的成本也要更高。因为访问性能方面的缘由,若是您正在建立大集合(例如,用于实现缓存),那么最好使用基于 Hash 的集合,而没必要考虑额外的开销。

20. 延迟分配 Hashtable:若是 Hashtable 为空是常常发生的广泛现象,那么仅在存在须要存储的数据时分配 Hashtable 应该是一种合理的作法。将 Hashtable 分配为准确的大小:虽然会有默认大小,但建议使用更为准确的初始大小。、

21. 选择正确的集合类型使你可以在集合性能与内存占用之间达到合理的平衡。除此以外,你能够经过正确调整集合大小来最大化填充率、最小化未获得利用的空间,从而最大限度地减小内存占用。

22. 对于并不那么注重访问性能的较小集合而言,List 则是合理的选择。ArrayList 和 LinkedList 集合的性能大致相同,但其内存占用彻底不一样:ArrayList 的每条目大小要比 LinkedList 小得多,但它不是准确设置大小的。List 要使用的正确实现是 ArrayList 仍是 LinkedList 取决于 List 长度的可预测性。若是长度未知,那么正确的选择多是 LinkedList,由于集合包含的空白空间更少。若是大小已知或可预知或比较小,那么 ArrayList 的内存开销会更低一些。

23. 因为String类的immutable性质,当String变量须要常常变换其值时,应该考虑使用StringBuilder提高性能,多线程使用StringBuffer操做string提升程序效率。

24. java 栈的优点是比堆速度快,可共享,主要存放临时变量、参数等,堆的优点是可动态分配内存大小。

25. 只要是用new()来新建对象的,都会在堆中建立,并且其数据是单独存值的,即便与栈中的数据(值)相同,也不会与栈中的数据共享。

26. 基本数据类型定义的变量称自动变量,存的是‘字面值’,存在于栈中,可共享(存在即不新建)。

27.多个RandomAccessFile对象指向同一个文件,可以使用多个线程一块儿写入无需再本身加锁,经试验结论:三个线程分别写入100万次数据,使用锁约12秒,不使用约8.5秒。100个线程分别写入1万次数据使用锁耗时约4.2秒,不使用锁耗时约3秒。

28.XmlPullParser解析慎用nextText()方法,xml比较复杂,含有空标签、重复名字标签时容易出现异常问题;TEXT中使用getText()方法代替START_TAG中使用nextText()方法;START_TAG,TEXT,END_TAG三个事件配合使用。注意每一个xml节点之间(无论是开始节点仍是结束节点)都会出现TEXT事件。

29. 注意函数参数里的++或者–操做。是++c 仍是 c++,区别很大。

3、总体设计

1. 不要相信庞大的管理类的东西会带来什么好处,多是一场灾难,而要时刻注意单一职责原则,一个类专心作好一件事情更为清晰。

2. 异常抛出,在合适的位置处理或者集中处理,不要搞的处处是catch,混乱且性能低,尽可能不要在循环体中捕获异常,以提高性能。

3.地址引用链长时(3个以上指向)当心内存泄漏,和警戒堆栈地址指向,典型的易发事件是:数据更新了,ListView视图却没有刷新,这时Adapter极可能指向并的并非你更新的数据容器地址(通常为List)。

4. 关于形参实参:调用函数时参数为基本类型传的是值,即传值;参数为对象传递的是引用,即传址。

5. Log请打上Tag,调试打印必定要作标记,能定位打印位置,不然尴尬是:不知道是哪里在打印。

6. Long a; 判断a有没有赋值,if(a == 0)在a没有赋值状况下会报错。应该if(a == null),Integer、Floag等也同样,缘由你懂,只是提醒你要当心喔。
7. 构造函数里面极度不推荐启动异步线程,会埋下隐患。好比:异步线程调用了本例的示例,就会悲剧等着崩溃吧。
8. 千万不要理所固然的觉得一个对象不会为空,充分的作好容错处理;另外注意null也能够插入ArrayList等容器中。

9. 服务器和客户端尽可能统一惟一标识(有多是ID),不然多少会有歧义和问题。

10. 注释,尽可能去写足够的注释,去描述一下思路,达到看了能够明白某一块代码的效果。

11.监听者模式不方便使用时,推荐EventBus框架库,使用时间总线,没接触过的同窗能够自行脑补一下哦。
12. 充分利用封装(提供接口类来控制访问数据)和委托(helper对象来实施任务)两种理念。

13.当逻辑没有明显问题时考虑对象属性、函数参数、网络传输参数是否所有了解,是否设置正确。

14. 当出现编译或者运行时错误,别人那没问题时,考虑你的编译环境和环境版本是否有问题。

15. 改变逻辑的时候考虑所有用到这项功能的地方,分散的地方多了,容易大意。

16. 当系统原生组件出现问题时,查看错误栈信息,本身写一个该组件的子类,并在合适的地方将出错方法复写一下,加上try catch保证不崩溃掉。不要扰乱了该系统控件的正常逻辑。

17. 各类地方、永远的不要小看null指针问题,甚至有些场合宁肯错杀(try catch),不可放过。

18.MVC和MVP的区别
MVP将MVC中的Controller层进行了优化而生成了Presenter。Presenter单词翻译为“提出者;任命者;主持人”,Presenter层和MVC的Controller同样,负责核心逻辑,但不同的是Presenter经过接口协议进行数据传递,并阻断了View和Model的直接联系,从而使View和Model更加专一于自身业务逻辑。
各个层之间经过接口协议进行沟通;
View和Model再也不进行直接交互;

4、功能实现

1.android中获取IP地址

public String getLocalIpAddress() {  
    try {  
        for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();   
        en.hasMoreElements();) {  
            NetworkInterface intf = en.nextElement();  
            for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses();   
        enumIpAddr.hasMoreElements();) {  
                InetAddress inetAddress = enumIpAddr.nextElement();  
                if (!inetAddress.isLoopbackAddress()) {  
                    return inetAddress.getHostAddress().toString();  
                }  
            }  
        }  
    } catch (SocketException ex) {  
        Log.e(LOG_TAG, ex.toString());  
    }  
    return null;  
}  

2.android获取存储卡路径以及使用状况

/** 获取存储卡路径 */   
File sdcardDir=Environment.getExternalStorageDirectory();   
/** StatFs 看文件系统空间使用状况 */   
StatFs statFs=new StatFs(sdcardDir.getPath());   
/** Block 的 size*/   
Long blockSize=statFs.getBlockSize();   
/** 总 Block 数量 */   
Long totalBlocks=statFs.getBlockCount();   
/** 已使用的 Block 数量 */   
Long availableBlocks=statFs.getAvailableBlocks(); 

3.查看电池使用状况:

Intent intentBatteryUsage = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);          
startActivity(intentBatteryUsage);  

4.删除APK:

Uri uri =Uri.fromParts("package", strPackageName, null);    
Intent it = newIntent(Intent.ACTION_DELETE, uri);     
startActivity(it);  

5.安装APK

Uri installUri = Uri.fromParts("package","xxx", null);     
returnIt = newIntent(Intent.ACTION_PACKAGE_ADDED, installUri);  

6.接收短信代码

public class SMSReceiver extends BroadcastReceiver  
{  
       /*当收到短信时,就会触发此方法*/  
       public void onReceive(Context context, Intent intent)  
      {  
            Bundle bundle = intent.getExtras();  
            Object messages[] = (Object[]) bundle.get( "pdus");  
            SmsMessage smsMessage[] = new SmsMessage[messages.length];  
             for (int n = 0; n < messages.length; n++)  
            {  
                  smsMessage[n] = SmsMessage.createFromPdu(( byte[]) messages[n]);  
            }  
             //产生一个Toast  
            Toast toast = Toast.makeText(context, "短信内容: " + smsMessage[0].getMessageBody(), Toast.LENGTH_LONG);  
             //设置toast显示的位置  
             //toast.setGravity(Gravity.TOP|Gravity.LEFT, 0, 200);  
             //显示该Toast  
            toast.show();  
      }  
}  

XML中须要添加:
[html] view plain copy print?
<receiver android:name=".SMSReceiver" android:enabled="true">   
      <intent-filter>   
           <action android:name="android.provider.Telephony.SMS_RECEIVED"/>   
      </intent-filter>   
 </receiver>  
相关文章
相关标签/搜索