面向对象的特征
讲到面向对象,就不得不提起它的三大特性:封装、继承、多态。
封装
封装是面向对象编程的核心思想,将对象的属性和行为封装起来,用“类”作为载体。类通常对客户隐藏其实现细节,这就是封装的思想。
Android针对封装的使用场景:
1.封装第三方开源框架,封装变化。
比如说,项目中要用到图片加载框架UniversalImageLoader。如果不针对图片加载框架进行封装,那么每个图片加载的地方,都会是这样的:
ImageLoader.getInstance().loadImage(imageUrl, new ImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
}
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
}
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
mImageView.setImageBitmap(loadedImage);
}
@Override
public void onLoadingCancelled(String imageUri, View view) {
}
});
过段时间,老板说:Picasso好像很不错,下个版本咱们换这个框架,给你一天时间能搞定吗?囧…
然后开始疯狂Ctrl^C、Ctrl^V,把每一个地方换成这样:
Picasso.with(this).load("url").placeholder(R.mipmap.ic_default).into(imageView);
然后,由于Picasso不支持缓存,还要解决各种问题。
可是,如果老板下次又要换Glide、Fresco等其他框架呢?怎么办?
很多人觉得,封装只是为了隐藏细节,有点像保护隐私的感觉。但很多时候,封装其实是为了实现下层对上层的透明。
2.封装工具类,减少重复。
封装工具类,关键在于减少重复的工作。举个例子:
SharedPreferences大家应该都用过,每次使用的时候,都要写这样的模(chong)板(fu)代码。
//指定操作的文件名称
SharedPreferences share = getSharedPreferences(SILENAME, MODE_PRIVATE);
SharedPreferences.Editor edit = share.edit(); //编辑文件
edit.putInt("age", 22); //根据键值对添加数据
edit.putString("name", "LJie");
edit.commit(); //保存数据信息
如果简单封装一下呢?
public class SPUtils
{
/**
* 保存在手机里面的文件名
*/
public static final String FILE_NAME = "share_data";
/**
* 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法
*
* @param context
* @param key
* @param object
*/
public static void put(Context context, String key, Object object)
{
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
if (object instanceof String)
{
editor.putString(key, (String) object);
} else if (object instanceof Integer)
{
editor.putInt(key, (Integer) object);
} else if (object instanceof Boolean)
{
editor.putBoolean(key, (Boolean) object);
} else if (object instanceof Float)
{
editor.putFloat(key, (Float) object);
} else if (object instanceof Long)
{
editor.putLong(key, (Long) object);
} else
{
editor.putString(key, object.toString());
}
SharedPreferencesCompat.apply(editor);
}
/**
* 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值
*
* @param context
* @param key
* @param defaultObject
* @return
*/
public static Object get(Context context, String key, Object defaultObject)
{
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
if (defaultObject instanceof String)
{
return sp.getString(key, (String) defaultObject);
} else if (defaultObject instanceof Integer)
{
return sp.getInt(key, (Integer) defaultObject);
} else if (defaultObject instanceof Boolean)
{
return sp.getBoolean(key, (Boolean) defaultObject);
} else if (defaultObject instanceof Float)
{
return sp.getFloat(key, (Float) defaultObject);
} else if (defaultObject instanceof Long)
{
return sp.getLong(key, (Long) defaultObject);
}
return null;
}
/**
* 移除某个key值已经对应的值
* @param context
* @param key
*/
public static void remove(Context context, String key)
{
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.remove(key);
SharedPreferencesCompat.apply(editor);
}
/**
* 清除所有数据
* @param context
*/
public static void clear(Context context)
{
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.clear();
SharedPreferencesCompat.apply(editor);
}
/**
* 查询某个key是否已经存在
* @param context
* @param key
* @return
*/
public static boolean contains(Context context, String key)
{
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
return sp.contains(key);
}
/**
* 返回所有的键值对
*
* @param context
* @return
*/
public static Map<String, ?> getAll(Context context)
{
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
return sp.getAll();
}
/**
* 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类
*
*
*
*/
private static class SharedPreferencesCompat
{
private static final Method sApplyMethod = findApplyMethod();
/**
* 反射查找apply的方法
*
* @return
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private static Method findApplyMethod()
{
try
{
Class clz = SharedPreferences.Editor.class;
return clz.getMethod("apply");
} catch (NoSuchMethodException e)
{
}
return null;
}
/**
*
* commit方法是同步的,并且我们很多时候的commit操作都是UI线程中,毕竟是IO操作,尽可能异步;
* 如果找到则使用apply执行,否则使用commit;
*
* @param editor
*/
public static void apply(SharedPreferences.Editor editor)
{
try
{
if (sApplyMethod != null)
{
sApplyMethod.invoke(editor);
return;
}
} catch (IllegalArgumentException e)
{
} catch (IllegalAccessException e)
{
} catch (InvocationTargetException e)
{
}
editor.commit();
}
}
}
那么我们在使用的时候只需要这样写:
SPUtils.put(context, 'age', 23);
是不是很酷?
3.编写BaseActivity抽象类,通过继承实现复用,通过覆盖实现多态。
我们在编写Activity的时候,其实也会写很多重复的代码。比如说:
- 设置全屏
- 生命周期打印Log
- 设置沉浸状态栏
- 界面是否可以旋转
- 启动另一个Activity
如果我们可以编写一个BaseActivity的抽象类,并且让这个BaseActivity实现一些公共的功能,然后让我们的Activity都继承自这个BaseActivity,那么,我们就可以减少重复代码的出现,同时Activity的业务逻辑也会更加清晰。
public abstract class BaseActivity extends Activity
implements View.OnClickListener
{
/** 是否沉浸状态栏 **/
private boolean isSetStatusBar = true;
/** 是否允许全屏 **/
private boolean mAllowFullScreen = true;
/** 是否禁止旋转屏幕 **/
private boolean isAllowScreenRoate = false;
/** 当前Activity渲染的视图View **/
private View mContextView = null;
/** 日志输出标志 **/
protected final String TAG =
this.getClass().getSimpleName();
/** View点击 **/
public abstract void widgetClick(View v);
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Log.d(TAG, "BaseActivity-->onCreate()");
Bundle bundle = getIntent().getExtras();
initParms(bundle);
View mView = bindView();
if (null == mView)
{
mContextView = LayoutInflater.from(this)
.inflate(bindLayout(), null);
} else{
mContextView = mView;
}
//这里判断允许是否屏幕旋转
if (mAllowFullScreen)
{
requestWindowFeature(
Window.FEATURE_NO_TITLE);
}
//是否沉侵式标题栏
if (isSetStatusBar)
{
steepStatusBar();
}
//写入布局
setContentView(mContextView);
if (!isAllowScreenRoate)
{
setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
initView(mContextView);
setListener();
doBusiness(this);
}
/**
* [沉浸状态栏]
*/
private void steepStatusBar()
{
if (Build.VERSION.SDK_INT >=
Build.VERSION_CODES.KITKAT)
{
// 透明状态栏
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
// 透明导航栏
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
}
/**
* 初始化参数
*
* @param parms
*/
public abstract void initParms(Bundle parms);
/**
* [绑定视图]
*
* @return
*/
public abstract View bindView();
/**
* 绑定布局
*
* @return
*/
public abstract int bindLayout();
/**
* 初始化控件
*
* @param view
*/
public abstract void initView(final View view);
/**
* 绑定控件
*
* @param resId
*
* @return
*/
protected T $(int resId)
{
return (T) super.findViewById(resId);
}
/**
* 设置监听
*/
public abstract void setListener();
@Override
public void onClick(View v) {
widgetClick(v);
}
/**
* 业务操作
*
* @param mContext
*/
public abstract void doBusiness(Context mContext);
/**
* 页面跳转
*
* @param clz
*/
public void startActivity(Class clz)
{
startActivity(new Intent(BaseActivity.this,clz));
}
/**
* 携带数据的页面跳转
*
* @param clz
* @param bundle
*/
public void startActivity(Class clz, Bundle bundle)
{
Intent intent = new Intent();
intent.setClass(this, clz);
if (bundle != null) {
intent.putExtras(bundle);
}
startActivity(intent);
}
/**
* 含有Bundle通过Class打开编辑界面
*
* @param cls
* @param bundle
* @param requestCode
*/
public void startActivityForResult(Class cls,
Bundle bundle,int requestCode)
{
Intent intent = new Intent();
intent.setClass(this, cls);
if (bundle != null) {
intent.putExtras(bundle);
}
startActivityForResult(intent, requestCode);
}
@Override
protected void onRestart()
{
super.onRestart();
Log.d(TAG, "onRestart()");
}
@Override
protected void onStart()
{
super.onStart();
Log.d(TAG, "onStart()");
}
@Override
protected void onResume()
{
super.onResume();
Log.d(TAG, "onResume()");
}
@Override
protected void onPause()
{
super.onPause();
Log.d(TAG, "onPause()");
}
@Override
protected void onStop()
{
super.onStop();
Log.d(TAG, "onStop()");
}
@Override
protected void onDestroy()
{
super.onDestroy();
Log.d(TAG, "onDestroy()");
}
/**
* 简化Toast
* @param msg
*/
protected void showToast(String msg)
{
Toast.makeText(this,msg,Toast.LENGTH_SHORT)
.show();
}
/**
* 是否允许全屏
*
* @param allowFullScreen
*/
public void setAllowFullScreen(boolean allowFullScreen)
{
this.mAllowFullScreen = allowFullScreen;
}
/**
* 是否设置沉浸状态栏
*
* @param isSetStatusBar
*/
public void setSteepStatusBar(boolean isSetStatusBar)
{
this.isSetStatusBar = isSetStatusBar;
}
/**
* 是否允许屏幕旋转
*
* @param isAllowScreenRoate
*/
public void setScreenRoate(boolean isAllowScreenRoate)
{
this.isAllowScreenRoate = isAllowScreenRoate;
}
}
注意:BaseActivity里面只适合封装那些公共的代码逻辑,具体应该封装哪些代码,要视情况而定。