MacOS下编译Android源代码

Mac OS: 10.7.5

在 MacOS 上编译 Android 源码的前提是你所使用的文件系统必须是 大小写敏感 的。下面的内容旨在说明如何在不破坏原有文件系统的基础上建立一个供编译 Android 使用的文件系统。

检查你现有的文件系统

依次打开 GO —-> Utilities —-> Disk Utility.app查看当前磁盘的格式,如下图: alt none

在左侧栏中选中你希望在上面编译android的那块磁盘,查看右侧栏中的“Format”一项,如果format格式中带有“Case-sensitive”字样,那么恭喜你,你不需要再做任何操作即可开始编译android源码了,否则,继续往下操作。

确定磁盘空间

当然最方便的方法是把整个磁盘都重新格式成大小写敏感的文件系统,然后重新安装系统。但那样做的成本比较高并且很浪费时间。这里要谈的是不破坏原有系统的前提下,创建一块只供编译android的文件系统。首先需要确保你磁盘的剩余空间在30G以上,编译整个android大概会使用掉25G空间(Google官方显示至少25G)。

创建磁盘镜像

打开一个Terminal,输入如下命令:

$ hdiutil create -type SPARSE -fs 'Case-sensitive Journaled HFS+' -size 60g   YOU_FOLDER/android.dmg

这条命令在你所指定的文件夹中(YOU_FOLDER)创建了一个大小写敏感的可以自增长的最大为60GB的镜像。查看你的文件夹出现了新文件android.img.sparseimage。接下来把这个镜像挂载到系统:

$ hdiutil  attach ./android.dmg.sparseimage  -mountpoint /Volumes/android

这条命令把上一步中创建的android.dmg挂载到了/Volumes/android下,以后这里就是我们编译android的地方。如果你希望每次开机的时候系统自动挂载这个镜像,你可以把下面的命令放到你的~/.profile中。

$ hdiutil attach YOU_FOLDER/android.dmg.sparseimage -mountpoint /Volumes/android

接下来就是把down下来的android源码拷贝到/Volumes/android目录下进行编译。

Android 使用 CountDownTimer

在onResume()方法中构造CountDownTimer的好处是,onResume()是在onRestoreInstanceState()之后执行的, 这样就可以在onRestoreInstanceState()中恢复上次倒计时后的剩余时间,这样在手机屏幕旋转后,倒计时不会重置。

MainActivity.java

package com.example.countdowntimeexample;

import android.os.Bundle;
import android.os.CountDownTimer;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends Activity {

	private TextView mTimeLabel;
	CountDownTimer myTimer;
	long myTime = 30000;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		mTimeLabel = (TextView) findViewById(R.id.text);	
	}

	@Override
	protected void onResume() {
	       
		myTimer = new CountDownTimer(myTime, 1000) {

			@Override
			public void onTick(long arg0) {
				mTimeLabel.setText("second remaining: " + arg0 / 1000);
				myTime = arg0;
			}

			@Override
			public void onFinish() {
				mTimeLabel.setText("done!");
				myTime = 0;
			}
		}.start();
		super.onResume();
	}

	@Override
	protected void onStop() {
		myTimer.cancel(); // 取消计时器 
		super.onStop();
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
   // 保存本次倒计时余下的时间,以便在acitivity再次激活的时候能从上次的断点继续倒计时 
		outState.putLong("time", myTime); 
		super.onSaveInstanceState(outState);
	}

	@Override
	protected void onRestoreInstanceState(Bundle savedInstanceState) {
    // 恢复上次倒计时断点,onResume函数将使用这个值来构造CountDownTimer
		myTime = savedInstanceState.getLong("time");
		super.onRestoreInstanceState(savedInstanceState);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
}

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

Java线程同步方法

CountDownLatch

