天天寫代碼,月月寫代碼,最後代碼寫成什麼樣了?有木有提高,這纔是一個程序員成長的關鍵。今天記錄一下最近的一些感悟。
一、保持你的創造力和創新能力
1.勞逸結合
程序猿,咱傷不起啊,被催着加班是常有的事。爲了防止掙得多,花得少,死得早發生!咱還是勞逸結合。
今天我就講講自己的感悟。曾經一段時間,我連續加班了2~3個月,天天到晚上凌晨回家睡覺,剛畢業嘛,還可以,連續下來,很快的把項目完成了,並且上線了,只要15天,包括產品花的時間,測試時間和接口開發時間。很多工作都並行進行,很多天通宵。。。幾個月後發現自己的效率開始大幅下降,智商變低!!一個簡單的單詞都會卡殼。發現自己在寫代碼的時候往往採用的是最直接解決問題的辦法,沒有變通和太多的思考。代碼質量可想而知。。。
好吧,看樣子上邊的狀態我是不能在醬紫下去了,我還是好好注意休息吧,勞逸結合,我還想工作到領退休金的那一天(說不定要我80大壽的那天才能退休- -),那個老淚縱橫啊。。。
後來,我開始了代碼的質量和代碼的含金量。我想告訴大家的是,偶爾加班趕上線並不一定真的能搞好一個項目,還是用自己的智慧寫代碼,會事半功倍,就拿上邊這個簡單的緩存數據庫來說吧。當初要的是實現6個界面數據緩存,每個界面有幾十個字段,剛開始是像創建數據庫,把解析後的列表存到數據庫,這樣就要維護6張表,每張表有幾十個字段,那不把人搞傻了。。反正耗費時間很長就是了,用了上邊這個方法,靈活又簡單,還不用關心字段變動。這就是idea!
2.學會分享與交流
你的方法並不一定是最好的方法,要學會分享和交流,纔會發現自己的不足,不斷的思考纔會有較好的方法。團隊合作,交流必不可少,程序猿不能只做一個一言不發的編碼工具,要多交流思想,隨時有個清晰的交流思路,這樣以後的成長是非常重要的。分享會讓你更深入的思考一樣東西,交流可以提高你的表達能力,到了該漲工資的時候千萬別憋着,O(∩_∩)O哈哈~。。。
二、程序猿,你要有夢想
我的夢想是。。。。擼出一個吊炸天的遊戲。。。。O(∩_∩)O哈哈~,千里之行,始於足下,還是先擼出個帥氣的Hello World!!尼瑪,太扯了。。。
1.關於未來
我想做什麼呢?是給別人老老實實打工,到退休麼?不,程序猿這條路不可能幹一輩子!!10年對你來說都太長了。。掙得多,花得少,死得早~~那你就要知道自己想要的是什麼,未來你的方向是什麼。世界沒有那麼光明,擼代碼買房壓力山大,那還是想想怎麼爲自己幹活,自己在互聯網行業立足吧。你可以大聲告訴你的Boss,20年後互聯網屬於我們,你個糟老頭子別囂張!!O(∩_∩)O哈哈~我以後不會讓我的程序猿加班的,會給他們更多的假期的獎金 - -
2.關於現在
天天擼代碼,不一樣的功能,同樣的代碼。對於剛畢業一年左右的我們,我覺得該對學習,不斷的擴展自己的視野,讓自己去學更多的東西。我畢業到現在快半年了,09級的。。我在做Android開發的同時,學了IOS開發,現在又在學Cocos2d-x遊戲開發,未來想在手遊裏幹出點什麼。。。做應用找不到前途啊。。。。難道是想着20年後還給別人打工??不能夠啊!!平時不怎麼寫博客,今天項目提測了,得寫點什麼吧。。
3.關於腳步
我想人的價值在於學習和工作,當然只是事業方面的。還有家庭也是很重要的,經營好一份感情,讓代碼擼得不那麼淒涼。。腳踏實地的走,不能太浮躁了,剛畢業就想做出什麼吊炸天的東西或者快速學會什麼都不現實的,腳踏實地的,一步一步的來,不斷積累纔是重點。我有很多同學都在急於求成,剛畢業半年就想學會很多,不斷的換工作嘗試。這是不好的,未來路那麼長,我們得認認真真,腳踏實地的走下去,等我們準備好了,再放開手去做,換工作並不能夠很好的解決當前的矛盾,關鍵是我們要知道自己想要的是什麼,不能跳來跳去,最後虛度了時光。
三、擼代碼的一些建議
擼得一手好代碼,把更多的時間花在享受生活上!
1.模塊劃分
實現一個功能,這個功能可能比較簡單,可獨立可不獨立。功能相似度達到多少以下的時候我們可以單獨創建一個界面和類配合實現呢?這個問題在寫程序的時候我有點糾結,但是一個同事,他喜歡把很多不同的東西整合在一個裏邊。這樣有的功能區分度不高,導致我添加百度統計的時候的不知道去那統計。首先得贊一下他的整合能力。那麼多的東西整合在一起,複雜度顯然會比較高,容易導致傷筋動骨的事,改bug就很難了。
關於過多的面相對象知識,這裏沒辦法一一講解,但是我們得注意,數據建模很重要,把重要的、共用的信息提取出來進行封裝會節約我們很多的時間。在封轉控件的時候儘量做到與義務邏輯脫離,把需要實現邏輯的東西放到回調接口中來處理。封裝的控件儘量只實現接受界面數據的初始化和展示,把數據的操作放到回調接口中來實現。
2.儘量防止重複代碼過多
今天干了件很爽的事,一個動畫效果需要在6個界面中實現。經過思考和查找發現了8個共有的屬性,並且可以提取出來的。。喜出望外啊,我能單獨的抽取出這些屬性,進行封裝豈不是很好。在經過實踐之後,我把功能提取出來了。給大家看下:
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.View.OnTouchListener;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.TranslateAnimation;
import android.widget.AbsListView;
import android.widget.LinearLayout;
import com.demo.widget.search.MySearchToolBar;
/**
* 將搜索欄動畫方法封裝,抽取出公共部分
* 裏邊包含了下拉刷新控件,和搜索欄控件
*
* @author [email protected]
*
*/
public class SearchToolBarAnimation {
public SearchToolBarAnimation(){
}
/**
* 搜索欄動畫
*
* @param searchToolbarHeight
* 搜索欄高度
* @param mSearchToolBar
* 搜索欄控件
* @param mDataListView
* 列表頁的自定義ListView
* @param mGapView
* 跟隨滾動視圖
*/
private void translateTitle(final AnimationItem animationItem) {
if (animationItem.searchToolbarHeight < 1) {
int w = View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED);
int h = View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED);
animationItem.mSearchToolBar.measure(w, h);
animationItem.searchToolbarHeight = animationItem.mSearchToolBar
.getMeasuredHeight();
}
final int searchToolbarHeightTemp = animationItem.searchToolbarHeight;
Animation animation = animationItem.mSearchToolBar.getAnimation();
if (animation != null) {
return;
}
final int visibility = animationItem.mSearchToolBar.getVisibility();
TranslateAnimation translate1 = null;
TranslateAnimation translate2 = null;
if (visibility == View.VISIBLE) {
// mSearchToolBar.setVisibility(View.GONE);
LinearLayout.LayoutParams gapViewParams = new LinearLayout.LayoutParams(
1, 0);
animationItem.mGapView.setLayoutParams(gapViewParams);
translate1 = new TranslateAnimation(0.0F, 0.0F, 0.0F,
-animationItem.searchToolbarHeight);
translate2 = new TranslateAnimation(0.0F, 0.0F,
animationItem.searchToolbarHeight, 0.0F);
// mSearchToolBar.setVisibility(View.GONE);
} else {
translate1 = new TranslateAnimation(0.0F, 0.0F,
0.0F - animationItem.searchToolbarHeight, 0.0F);
translate2 = new TranslateAnimation(0.0F, 0.0F, 0.0F,
animationItem.searchToolbarHeight);
// mSearchToolBar.setVisibility(View.VISIBLE);
}
translate1.setDuration(300);
translate2.setDuration(300);
translate1.setInterpolator(new AccelerateDecelerateInterpolator());
translate2.setInterpolator(new AccelerateDecelerateInterpolator());
translate1.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation arg0) {
}
@Override
public void onAnimationRepeat(Animation arg0) {
}
@Override
public void onAnimationEnd(Animation arg0) {
if (visibility == View.VISIBLE) {
LinearLayout.LayoutParams gapViewParams = new LinearLayout.LayoutParams(
1, 0);
animationItem.mGapView.setLayoutParams(gapViewParams);
animationItem.mSearchToolBar.setVisibility(View.GONE);
} else {
LinearLayout.LayoutParams gapViewParams = new LinearLayout.LayoutParams(
1, searchToolbarHeightTemp);
animationItem.mGapView.setLayoutParams(gapViewParams);
animationItem.mSearchToolBar.setVisibility(View.VISIBLE);
}
animationItem.mSearchToolBar.clearAnimation();
}
});
translate2.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
animationItem.mDataListView.clearAnimation();
}
});
animationItem.mSearchToolBar.clearAnimation();
animationItem.mDataListView.clearAnimation();
translate1.setFillEnabled(true);
translate2.setFillEnabled(true);
translate1.setFillAfter(true);
translate2.setFillAfter(true);
animationItem.mSearchToolBar.startAnimation(translate1);
animationItem.mDataListView.startAnimation(translate2);
}
/**
* 獲得SearchToolbar的高度
*/
private void getSearchToolbarHeight(AnimationItem animationItem) {
int w = View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED);
int h = View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED);
animationItem.mSearchToolBar.measure(w, h);
animationItem.searchToolbarHeight = animationItem.mSearchToolBar.getMeasuredHeight();
}
/**
* 綁定所有監聽器和動畫效果
* @param animationItem
*/
public void initAnimation(final AnimationItem animationItem) {
//初始化數據
getSearchToolbarHeight(animationItem);
getTransHeight(animationItem);
if (animationItem.searchToolbarHeight != 0) {
LinearLayout.LayoutParams gapViewParams = new LinearLayout.LayoutParams(
1, animationItem.searchToolbarHeight);
animationItem.mGapView.setLayoutParams(gapViewParams);
}
animationItem.mDataListView
.setOnScrollListener(new ScrollOverListView.OnMyScorllListener() {
@Override
public void onScrollStateChanged(AbsListView view,
int scrollState) {
}
@Override
public void onScroll(AbsListView view,
int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
final int currentFirstVisibleItem = view
.getFirstVisiblePosition();
Log.d("liwt", "onScroll currentFirstVisibleItem:"
+ currentFirstVisibleItem
+ " mLatestFirstVisibleItem:"
+ animationItem.mLatestFirstVisibleItem);
Log.i("liwt", "onScroll mTouchDown:"
+ animationItem.mTouchDown + " mSwitched:"
+ animationItem.mSwitched);
if (!animationItem.mTouchDown
|| !animationItem.mSwitched) {
int type = 0;
if (currentFirstVisibleItem > animationItem.mLatestFirstVisibleItem) {
type = ISlideTabHostListener.SLIDE_DOWN;
if (animationItem.mSearchToolBar
.getVisibility() == View.VISIBLE) {
translateTitle(animationItem);
}
} else if (currentFirstVisibleItem < animationItem.mLatestFirstVisibleItem) {
type = ISlideTabHostListener.SLIDE_UP;
if (animationItem.mSearchToolBar
.getVisibility() == View.GONE) {
translateTitle(animationItem);
}
}
if (type > 0 && animationItem.mTouchDown) {
animationItem.mSwitched = true;
}
}
animationItem.mLatestFirstVisibleItem = currentFirstVisibleItem;
}
});
animationItem.mDataListView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.i("liwt", "touch action" + event.getAction());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
animationItem.mTouchDown = true;
break;
case MotionEvent.ACTION_OUTSIDE:
case MotionEvent.ACTION_UP:
animationItem.mTouchDown = false;
animationItem.mSwitched = false;
break;
}
return false;
}
});
}
/**
* 獲得執行動畫的高度
*/
private void getTransHeight(final AnimationItem animationItem) {
// 注意:如下獲得控件高度的方法對設置了Visiblity=gone 屬性的控件無效。
ViewTreeObserver vto2 = animationItem.mDataListView.getViewTreeObserver();
vto2.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {
animationItem.mDataListView.getViewTreeObserver()
.removeGlobalOnLayoutListener(this);
animationItem.translateHeight = animationItem.mDataListView.getHeight();
if (animationItem.translateHeight != 0) {
animationItem.mSearchToolBar.setTranslateHeight(animationItem.translateHeight);
}
}
});
}
public static class AnimationItem {
public static AnimationItem getInstance() {
return new AnimationItem();
}
public boolean mTouchDown = false;
public boolean mSwitched = false;
public int mLatestFirstVisibleItem = 0;
public View mGapView = null;
/** 搜索工具條的高度 */
public int searchToolbarHeight = 0;
/** 搜索結果列表 **/
public PullDownView mDataListView = null;
/** 搜索條件工具條 */
public MySearchToolBar mSearchToolBar = null;
/** 動畫執行高度*/
public int translateHeight;
}
public interface ISlideTabHostListener {
public static final int SLIDE_UP = 1;
public static final int SLIDE_DOWN = 2;
public void slide(int slideType);
}
}
注:以上是一個PullDownListView ,加一個自定義搜索工具條的代碼,它實現的是搜索工具條自動收放。避免了6*300行的重複代碼。原來程序員也可以開心一刻。。。
3.封轉方法的時候對方法的調用約束儘量降低、程序的健壯性要強
再給一個經典的do{}while(false)的方法,做到寫程序優雅,嚴謹,容易查找bug。
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils;
import com.<span style="font-family: Arial, Helvetica, sans-serif;">demo</span><span style="font-family: Arial, Helvetica, sans-serif;">.database.TableCacheDatabase;</span>
import com.<span style="font-family: Arial, Helvetica, sans-serif;">demo</span>.globleData.GlobleData;
/**
* 來電列表數據緩存數據庫
*
* @author [email protected]
*
*/
public class ListDataCache {
/** 緩存使用者的id*/
private static final String USERID = "USERID";
/** 我的賣車緩存 */
private static final String MYSELLCARCACHE = "MYSELLCARCACHE";
/** 我的買車緩存*/
private static final String MYBUYCARCACHE = "MYBUYCARCACHE";
/** 搜索賣車緩存 */
private static final String STORESELLCARCHE = "STORESELLCARCHE";
/** 搜索買車緩存 */
private static final String STOREBUYCARCHE = "STOREBUYCARCHE";
/** 我的來電列表緩存 */
private static final String MYPHONECARCHE = "MYPHONECACHE";
/** 店內來電列表緩存 */
private static final String STOREPHONECARCHE = "STOREPHONECACHE";
private static final String TABLENAME = "CACHETABLE";
public static final String CREATETABLESQL = "CREATE TABLE IF NOT EXISTS "+
TABLENAME+ " ( "+
MYSELLCARCACHE + " text, "+
MYBUYCARCACHE + " text, " +
STORESELLCARCHE +" text, "+
STOREBUYCARCHE + " text, " +
MYPHONECARCHE + " text, "+
STOREPHONECARCHE + " text, "+
USERID + " text NOT NULL);";
public enum CACHETYPE{
TYPE_MYSELLCARCACHE,
TYPE_MYBUYCARCACHE,
TYPE_STORESELLCACHE,
TYPE_STOREBUYCACHE,
TYPE_MYPHONECACHE,
TYPE_STOREPHONECACHE
};
private SQLiteDatabase db;
private TableCacheDatabase cache;
private Context context;
public ListDataCache(Context context){
this.context = context;
cache = new TableCacheDatabase(context);
}
/**
* 將json數據放入緩存
* @param value json值
* @param TYPE 緩存位置枚舉位置
*/
public void addDataToCache(String value,CACHETYPE TYPE){
do{
if(TextUtils.isEmpty(value)){
continue;
}
if(cache==null){
continue;
}
db = cache.getWritableDatabase();
if(db==null){
continue;
}
Cursor cursor = db.query(TABLENAME, null, USERID+"=?", new String[]{GlobleData.getUserInfo(context).userID}, null, null, null);
if(cursor==null){
continue;
}
ContentValues values = getContentValues(value,TYPE);
if(values==null||values.size()==0){
continue;
}
//這裏是查找性的插入或更新,其實我覺得這裏可以由SQL語句優化,不用那麼麻煩的去,一條SQL查找兼插入或更新豈不更好- -
if(cursor.moveToFirst()){
if(!cursor.isAfterLast()){
db.update(TABLENAME, values, USERID+"=?",new String[]{GlobleData.getUserInfo(context).userID});
}
}else{
values.put(USERID, GlobleData.getUserInfo(context).userID);
db.insert(TABLENAME, null,values);
}
cursor.close();
db.close();
values.clear();
}while(false);
}
/**
* 獲取ContentValues 根據值和類型
* @param value
* @param TYPE
* @return ContentValues
*/
private ContentValues getContentValues(String value,CACHETYPE type){
ContentValues values = new ContentValues();
switch(type){
case TYPE_MYSELLCARCACHE:{
values.put(MYSELLCARCACHE, value);
}
break;
case TYPE_MYBUYCARCACHE:{
values.put(MYBUYCARCACHE, value);
}
break;
case TYPE_STORESELLCACHE:{
values.put(STORESELLCARCHE, value);
}
break;
case TYPE_STOREBUYCACHE:{
values.put(STOREBUYCARCHE, value);
}
break;
case TYPE_MYPHONECACHE:{
values.put(MYPHONECARCHE, value);
}
break;
case TYPE_STOREPHONECACHE:{
values.put(STOREPHONECARCHE, value);
}
break;
default:break;
}
return values;
}
/**
* 獲取當前列的位置
* @param cursor
* @param TYPE
* @return index
*/
private int getIndexByType(Cursor cursor, CACHETYPE type){
int index = 0;
switch(type){
case TYPE_MYSELLCARCACHE:{
index = cursor.getColumnIndex(MYSELLCARCACHE);
}
break;
case TYPE_MYBUYCARCACHE:{
index = cursor.getColumnIndex(MYBUYCARCACHE);
}
break;
case TYPE_STORESELLCACHE:{
index = cursor.getColumnIndex(STORESELLCARCHE);
}
break;
case TYPE_STOREBUYCACHE:{
index = cursor.getColumnIndex(STOREBUYCARCHE);
}
break;
case TYPE_MYPHONECACHE:{
index = cursor.getColumnIndex(MYPHONECARCHE);
}
break;
case TYPE_STOREPHONECACHE:{
index = cursor.getColumnIndex(STOREPHONECARCHE);
}
break;
default:break;
}
return index;
}
/**
* 獲取緩存數據根據位置
* @param TYPE 位置枚舉類型
* @return 緩存的json數據
*/
public String getDataCache(CACHETYPE type){
String value = "";
do{
if(cache==null){
continue;
}
db = cache.getWritableDatabase();
if(db==null){
continue;
}
Cursor cursor = db.query(TABLENAME, null, USERID+"=?", new String[]{GlobleData.getUserInfo(context).userID}, null, null, null);
if (cursor == null){
continue;
}
if(cursor.moveToFirst()){
if(!cursor.isAfterLast()){
int index = getIndexByType(cursor, type);
value = cursor.getString(index);
}
}
cursor.close();
db.close();
}while(false);
return value;
}
}
注:以上是緩存數據用的一個簡易數據庫緩存,它需要緩存6中不同的數據,涉及到緩存的添加和更新,怎麼去管理這個緩存呢??當然枚舉類型是一種合適的方法,還要加上一些嚴謹的代碼風格,習慣了。寫起代碼會比較好管控bug,寫完的代碼心裏也有底。
小結一下:面相對象的編程思想,還有代碼的優化和代碼規範是每個程序員成長中的重點吧,寫了段時間的程序,今天有空了,就總結一下。