在公司多人协作写代码最怕的就是冲突。。。因此一定要协作好,必须有规范,比如引用的库v4、v7包版本都要一致等等。
对于invalidate()源码注释如下:
*Invalidate the whole view. If the view is visible,
* {@link #onDraw(android.graphics.Canvas)} will be called at some point in
* the future. This must be called from a UI thread. To call from a non-UI thread,
* call {@link #postInvalidate()}.
即该方法会导致整个View都无效,然后会调用onDraw()方法,且该方法必须在主线程中使用,如果需要在子线程中调用,我们通常的做法是使用Thread+Handler来完成invalidate()调用,或者使用postInvalidate()方法,此方法可以直接在子Thread中使用。这就是两者的区别。需要注意的是,如果是在View中调用那么会导致该View被绘制,而其它视图不会被绘制,如果是在ViewGroup中调用这两个方法那么会导致该ViewGroup下的所有子视图重绘。
此接口源码解释如下:
* Interface for classes whose instances can be written to
* and restored from a {@link Parcel}. Classes implementing the Parcelable
* interface must also have a static field called <code>CREATOR</code>, which
* is an object implementing the {@link Parcelable.Creator Parcelable.Creator}
* interface.
*
此接口用于序列化和反序列化数据,而且性能较Serializable稍微高一些,不过实现也稍微多一个步骤,注释中已有说明,且源码还有一个例子,就不贴出来了。值得思考的是Android为什么引进一个Parcelable接口呢?我猜测主要还是基于性能考虑吧,Ctrl+T发现framework中实现此接口的类有很多,我目测了下,至少有好几十个类。典型的有Bundle和ContentValues,所以在Intent传递数据的时候我们可以直接传递ContentValues,可以直接intent.putExtra(key,cv),获取时intent.getExtras().get(key)。。。etc. 跑题了!。。那么framework中有这么多类都需要序列化存储数据,为了提高性能,是很有值得引入一个接口代替Serializable了。实际上Serializable接口中没啥内容,要被序列化的类实现此接口不过是一个标识,标识该类可以被序列化。同理Parcelable接口也是一样,不过在序列化时能提高性能,具体没有研究 - -、,以后有时间了再仔细瞅瞅。
“?”引用主题属性,当使用这个标记,我们所提供的资源名必须能够在主题属性中找到,因为资源工具认为这个资源属性是被期望得到的,我们不需要明确的指出它的类型(也就是不需要写全在哪个文件中?android:attr/android:textDisabledColor)。
@表示引用资源文件中我们定义的内容drawable、string等,主题属性和样式属性只是使用范围不同而已,效果差不多,系统的主题属性有:http://android.toolib.net/reference/android/R.styleable.html#Theme
如果在xml中要引用自定义控件的属性,必须在xml命名空间引用,比如:xmlns:bar="http://schemas.android.com/apk/res/com.geo.ui",和系统的属性引用一样只不过在res目录后加上自己程序的包名,这个包名不是自定义控件所在的包名,而是在androidmanifest.xml 文件中的package属性的名字,这个包名就是应用程序的进程名字。当然了“bar”这个名字随意起。
public static HashSet<String> sDocMimeTypesSet = new HashSet<String>() { { add("text/plain"); add("text/plain"); add("application/pdf"); add("application/msword"); add("application/vnd.ms-excel"); add("application/vnd.ms-excel"); } };
ActionMode是4.0后新特性,表示长按某个视图就会出现类似菜单上下文的菜单,但不是弹窗,而是在ActionBar上面显示。要使用ActionMode需要先实现ActionMode.CallBback接口,然后在Activity中调用startActionMode(),或在Fragment中调用getActivity().startActionMode();
SQLiteOpenHelper的onCreate()方法只在数据库第一次被创建的时候调用一次,如果该数据库已经存在就不会重复调用了。因此,如果我们在一个已有的数据库中新增一个表,就需要在onUpgrade(SQLiteDatabase,int,int)中做数据库升级。当我们要对数据库升级的时候,仅仅在onCreate(SQLiteDatabase db)方法中增加一条sql语句和修改版本号是不够的,还要在onUpgrade()函数中增加要升级的sql语句,不然会导致升级失败,项目中遇到这个坑。比较详细的看此博客:http://www.cnblogs.com/liqw/p/4264925.html
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // TODO Auto-generated method stub try { db.execSQL("drop table if exists "+mTableName); } catch (SQLException e) { e.printStackTrace(); } }
ConcurrentHashMap的在并发情况下使用的HashMap。普通的HashMap在并发情况下使用put方法会容易引起死循环。关于并发如下:http://ifeve.com/concurrenthashmap/
Date的日期比较:date1.after(date2)表示的是如果date1在date2之后就返回true,比如date1=2015-01-23,date2=2014-12-25,结果返回true,此时如果是date1.before(date2)将会返回false.此外,讲一个字符串的时间转换为Date直接用new SimpleDateFormat("....").parse("...");都是些无关痛痒的小问题,不过还是习惯记录下。
/** * 重新计算ListView的高度,解决ScrollView和ListView两个View都有滚动的效果,在嵌套使用时起冲突的问题 * @param listView */ public void setListViewHeight(ListView listView) { // 获取ListView对应的Adapter ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) { return; } int totalHeight = 0; for (int i = 0, len = listAdapter.getCount(); i < len; i++) { // listAdapter.getCount()返回数据项的数目 View listItem = listAdapter.getView(i, null, listView); listItem.measure(0, 0); // 计算子项View 的宽高 totalHeight += listItem.getMeasuredHeight(); // 统计所有子项的总高度 } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); listView.setLayoutParams(params); }
ScrollView只能有一个子View。需要注意的是子ListView的每个Item必须是LinearLayout,不能是其他的,因为其他的Layout(如RelativeLayout)没有重写onMeasure(),所以会在onMeasure()时抛出异常。原文在此http://blog.csdn.net/wulianghuan/article/details/8627958。其实也可以重写一个ListView,只需要重写其onMeasure()方法。
从我电脑上拷了Android项目到公司电脑上的Eclipse的workeplace,出现overlaps the location of another project: 'XXX'错误,项目重复了。貌似是Eclipse在导入创建项目的时候会创建同名的目录,因此会报错,我把项目放在非workplace目录可以正常导入,但是我的项目引用了workplace中的其他项目!导致项目虽然能够正常导入但是不能正常使用,因此我在workplace中再建一个目录用于放我导入的项目,这一次就ok了!
使用代码将EditText设置为密码形式:inputEt.setTransformationMethod(PasswordTransformationMethod.getInstance());
public static float[] getWHofDevice(Activity ac){ float[] wh = new float[2]; //Display用于展示尺寸和密度的类 Display display = ac.getWindowManager().getDefaultDisplay(); //Point类封装了坐标系的X轴和Y轴两个坐标点 Point size = new Point(); display.getSize(size); wh[0] = size.y; wh[1] = size.x; return wh; }
当然了,也可以用一下方法:
Display diaplay = getWindowManager().getDefaultDisplay(); Point point = new Point(); diaplay.getSize(point); int x = point.x; int y = point.y;
MotionEvent的getRowX()表示获取的是滑动的相对屏幕的X轴坐标,getX()表示相对于被滑动的View的坐标,getX()的值不会超过该VIew的宽,getY()和getRowY()同理。
在ListView的Item的控件上设置Selector必须对该控件设置一个clickable属性为true才有效,否则设置会不起作用。
自定义视图中,当重写onMeasure()方法时,如果不super.onMeasure(),那么就必须设置setMeasuredDimension(width, height);的值。
关于View的post()方法和Handler的post()、sendMessage(..)的方法的比较,实际上View的post()方法都是调用了Handler的post()或postDelay()方法,而Handler的post()方法最终还是调用它自己的sendMessageAtTime()方法。
1)进入刚安装的Android Studio目录下的bin目录。找到idea.properties文件,用文本编辑器打开。
2)在idea.properties文件末尾添加一行: disable.android.first.run=true ,然后保存文件。
3)关闭Android Studio后重新启动,便可进入界面。、
在做适配的时候报错:android.content.res.Resources$NotFoundException: File res/drawable-hdpi/expanded.PNG from drawable resource ID #0x7f02007d: .xml extension required。已经解决,http://www.360doc.com/content/12/1205/14/1801810_252271083.shtml
Adapter的getView()方法的position总是返回0,明明有很多item,但是返回的总是0,原因是这些item中的高度是不同的,在变化,这导致ListView重绘了。
1创建一个基类,BaseActivity并继承Activity
方法如下:
public class BaseActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } protected <T extends View> T generateFindViewById(int id) { //return返回view时,加上泛型T return (T) findViewById(id); } }
2自己写的Activity都去继承BaseActivity
之后我们自己写的每一个Activity都去继承BaseActivity,然后在初始化控件时直接使用generateFindViewById来代替findViewById即可。
有时候我们需要在子线程中创建Handler对象,我们知道,在线程中创建Handler的时候必须保证当前线程有Looper对象,因此通常需要在run方法中调用prepare()和loop,其实有一种更方便的用法来创建Loop,那就是使用HandlerThread实现,HandlerThrtead是SDK提供的一个简单的类,用法如下:
(1)创建HandlerThread对象:HandlerThread handlerThread = new HandlerThread("my_handler");
(2)调用start方法:handlerThread.start();
(3)创建Handler:Handler handler = new Handler(handlerThread.getLooper());如此即可。
有时候我们需要监听手机上指定的目录或文件的变化,如被删除、被修改或新增了文件等,这种变化需要我们的app随时知道,应该怎么实现呢?SDK提供了一个FileObserver类给我们,可以很容易的实现:
(1)继承FileObserver类实现其抽象方法来完成自己的FileObserver。
(2)为指定目录/文件添加监听:添加监听其实就是在创建FileObserver对象的时候传递路径:
FileObserver mFrameworkInstallObserver = new AppDirObserver( mFrameworkDir.getPath(), OBSERVER_EVENTS, true);其中的mFrameworkDir.getPath()就是监听system/app目录。
(3)启动监听:mFrameworkInstallObserver.startWatching();
可以使用Android自带的LruCache或者使用轻量级的ACache(网上搜).
在布局文件的ImageView标签中加入android:adjustViewBounds="true"或者在代码中设置ImageView.setAdjustViewBounds(true)即可。
首先需要继承TextView,什么也不用干,就把isFocused()返回true即可。
(1)限制文本长度:android:maxEms="6",最长只能显示6个字符。
(2)跑马灯x效果:android:singleLine="true",android:ellipsize="marquee"
(3)当然我们也可以在代码中设置:tv.setEllipsize(TruncateAt.MARQUEE);
(1)设置多行显示,类似html的textarea:android:lines="4",显示四行,
(2)如果lines是多行,光标显示在第一行: android:lines="4",android:gravity="top",这样就行了。
“你的属性或方法是否需要在没有对象的情况下使用?如果是那么就该用static了,如果不是那么就别用static了。”。
主要是焦点问题,这里就需要用到android:descendantFocusability属性了,详见此博客http://www.cnblogs.com/eyu8874521/archive/2012/10/17/2727882.html ; 。