基本知识
2015-03-15
所有代码研究基于android4.2.2_R1
关于instance单例的一些问题
import java.util.ArrayList;
import java.util.List;
public class Hello {
public List<String> mXs = new ArrayList<String>();
public List<String> mYs = new ArrayList<String>();
public List<String> mZs = new ArrayList<String>();
static Hello sInstance = null;
public static Hello getInstance() {
sInstance = new Hello();
return sInstance;
}
public String getX(int i) {
synchronized (Hello.class) {
return mXs.get(i);
}
}
public void addX(String s) {
synchronized (Hello.class) {
mXs.add(s);
}
}
public String getY(int i) {
synchronized (Hello.class) {
return mYs.get(i);
}
}
public void addY(String s) {
synchronized (Hello.class) {
mYs.add(s);
}
}
public void addZ(String s) {
synchronized (this) {
mZs.add(s);
}
}
public String getZ(int i) {
synchronized (this) {
return mZs.get(i);
}
}
public synchronized int removeAllFromX(String x) {
int i = 0;
for(String s : mXs) {
if(s.equals(x)) {
mXs.remove(s);
++i;
}
}
return i;
}
}
这段代码存在的问题:
- 单例非线程安全,可能会出现多个实例
- mXs多线程操作会出问题(Race Condition)
- 原因: addX 使用的是受Hello类的静态锁保护的临界区 / removeAllFromX 使用的是对象实例的内置锁保护的临界区,因此多线程可以同时读写mXs,产生RaceCondition
- 解决方法:
public String getX(int i) {
synchronized (this) {
return mXs.get(i);
}
}
public void addX(String x) {
synchronized (this) {
mXs.add(x);
}
}
- 并发性能差
- 原因: mXs/mYs/mZs的读写操作存在共用同一把锁的问题, 会导致不必要的block. 比如操作mXs时,会block操作mY(取 决于怎么修改问题2)
- 解决方法, mXs/mYs/mZs 各用各的锁
比如:
Object lockX = new Object(); // -> 保护mXs
Object lockY = new Object(); // -> 保护mYs
Object lockZ = new Object(); // -> 保护mZs
- removeAllFromX遍历删除有问题:
- 解决方法: 使用Iterator或者遍历时标记, 遍历完毕后再统一删除
高效的代码样例
public class Demo {
public static void main(String[] args){
//1:考察Integer的cache,避免coding的时候产生更多的对象
//-128~127有缓存对象的
Integer i1 = Integer.valueOf(1);
Integer i2 = Integer.valueOf(1);
System.out.println(i1==i2);//true
Integer i3 = Integer.valueOf(1000);
Integer i4 = Integer.valueOf(1000);
System.out.println(i3 == i4);//false
//2:考察Java中的常量池概念,避免coding的时候产生更多的对象
String s1 = "aa";
String s2 = new String("aa");
String s3 = String.valueOf("aa");
System.out.println(s1 == s2);//false
System.out.println(s1 == s3);//true
System.out.println(s2 == s3);//false
//调用s2的什么方法,可以让s2和s1,s3相等,这个方法的作用是什么?
//intern方法,这个方法就是返回常量池中值为:"aa"的对象
//3:考察对ArrayList的源码解析程度,coding的时候提高程序的的效率,ArrayList默认的容量是10,如果超过10的话,会自动扩容。
//已知list的大小为10,list1和list2的定义哪种方式比较好:效果一样的
//已知list的大小为20,list1和list3的定义哪种方式比较好:list3方式好
ArrayList<String> list1 = new ArrayList<String>();
ArrayList<String> list2 = new ArrayList<String>(10);
ArrayList<String> list3 = new ArrayList<String>(20);
}
}
值传递与引用传递
public class Test {
public static void main(String[] args) {
String str = new String("good");
char[] ch = {'a', 'b', 'c'};
Test t = new Test();
t.change(str, ch);
System.out.print(str + " ");
System.out.print(ch);
}
public void change(String str, char[] ch) {
str = "welcome";
ch[0] = 'g';
}
}
打印结果为:good gbc
View的常见动画
实现继承View的控件,在加载到布局后,得到长宽时画一个扇形在2秒内从0度到360度匀速动画。长宽为100dp。
public class SectorView extends View{
private float mHeight = 0;
private float mWidth = 0;
private Paint mPaint;
private RectF mRectf;
private float mSweep = 0;
public SectorView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int height = getHeight();
if(height != 0){
mHeight = height;
mWidth = getWidth();
mRectf = new RectF(0, 0, mWidth, mHeight);
getViewTreeObserver().removeGlobalOnLayoutListener(this);
startAnim();
}
}
});
}
private void startAnim() {
ValueAnimator anim = ValueAnimator.ofFloat(0,360);
anim.setDuration(2000);
anim.setInterpolator(new LinearInterpolator());
anim.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float sweep = (Float)animation.getAnimatedValue();
mSweep = sweep;
invalidate();
}
});
anim.start();
}
private void init() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(0xFF0000FF);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(mHeight > 0){
canvas.save();
canvas.rotate(-90, mWidth/2, mHeight/2);
canvas.drawArc(mRectf, 0, mSweep, true, mPaint);
canvas.restore();
}
}
}
常见内存问题
- 构建Adapter适配器时 convertview不重用
- 游标 不及时关闭
- I/O流不及时关闭
- bitmap确认不在用时不及时recycle
- 大的对象比如activity不被回收
SharedPreference的问题:
Editor 的apply和commit方法异同
- apply没有返回值而commit返回boolean表明修改是否提交成功
- apply是将修改数据原子提交到内存, 而后异步真正提交到硬件磁盘, 而commit是同步的提交到硬件磁盘,因此,在多个并发的提交commit的时候,他们会等待正在处理的commit保存到磁盘后在操作,从而降低了效率。而apply只是原子的提交到内容,后面有调用apply的函数的将会直接覆盖前面的内存数据,这样从一定程度上提高了很多效率。
- apply方法不会提示任何失败的提示。 由于在一个进程中,sharedPreference是单实例,一般不会出现并发冲突,如果对提交的结果不关心的话,建议使用apply,当然需要确保提交成功且有后续操作的话,还是需要用commit的。
关于webview:
How to resize a android webview after adding data in it:
private void setupWebView() {
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
webView.loadUrl("javascript:MyApp.resize(document.body.getBoundingClientRect().height)");
super.onPageFinished(view, url);
}
});
webView.addJavascriptInterface(this, "MyApp");
}
@JavascriptInterface
public void resize(final float height) {
MyActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
webView.setLayoutParams(new LinearLayout.LayoutParams(getResources().getDisplayMetrics().widthPixels, (int) (height * getResources().getDisplayMetrics().density)));
}
});
}
参考
AndRoid-Memory-leaks-OR-Different-Ways-to-Leak
评论: