单例设计模式
概念
单例模式(Singleton)主要作用是保证在Java应用程序中,一个类只有一个实例存在。
如何实现
- 私有的构造方法,可以防止多个实例产生,英文私有,其他类无法new该类。
- 私有静态实例变量,私有是防止外部滞空,下面要说到的静态的方法不能访问非静态变量。
- 公有的静态访问方法,公有是因为要提供对外访问,静态是因为该类不能在外部实例化。
public class MySingleTon {
// 单例(singleton)=1.私有的构造方法+2.私有静态实例变量+3.公有的静态访问方法
private MySingleTon() {
}
private static MySingleTon mySingleTon = new MySingleTon();
public static MySingleTon getInstance() {
return mySingleTon;
}
}
懒汉和饿汉模式
说到单例模式就得提到懒汉和饿汉模式,饿汉模式是上来就搞对象,不考虑是否使用就直接分配内存,上面的代码就是饿汉模式。而懒汉模式则是需要时才搞对象,这可以避免内存浪费。
public class MySingleTon {
// 单例(singleton)=1.私有的构造方法+2.私有静态实例变量+3.公有的静态访问方法
private MySingleTon() {
}
private static MySingleTon mySingleTon = null;
public static MySingleTon getInstance() {
if(mySingleTon==null){
mySingleTon=new MySingleTon();
}
return mySingleTon;
}
}
不过懒汉模式是线程不安全的。假如现在有两个线程,线程中都有这句代码
MySingleTon mySingleTon=MySingleTon.getInstance();
线程1运行到了if(mySingleTon==null)时被线程2抢去了,线程2同样运行到了if(mySingleTon==null)时被线程1抢去了,这时问题就发生了,由于线程1在被抢之前就已经判断了mySingTon不为空,这时就会实例mySingleTom,而但线程2重新抢到执行权时,它也已经完成非空的判断,并会往下,又实例了一遍mySingleTom,此时程序中就产生了两个实例,这与我们所期望的不同。对此,正确的做法是采用双重锁来处理
public static LazySingleTon2 getInstance() {
if (sSingleTon == null) {//提交效率,如果不为空,直接return
synchronized (LazySingleTon2.class) {//代码线程安全
if (sSingleTon == null) {
sSingleTon = new LazySingleTon2();
}
}
}
return sSingleTon;
}
Android 系统里在服务方面大量使用单例
TelephonyManager里的代码:
/** @hide */
private TelephonyManager() {
}
private static TelephonyManager sInstance = new TelephonyManager();
/** @hide
/* @deprecated - use getSystemService as described above */
public static TelephonyManager getDefault() {
return sInstance;
}
适配器模式
概念
将控件(Adaptee(被适配者))与内容(Adaptor(适配器))相分离的一种设计
Adaptee(被适配者):ListView ,GridView,Gallery,ViewPager,….
Adaptor(适配器):SimpleAdapter ,CursorAdapter,ArrayAdapter BaseAdapter
一般通过Adaptee.setadapter(Adaptor)来绑定。
观察者模式
概念
一个目标对象(Observable)会发生敏感数据的变化,通常我们需要获取该数据,创建一个观察者对象(Observer)放置到目标内部,一旦有数据变化,就及时获取,很多地方都用到了观察者模式,比如当我们取钱时,会受到到银行的短信通知,我们追的剧更新了,收到系统的通知
如何实现
- 确定目标对象(Observable),发生敏感数据变化
- 目标对象得继承Observable,extends Observable,但目标发生变化是,要setChanged,要通知观察者notifyObservers(Object Data);
public class TemperatureObservable extends Observable {
private int temperature = 0;
public void start() {
//模拟温度每秒提升1度
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
temperature++;//数据变化
setChanged();//标记
notifyObservers(temperature);//通知观察者
}
}
}
3.写观察者,implements Observer,重写public void update(Observable observable, Object data)方法,其中observable为目标对象,data为目标对象中notifyObservers传进的obj。
public class DisPlayer implements Observer{
//接收数据变化 的方法
@Override
public void update(Observable observable, Object data) {
int temperature=(Integer) data;
System.out.println("显示屏幕:"+temperature+"度");
}
}
4.为目标对象设置观察者
//温度实例
TemperatureObservable temperatureObservable =new TemperatureObservable();
//显示屏幕
DisPlayer displayer=new DisPlayer();
//添加
temperatureObservable.addObserver(displayer);
temperatureObservable.start();
我们常见的ListView里就用了观察者模式,当数据发生变化时,通过adapter.notifyDataSetChanged()通知listview刷新。
public class MainActivity extends Activity implements View.OnClickListener {
private ListView lv;
private Button bt;
private List<String> list;
ArrayAdapter<String> adapter;
View footview;
int i=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list=new ArrayList<String>();
for(;i<20;i++){
//初始数据为0-19
list.add(i+"");
}
lv=(ListView) findViewById(R.id.lv);
footview=View.inflate(MainActivity.this, R.layout.listviewfoot, null);
//添加listview的地步视图,加载更多按钮,当滚到listview最底边的时候会看到
lv.addFooterView(footview);
bt=(Button) findViewById(R.id.bt);
bt.setOnClickListener(this);
adapter=new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, list);
lv.setAdapter(adapter);
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.bt:
//假数据,一次加载20条数据
int j=i;
for(;i<j+20;i++){
list.add(i+"");
}
//通知更新
adapter.notifyDataSetChanged();
break;
default:
break;
}
}
}
现在的加载更多更多的是采用手势的方式,往上拉实现加载更多。
android还有四大组件之一的内容提供者ContentProvider也使用了观察者模式
public class MainActivity extends Activity {
private TextView sms_tv;
ContentResolver resolver;
MyObserver observer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sms_tv=(TextView) findViewById(R.id.sms_tv);
resolver=getContentResolver();
Uri uri=Uri.parse("Content://sms/");
observer=new MyObserver(new Handler());
//注册内容观察者
//resolver.registerContentObserver(观察的uri, 为ture表示uri子路径也属于观察范围,false则不属于, observer)
resolver.registerContentObserver(uri, true, observer);
}
//内容观察者
class MyObserver extends ContentObserver{
public MyObserver(Handler handler) {
super(handler);
// TODO Auto-generated constructor stub
}
//当内容观察者观察到数据库的内容变化了,调用这个方法
@Override
public void onChange(boolean selfChange) {
// TODO Auto-generated method stub
super.onChange(selfChange);
Toast.makeText(MainActivity.this, "数据库内容发生变化了", 1).show();
Uri uri=Uri.parse("content://sms/");
ContentResolver resolver=getContentResolver();
Cursor cursor=resolver.query(uri, new String[]{"address","date","type","body"}, null, null, null);
//因为短信是倒序排列,因此获取最新一个就是第一个
cursor.moveToFirst();
String address=cursor.getString(cursor.getColumnIndex("address"));
String body=cursor.getString(cursor.getColumnIndex("body"));
sms_tv.setText("短信内容:"+body+"\n短信地址:"+address);
cursor.close();
}
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if(resolver!=null){
resolver.unregisterContentObserver(observer);
}
observer=null;
resolver=null;
}
}
事件驱动模型
两大机制
- 事件驱动/监听器,如点击事件 setOnclick(Listener)
- 回调机制 , 点击事件传进的接口实例会回调onClick(View v)
概念
事件驱动模型=事件源+监听器+事件处理
1. 事件源:接收事件的对象,如控件
2. 监听器:设置在事件源内部,捕获事件转换成参数,如点击事件的监听器为onClickListener
3. 事件处理,监听器回调函数
bt=(Button) findViewById(R.id.bt);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
监听器一般有四种写法,可以看这里
监听器四种写法
Command 模式
概念
Command命令模式,主要是降低控件与事件处理程序之间的耦合性,我们平常常见的按钮Button,就用了Command命令模式,让控件与事件相分离,所以Button什么场合都能用
实现步骤
public class MyButton {
// 1.申明一个接口interface
interface MyOnClickListener{
// 2.定义接口方法参数
public void MyOnClick(View view);
}
// 3.控件内部声明成员变量(监听器)
private MyOnClickListener listener=null;
// 4.通过set方法设置监听器对象
public void setMyOnClickListener(MyOnClickListener l){
this.listener=l;
}
}
//在系统调用的地方调用方法,是不是跟平常点击事件写法一样
MyButton button=new MyButton();
button.setMyOnClickListener(new MyOnClickListener() {
@Override
public void MyOnClick(View view) {
// TODO Auto-generated method stub
}
});