實習週記(第二週)
本週知識清單
- git學習與實踐
- Android程式碼規範
- 網路請求框架使用小結
1. git學習與實踐
1.1 git簡介
git是一個分散式版本控制系統,用於程式碼管理,是多人合作程式碼合併解決衝突的一個利器
1.2 git安裝
直接到官方網站上下載安裝即可
1.3 git的基本使用功能
這部分先拋去遠端倉庫,先講一下本地倉庫的使用。步驟如下:
-
建立版本庫
首先建立一個空的資料夾,然後初始化版本庫
mkdir MyDemo
cd MyDemo
git init
- 編寫自己的程式碼/檔案等
- 把檔案提交到倉庫中
這裡的意思就是,雖然在資料夾中是存在了你編寫後的檔案/程式碼,但你建立的倉庫還沒有加進來這些內容,所以要執行提交命令
git add readme.txt
git commit -m “寫了一個readme檔案”
或者
git add .
git commit -m “提交所有的程式碼/檔案”
執行完這些命令後,後面應該會出現 一些檔案被修改的情況
1.4 git當前狀態查詢
git status
該命令會提示有沒有已修改/新增的檔案等待被add/commit
git diff
該命令提示有哪些程式碼/檔案與上一個版本有什麼不同
1.5 git版本控制
git log
git log --pretty-oneline //去除其他無用訊息,只顯示id和註釋
使用上面的命令檢視之前的版本
git reset --hard HEAD^
回退到上一個版本
git reflog
檢視所以版本記錄,包括最新版本被回退的資訊
找到,之前的新版本ID
git reset --hard ID
返回到新版本
1.6 新增遠端倉庫
註冊一個git程式碼管理網站,常用的有github,碼雲,coding等
首先使用命令生成金鑰,將金鑰新增到選擇的網站上,金鑰一般儲存在C:\Users\使用者名稱稱.ssh
如:github
建立和你本地專案同名的倉庫
複製github倉庫地址
建立連線
git push -u origin master
把本地倉庫內容推送到遠端倉庫上,第一次推送需要加**-u**
1.7 分支管理
-
master主分支
一般由develop功能整合後合併
-
hotfix維護分支
直接從master分支fork出來的分支,用於bug修復,修復完成後應該馬上合併回master分支和develop分支,master分支用新版本號,打上tag
-
develop發展分支
主要開發分支,新功能的分支由它擴充套件
-
feature功能分支
每個新功能位於自己的一個分支,使用decelop分支作為父分支,新功能完成後,合併回develop
-
預釋出測試分支
develop功能整合後,由develop分支fork一個release釋出分支,release分支主要用於bug修復,文件生成和其他面向釋出的任務,測試完畢後合併到master分支,並分配一個版本號打上Tag
1.7.1 建立分支
建立dev分支,並切換到dev分支
git branch dev
git checkout dev
合併成一句話
git checkout -b dev
檢視所有分支
git branch
在dev分支上編寫程式碼,
提交
git push origin [分支名稱]
git checkout master
切換到master分支
把dev分支的結果合併到master分支上
git merge dev
合併完成後,刪除dev分支
git branch -d dev
1.7.2 解決衝突
在多人合作開發中,master不會只有你自己一個合併更新的,當另一個人更新了master,你再合併的分支的話就會產生衝突
- 如在本地倉庫中master和自己的分支產生衝突
Auto-merging readme.txt
CONFLICT (add/add): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.
git會把所有修改過的內容都整合在一起,這裡需要自己手動修改
上傳、提交、刪除
git add .
git commit -m “整合”
git push origin master
git branch -d [分支名字]
- 遠端倉庫和其他人更新同一個分支出現衝突時
git push origin master
error: failed to push some refs to ‘https://github.com/Dream97/GitDemo.git’
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., ‘git pull …’) before pushing again.
hint: See the ‘Note about fast-forwards’ in ‘git push --help’ for details.
如上,當我想更新master分支時,發現遠端的分支早就被別人修改過,丟擲錯誤
我需要把遠端的倉庫pull下來
git pull
執行到這一步發現我的程式碼又被合併了,手動修改
git add .
git commit -m “整合”
git push origin master
有時候git pull會失敗,是因為沒有指定本地分支和遠端分支的連結,需要配置遠端庫和本地的連結
git branch --set-upstream-to=origin/[名字] [名字]
git pull
1.8 標籤
標籤(tag)用於標識版本的的一個快照,指向某個commit的指標,建立和刪除標籤都是瞬間完成的
git checkout master //切換到要打標籤的分支
git tag v1.0 //打新標籤
git tag //檢視所有標籤
也可以把標籤打到歷史提交的commit上
git log --pretty=oneline --abbrev-commit //查詢歷史提交
git tag v0.9 [歷史commit id]
git tag
檢視標籤資訊
git show v0.9
指定標籤資訊
git tag -a v0.9 -m “debug version”
推送標籤
git push origin v0.9
git push origin --tags //推送全部尚未推送到遠端的本地標籤
刪除本地標籤
git tag -d v0.9
刪除遠端標籤
git tag -d v0.9
git push origin :refs/tags/v0.9
2.Android程式碼規範
公司給的程式碼規範本來就有一份文件,但是文件還是有點長的,所以這裡就摘取點比較重要的來記錄一下
2.1 排版
- 縮排風格,縮排空格4個
- 長表示式/語句/引數多行書寫,操作符放在新行之首
- 對齊使用空格鍵
- 操作符的前後間隔
a) ,逗號;分號後面加空格
b) = >= 等比較操作符前後加空格
c) .前後不加空格
d) {}程式碼塊與前面的括號要用空格隔開
2.2 註釋規範
1.檔案註釋:檔案頭部,包名之前
2.類和介面註釋:package關鍵字之後,class或者interface之前
3.類和介面的註釋內容:
/**
* <一句話描述>
* <功能詳細簡述>
* @author [作者]
* @version [版本號, YYYY-MM-DD]
* @see [相關類/方法]
* @since [產品/模組版本]
* @deprecated [已廢棄說明]
*/
4.方法的註釋內容
推薦使用@exception標註Runtime異常,@throws標註非Runtime異常
/**
* <一句話功能簡述>
* <功能詳細描述>
* @param [引數1] [引數1說明]
* @param [引數2] [引數2說明]
* @return [返回型別說明]
* @exception/throws [違例型別] [違例說明]
* @see [類、類#方法、類#成員]
* @deprecated
*/
5.在程式塊結束行右方加註釋標記,表明程式塊的結束
if (...) {
}//end of if (...) 指明是哪條if語句結束
while (...) {
}//end of while(...)指明哪條if語句結束
2.3 命名規範
1.包名:小寫
com.公司名.產品名.模組名稱
com.公司名.部門名稱.專案名稱
2.類名:意義完整的英文描述,首字母大寫
3.方法名:第一個字母小寫
4.資原始檔,id命名:全部小寫,多個單子用下劃線隔開
5.打包釋出的安裝包命名規則:“專案名-釋出版本型別-版本名-編譯日期”
a)dev:開發版,多數功能尚未完成
b)alpha:內測版,功能較不穩定
c)beta:冊數版,功能較為穩定
d)release:釋出版本
6.普通類的屬性以一個小寫"m"開頭,其餘大小寫混合法,內部類的屬性以"mm"開頭
7.資原始檔的命名:“btn_selector”,字首使用:背景圖片(bg)、圖示圖片(ic)
8.佈局檔案:"字首_用途"如:activity_login.xml
9.View控制元件id:“tv_msg”,字首如:TextView(tv)、EditText(et)、ProgressBar(pb)、LinearLayout(ll)、RelativeLayout(rl)、GridView(gv)等
2.3 JTEST規範
- 使用System.arraycopy(),不使用迴圈來複制陣列
- finally 再異常處理時提供 finally塊來執行任何清除操作。如果丟擲一個異常,那麼相匹配的catch子句就會執行,然後控制就會進入finally塊(如果有的話)。finalize方法名。Java技術允許使用 finalize() 方法在垃圾收集器將物件從記憶體中清除出去之前做必要的清理工作。這個方法是由垃圾收集器在確定這個物件沒有被引用時對這個物件呼叫的。它是在Object類中定義的, 因此所有的類都繼承了它。子類覆蓋finalize()方法以整理系統資源或者執行其他清理工作。
finalize() 方法是在垃圾收集器刪除物件之前對這個物件呼叫的。 - 初始化時不要使用類的非靜態屬性。
說明:你用一個非靜態屬性去初始化一個變數,有可能非靜態屬性自己本身還沒有初始化。 - 顯式初始化所有的區域性變數。
因為沒有初始化的欄位會是一個潛在的bug,如一個整數開始你不能確定什麼值就初始化一個0給它 - 宣告方法違例的時候不要使用 Exception ,應該使用它的子類。
Exeption報的異常沒有它的子類具體。例如,DataFormatException,如果出異常就知道是資料格式異常。 IOException,就知道是IO操作的異常 - 使用StringBuffer的時候設定初始容量。在建立StringBuffer物件時java會預設分配一段空間給它,預設的空間可能過大,這樣就浪費空間。在程式執行過程中可能預設的空間不夠java又要重新建立一個StringBuffer這樣浪費時間,
- 執行緒同步中,使用 notifyAll() 代替 notify()。
- 非同步方法中不能呼叫 wait() , notify() 方法。
- 使用wait(),notify()代替while(),sleep()。sleep()方法是使執行緒停止一段時間的方法。在sleep 時間間隔期滿後,執行緒不一定立即恢復執行。這是因為在那個時刻,其它執行緒可能正在執行而且沒有被排程為放棄執行,除非(a)“醒來”的執行緒具有更高的優先順序(b)正在執行的執行緒因為其它原因而阻塞。wait()是執行緒互動時,如果執行緒對一個同步物件x發出一個wait()呼叫,該執行緒會暫停執行,被調物件進入等待狀態,直到被喚醒或等待時間到。
- 實現 equals() 方法時,先用 getClass() 或者 instanceof 進行型別比較,通過後才能繼續比較。首先兩個物件先用getClass()獲取它們所屬的類,再用instanceof看這兩個物件是不屬於同一個類,如果不是,就不用equals()比較了。
- 不要使用 Date[] 而要使用 long[] 替代。基本型別資料運算效率更高
2.4 國際化
1.不要使用一個字元進行邏輯操作,使用Characater。如果程式碼要在一個國家環境中執行的話。我們可以使用字元比較方法,這些方法使用統一字元比較標準來定義字元的屬性的。
public class CLOFixed {
public boolean isLetter (char ch) {
boolean _isLetter = Character.isLetter(ch);
return _isLetter;
}
}
2.不要進行字串連線操作,使用MessageFormat 。
3.使用 StringTokenizer 代替 indexOf() 和 substring() 。
4.不要使用 Date.toString(),Time.toString()方法。'DateFormat’類提供了一個預定義的格式型別來指定本地的格式。
5.字元和字串常量應該放在資原始檔中。
6.不要使用數字的 toString() 方法。
7.不要使用 String 類的 compareTo(), equals() 方法。
建議不要使用’String.equals ()’方法,因為在統一字元比較標準中不一定按照相關的順序來比較。 ‘Collator’提供的預定義整理規則來排序string,Collator類呼叫’getInstance ()’方法,一般來說,可以為預設的本地建立一個Collator。例如:Collator myCollator = Collator.getInstance (); 建立Collator的時候你也可以指定一個特殊的locale。 例如:Collator myFrenchCollator = Collator.getInstance (Locale.FRENCH); 然後就可以呼叫’Collator.compare ()’來執行一個本地的字元比較myCollator.compare (s1,s2);
3 網路請求框架使用小結
Android開發大多數的時候是使用HTTP來進行網路請求的。HTTP 請求一般採用原生的 HttpClient 和 HttpUrlConnection 的兩種網路訪問方式。可是在 Android 5.0 的時候 Google 就不推薦使用 HttpClient 了,到了 Android 6.0(api 23)SDK,不再提供 org.apache.http.*(只保留幾個類)為了更方便快捷地使用HTTP請求,我們往往會自己封裝網路請求類或者使用其他第三方網路請求框架。下面總結一下曾經用過的兩個網路請求框架Volley 和 OkHttp
3.1Volley
2013年 Google I/O大會 適用於資料量不大但通訊頻繁的網路操作
2、基於請求佇列,基於全域性性/區域性性
RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());
3、使用get方法請求百度
RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());
StringRequest mStringRequest = new StringRequest(Request.Method.GET,
"http://www.baidu.com",
new Response.Listener<String>() {
@Override
public void onResponse(String Response) {
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyErroe error){
}
}
});
//將請求新增到請求佇列中
mQueue.add(mStringRequest);
4、使用JsonRequest轉換成Java實體類
RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());
JsonObjectRequest mJsonObjectRequest = new JsonObjectRequest(
Request.Method.POST,
"http://...",
new Response.Listener<JsonObject>() {
@Override
public void onResponse(JsonObject response) {
MyBean myBean = new Gson().fromJson(response.toString(),MyBean.class);
...
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyErroe error){
}
});
mQueue.add(mJsonObjectRequest);
5、使用ImageLoader載入圖片
ImageLoader的內部使用ImageRequest來實現,先顯示預設圖片,圖片載入完成才會顯示到ImageView
RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());
ImageLoader imageLoader = new ImageLoader(mQueue, mew BitmapCache());
ImageLoader.ImageListener listener = ImageLoader.getImageListener();
imageLoader.get("http://...",
listener);
6、使用NetWorkImageView載入圖片
<com.android.volley.toolbox.NetworkImageView
android:id="@+id/nv_image"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerHorizontal="true">
</com.android.volley.toolbox.NetworkImageView>
程式碼中使用
RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());
ImageLoader imageLoader = new ImageLoader(mQueue,new BitmapCache());
nv_image.setDefaultImageResId(R.drawable.ic_default);
nv_image.setErrorImageResId(R.drawable.ic_error);
nv_iamge.setImageUrl("http...",imageLoader);
3.2 OkHttp
OkHttp出自Square公司,在目前開發中是一個使用頻率非常高的一個網路請求框架。特別是在Square釋出Retrofit後,基於OkHttp的Retrofit+RxJava基本上成為了Android主流框架。下面瞭解一下okHttp的基本使用
1、配置gradle
2、非同步GET請求
Request.Builder requestBuilder = new Requet.Builder().url("http:...");
requestBuilder.method("GET", null);
Request request = requestBuilder.build();
OkHttpClient mOkHttpClient = new OkHttpClient();
Call mCall = mOkHttpClient.newCall(request);
mCall.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) {
String str = response.body().string();
}
});
onResponse的回撥並非UI執行緒
3、非同步POST請求
OkHttp3非同步請求使用FormBody ,OkHttp2.x使用FormEncodingBuilder
RequestBody formBody = new FormBody.Builder()
.add("key","value")
.build();
Request request = new Requet.Builder()
.url("http:....")
.post(formBody)
.build();
OkHttpClient mOkHttpClient = new OkHttpClient();
Call mCall = mOkHttpClient.newCall(request);
mCall.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) {
String str = response.body().string();
}
});
4、檔案和引數混合上傳
OkHttpClient client = new OkHttpClient();
MultipartBody.Builder builder = new MultipartBody.Builder();
if (map!=null)
{
for (Map.Entry<String,String> entry:map.entrySet())
{
builder.addFormDataPart(entry.getKey(),entry.getValue()); //新增請求引數到請求體
}
}
File file = new File("檔案路徑");
if(file.exists()){
Log.d(TAG, "post3: 檔案存在");
String TYPE = "application/octet-stream";
RequestBody fileBody = RequestBody.create(MediaType.parse(TYPE),file);
RequestBody requestBody = builder
.setType(MultipartBody.FORM)
.addFormDataPart("detail_image",file.getName(),fileBody)
.build();
Request request = new Request.Builder()
.url(address)
.post(requestBody)
.addHeader("Authorization","Bearer "+CommonVari.token)
.build();
}else {
Log.d(TAG, "post3: 檔案不存在");
RequestBody requestBody = builder
.setType(MultipartBody.FORM)
.build();
Request request = new Request.Builder()
.url(address)
.post(requestBody)
.addHeader("Authorization","Bearer "+CommonVari.token)
.build();
}
client.newCall(request).enqueue(callback);
5、非同步下載檔案
Request request = new Requet.Builder()
.url("http:....")
.build();
OkHttpClient mOkHttpClient = new OkHttpClient();
Call mCall = mOkHttpClient.newCall(request);
mCall.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) {
InputStream inputStream = response.body().byteStream();
FileOutputStream outputStream = response.body().byteStream();
String filePath = "";
try {
if (Environment.getExternalStorageState()
.equals(Environment.MEDIA_MOUNTED)) { //如果安裝了SD卡
filePath = Environment.getExternalStorageDirectory().
getAbsolutePath();
} else { //沒有安裝SD卡
filePath = getFilesDir().getAbsolutePath();
}
File file = new File(filePath,"xxxx.txt");
if(null != file) {
outputStream = new FileOutputStream(file); //指定輸出某檔案
byte[] buffer = new byte[2048];
int len = 0;
while((len = inputStream.read(buffer)) != -1) {
FileOutputStream.write(buffer, 0, len);
}
}
outputStream.flush();
} catch(IOException e) {
}
}
});
6、設定超時時間和快取
File sdcache = getExternalCacheDir();
int cacheSize = 10 * 1024 * 1024;
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout(15,TimeUnit.SECONDS)
.writeTimeout(20,TimeUnit.SECONDS)
.readTimeout(20,TimeUnit.SECONDS)
.cache(new Cache(sdcache.getAbsoluteFile(), cacheSize));
mOkHttpClient = builder.build();