CountDownLatch主要用来等待一系列线程都完成后,再继续下一步的执行,类似于C++中的join。

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CountDownLatchExample {

	public static void main(String[] args) {
		ExecutorService pool = Executors.newCachedThreadPool();
		final CountDownLatch doneLatch = new CountDownLatch(10);

		for(int i = 0; i < 10; i++) {
			Runnable runnable = new Runnable() {

				@Override
				public void run() {
					try {
						Thread.sleep((long)(Math.random() * 1000));
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println("Thread: " + Thread.currentThread().toString() + " done");
					doneLatch.countDown();
				}
			};
			pool.execute(runnable);
		}
		try {
			doneLatch.await();
			System.out.println("All Thread Done!");
		} catch(InterruptedException e) {
			e.printStackTrace();
		}
		pool.shutdown();
	}
}

CyclicBarrier

CyclicBarrier跟CountDownLatch很相似,它主要用来等待一系列线程都运行到某一步后,再同时继续往下运行。相当于是一个栅栏,只有当所有的线程都到达这个栅栏的时候,栅栏才会打开,各个线程继续往下执行,所以CyclicBarrier有栅栏函数的作用。 CyclicBarrier的构造函数除了指定需要等待的线程数目外,还可以指定一个Runnable对象,由最后一个到达的线程调用。

public CyclicBarrier(int parties, Runnable barrierAction)
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CyclicBarrierExample {
	
	public static void main(String[] args) {
		ExecutorService pool = Executors.newCachedThreadPool();
		final CyclicBarrier barrier = new CyclicBarrier(5);
		
		for(int i = 0; i < 5; i++) {
			Runnable runnable = new Runnable() {
				
				@Override
				public void run() {
					try {
						Thread.sleep((long)(Math.random() * 1000));
						System.out.println("Thread: " + Thread.currentThread().toString() + "step 1 done. "
								+ (barrier.getNumberWaiting() +1) + " thread finished!");
						
						barrier.await();
						System.out.println("Thread: " + Thread.currentThread().toString() + "start step 2 ...");
						
					} catch(InterruptedException e) {
						e.printStackTrace();
					} catch(BrokenBarrierException e) {
						e.printStackTrace();
					}
				}
			};
			pool.execute(runnable);
		}
		pool.shutdown();
	}
}

Semaphore

信号量,这个跟C++中的semaphore用法是一致的,在构造函数中指定资源数目,每个线程在访问临界区的时候都需要首先使用acquire()获得一个资源,完成后使用release()释放资源。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreExample {
	
	public static void main(String[] args) {
		ExecutorService pool = Executors.newCachedThreadPool();
		final Semaphore sem = new Semaphore(3);
		
		for(int i = 0; i < 10; i++) {
			Runnable runnable = new Runnable() {
				
				@Override
				public void run() {
					try {
						sem.acquire();
						System.out.println("Thread: " + Thread.currentThread().toString() + "running ...");
						Thread.sleep((long)(Math.random() * 1000));
						System.out.println("Thread: " + Thread.currentThread().toString() + "done");
						sem.release();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
			pool.execute(runnable);
		}
		pool.shutdown();
	}
}

Android Activity生命周期

Activity生命周期转换图

alt none

  • onCreate(Bundle): Activity生成时调用。如果存在使用OnSaveInstanceState方法保存的信息,将把保存的信息传递给OnCreate的Bundle参数。
  • onStart(): 在Activity即将显示的时候调用。
  • onResume(): 当Activity可以接受用户输入的时候调用。它是开始播放媒体文件的一个很好的时间点。
  • onPause(): Activity转入后台时调用。如果在调用这个方法之后,系统内存不足,这个Activity进程可能被终止掉。
  • onStop(): 暂时不使用Activity时调用这个方法(可能时因为其他Activity启动或者程序即将结束时)。如同onPause()一样:当内存不足时,系统可能会直接终止进出,而不调用这个方法。
  • onRestart(): 调用onStop后,再次显示这个Activity时调用。
  • onDestroy(): Activity即将终止时调用。如同onPause()一样:当内存不足时,系统可能会直接终止进出,而不调用这个方法。
  • onSaveInstanceState(Bundle): 保存实例的状态时调用。这里使用Bundle参数来保存值。当因为内存不足等原因而造成程序终止时,这个函数所保存的值能继续作为参数传递给onCreate()和onRestoreInstanceState(),因此,再次启动程序时就能利用这个传递给Bundle的值恢复之前的状态。
  • onRestoreInstanceState(Bundle): 在恢复实例的状态时调用。通过参数Bundle,可以获取通过onSaveInstanceState()保存的值,这个值与传递给onCreate()的内容相同。虽然采取任何一种方法进行恢复处理都没有问题,但是onRestoreInstanceState的处理方式跟自然。

Activity方法调用时序

alt none alt none

alt none alt none

alt none alt none

alt none

ref: http://developer.android.com/guide/components/activities.html ref:《Android开发秘籍》 顺便推荐一款好用的在线UML工具: http://www.websequencediagrams.com/

Java语言中的静态类

在写Android程序的时候,系统会自动生成一个R.java,这个类中使用了大量的静态类,对一个C++程序员来说,这是个新鲜事物,下面来看看这个神奇的玩意。

静态内部类的语法

public class ExternalClass {
    public static final class InnerClass {
        //...
    }
} 

静态内部类的作用

一般情况很少会用到静态类,但它也并不是一无是处,不然Java也就不会引入这个语法了。静态内部类的一个最大的用处出现在对Java类的测试中,例如:

public class Test {	
	public static void main(String[] args) {
		Other.Test.printx();
	}
}

class Other{
        static class Test {
              Other o = new Other();
              o.printx();       
        }	
	
	public void printx() {
		System.out.println("Other class");
	}
}

静态内部类与非静态内部类

  非静态内部类 静态内部类
修饰符   static
声明静态成员 不能
访问外部类成员 能访问外部类的所有成员 只能访问外部类的静态成员
跟外部类实例的关系 绑定外部类 不需要绑定外部类

Android的R类正是使用了“静态内部类不需要绑定到外部类”这条属性,使得我们可以方便的直接引用R类中常量。