svn操做
student05 123
http://192.168.77.84/svn/Mobliesfe05
代碼包結構劃分
目的:方便項目後期的維護和管理
1.按照代碼類型劃分
android
2.按照業務類型劃分
按照業務的不一樣,將不一樣的文件放到 不一樣的包中
傳智播客軟件:cn.itcast
招生:cn.itcast.student
教學:cn.itcast.teach
財務:cn.itcast.money
陰影的實現
<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:background="@drawable/splash"
>
<!-- layout_alignParentBottom : 在父控件的底部
layout_centerHorizontal : 在父控件中水平居中
layout_marginBottom : 距離父控件底部的邊框的距離
shadowColor : 陰影的顏色
shadowDx : x的偏移量
shadowRadius : 偏移弧度
-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="版本:1.0"
android:textColor="#FFFFFF"
android:textSize="20sp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:shadowColor="#00FF00"
android:shadowDx="1"
android:shadowDy="1"
android:shadowRadius="2"
/>
</RelativeLayout>
去除標題欄 (重點)
1.清單文件中使用系統的主題樣式
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.Black.NoTitleBar" >
缺陷:樣式不匹配
2.修改res -> values -> styles.xml AppTheme主題樣式
<style name="AppTheme" parent="AppBaseTheme">
<!-- 去除標題欄操做 -->
<item name="android:windowNoTitle">true</item>
</style>
3.使用代碼實現去除標題欄
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);//去除標題欄,必須執行在setContentView方法以前,只在當前的activity生效
setContentView(R.layout.activity_splash);
}
獲取展現版本名稱
1.建立一個工具類,獲取版本號和版本名稱
public class PackageUitls {
/**
* 獲取版本號
* 2016-9-26 上午10:32:58
*/
public static int getVersionCode(Context context){
//1.包的管理者,用來獲取應用程序的清單文件中的信息
PackageManager pm = context.getPackageManager();
try {
//2.獲取清單文件中的信息
//packageName : 應用程序的包名
//flags : 額外信息標示,好比GET_ACTIVITIES:能夠額外獲取出activity的信息,若是是0表示只能獲取包名,版本號,版本名稱等基本信息
//getPackageName() : 獲取當前應用程序的包名
PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
//3.獲取相關信息
return packageInfo.versionCode;
} catch (NameNotFoundException e) {
//包名找不到的異常
e.printStackTrace();
}
return -1;
}
/**
* 獲取版本名稱
* 2016-9-26 上午10:32:58
*/
public static String getVersionName(Context context){
//1.包的管理者,用來獲取應用程序的清單文件中的信息
PackageManager pm = context.getPackageManager();
try {
//2.獲取清單文件中的信息
//packageName : 應用程序的包名
//flags : 額外信息標示,好比GET_ACTIVITIES:能夠額外獲取出activity的信息,若是是0表示只能獲取包名,版本號,版本名稱等基本信息
//getPackageName() : 獲取當前應用程序的包名
PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
//3.獲取相關信息
return packageInfo.versionName;
} catch (NameNotFoundException e) {
//包名找不到的異常
e.printStackTrace();
}
return "";
}
}
2.展現給activity中的textview顯示
/**
* 初始化控件
* 2016-9-26 上午10:40:58
*/
private void initView() {
mVersion = (TextView) findViewById(R.id.splash_tv_version);
//獲取應用程序的版本名稱,設置給textview顯示
mVersion.setText("版本:"+PackageUitls.getVersionName(this));
}
鏈接服務器
SplashActivity.java
private void update() {
//1.鏈接服務器,獲取服務器數據,判斷是否有最新版本
//1.1.鏈接服務器,注意:(1).聯網操做,耗時操做,放到子線程中;(2).權限;(3).HttpUrlConnection httpclient Xutils volly okhttp
//connTimeout : 鏈接超時時間
HttpUtils httpUtils = new HttpUtils(2000);
//發送請求操做
//method : 請求方式
//url : 請求的地址
//params : 請求傳遞參數
//RequestCallBack : 請求的回調函數,用來接受服務器傳遞的信息
httpUtils.send(HttpMethod.GET, CONNECTURL, null, new RequestCallBack<String>() {
//請求成功調用的方法
@Override
public void onSuccess(ResponseInfo<String> arg0) {
// TODO Auto-generated method stub
}
//請求失敗調用的方法
@Override
public void onFailure(HttpException arg0, String arg1) {
// TODO Auto-generated method stub
}
});
}
xml和json封裝數據 (重點)
xml
json
{"code":"2","apkurl":"xxxxxxx","msg":"新版本上線了,快來下載吧!!!!!"}
注意:
notepad++ Utf-8 無bom
Editplus utf-8(選擇) utf-8+bom
獲取服務器返回的數據
1.修改請求路徑
//10.0.2.2 至關於 127.0.0.1,僅限於虛擬機,若是是真機要使用ip地址(真機的ip地址要和電腦在同一個網段)
/**請求路徑**/
private static final String CONNECTURL = "http://10.0.2.2:8080/update.html";
2.在請求成功的方法中獲取服務器返回的數據
//請求成功調用的方法
//responseInfo : 保存有服務器返回的數據
@Override
public void onSuccess(ResponseInfo<String> responseInfo) {
//1.2.獲取服務器返回的數據
//問題:服務器返回那些數據.code:新版本的版本號;apkurl:新版本的下載地址;msg:新版本優化信息
//問題:服務器要返回3個數據,考慮封裝數據的形式 xml json
String json = responseInfo.result;//獲取服務器返回的數據
Log.i(TAG, json);
}
解析json數據判斷是否有最新版本操做 (重點)
SplashActivity.java
protected void processJson(String json) {
try {
//將json串封裝成JSONObject對象
JSONObject jsonObject = new JSONObject(json);
mNewCode = jsonObject.getInt("code");
mNewUrl = jsonObject.getString("apkurl");
mNewMsg = jsonObject.getString("msg");
Log.i(TAG, "code:"+mNewCode+" apkurl:"+mNewUrl+" msg:"+mNewMsg);
//根據服務器返回的新版本的版本號和當前應用程序的版本號進行比較,若是一致,沒有最新版本,若是不一致,有最新版本
if (mNewCode == PackageUitls.getVersionCode(this)) {
//一致,沒有最新版本
}else{
//不一致,有最新版本
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
彈出更新對話框
SplashActivity.java
1.彈出對話框操做
private void showUpdateDialog() {
AlertDialog.Builder builder = new Builder(this);
//builder.setCancelable(false);//設置對話框是否可以消失,屏蔽返回鍵
//設置標題
builder.setTitle("最新版本:"+mNewCode+".0");
//設置圖標
builder.setIcon(R.drawable.ic_launcher);
//設置描述信息
builder.setMessage(mNewMsg);
//監聽對話框的隱藏操做
builder.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
//隱藏對話框
dialog.dismiss();//隱藏對話框
//跳轉首頁的操做
enterHome();
}
});
//設置兩個按鈕
builder.setPositiveButton("當即更新", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
});
builder.setNegativeButton("之後再說", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
});
//顯示對話框
builder.show();
//builder.create().show();效果同樣
}
2.修改跳轉首頁的操做
private void enterHome() {
Intent intent = new Intent(this,HomeActivity.class);
startActivity(intent);
//跳轉到首頁以後,從首頁返回,不能回到歡迎界面
finish();//移出當前activity頁面
}
下載最新版本apk
protected void downLoadAPK() {
//判斷SD卡是否掛載
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
//鏈接服務器,從服務器去下載最新的版本
HttpUtils httpUtils = new HttpUtils();
//執行下載操做
//問題:1.下載路徑;2.權限;3.判斷SD卡是否掛載;4.生成一個2.0版本的apk
//url:下載路徑
//target : 保存的路徑
//callback : 下載回調
httpUtils.download(mNewUrl, SAVEURL, new RequestCallBack<File>() {
//下載成功調用的
@Override
public void onSuccess(ResponseInfo<File> arg0) {
// TODO Auto-generated method stub
}
//下載失敗調用的
@Override
public void onFailure(HttpException arg0, String arg1) {
// TODO Auto-generated method stub
}
});
}else{
Toast.makeText(getApplicationContext(), "沒有發現可用的SD卡", 0).show();
}
}
顯示下載進度條對話框 (重點)
1.顯示進度條對話框
protected void downLoadAPK() {
//判斷SD卡是否掛載
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
//3.2.顯示進度條的對話框
showProgressDialog();
......
}
2.建立顯示的方法
/**
* 顯示下載的進度條的對話框
* 2016-9-26 下午2:56:44
*/
private void showProgressDialog() {
progressDialog = new ProgressDialog(this);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);//設置對話框中進度的樣式是水平進度條
progressDialog.setCancelable(false);//設置對話框是否能夠隱藏
progressDialog.show();//顯示進度條
}
3.設置下載的進度
protected void downLoadAPK() {
//判斷SD卡是否掛載
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
....
httpUtils.download(mNewUrl, SAVEURL, new RequestCallBack<File>() {
.....
//設置加載進度的操做
//total : 總進度
//current : 當前進度,下載的進度
//isUploading : 是否支持回調上傳
@Override
public void onLoading(long total, long current,
boolean isUploading) {
super.onLoading(total, current, isUploading);
progressDialog.setMax((int) total);//設置總的進度
progressDialog.setProgress((int) current);//設置當前進度(下載進度)
}
});
}else{
Toast.makeText(getApplicationContext(), "沒有發現可用的SD卡", 0).show();
}
}
4.下載成功/下載失敗,隱藏對話框
protected void downLoadAPK() {
//判斷SD卡是否掛載
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
....
httpUtils.download(mNewUrl, SAVEURL, new RequestCallBack<File>() {
//下載成功調用的
@Override
public void onSuccess(ResponseInfo<File> arg0) {
//下載成功,隱藏對話框
progressDialog.dismiss();//隱藏對話框
}
//下載失敗調用的
@Override
public void onFailure(HttpException arg0, String arg1) {
progressDialog.dismiss();//隱藏對話框
}
.....
});
}else{
Toast.makeText(getApplicationContext(), "沒有發現可用的SD卡", 0).show();
}
}
安裝操做
/**
* 4.安裝最新版本的apk
* 2016-9-26 下午3:06:32
*/
protected void installApk() {
//經過隱式意圖,打開系統的安裝界面,安裝
/**
* <intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" /> content://
<data android:scheme="file" />file : 文件形式
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
*/
Intent intent = new Intent();
intent.setAction("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
//相互覆蓋
/*intent.setData(Uri.fromFile(new File(SAVEURL)));
intent.setType("application/vnd.android.package-archive");*/
intent.setDataAndType(Uri.fromFile(new File(SAVEURL)), "application/vnd.android.package-archive");
//startActivity(intent);
//在當前(跳轉到的activity)的activity退出的時候,會調用以前activity的onActivityResult方法
startActivityForResult(intent, 100);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
enterHome();
}
延遲執行更新操做 (重點)
private void initView() {
.....
//更新版本
//1.
//延遲兩秒中在去更新版本
//參數1:handler中執行的操做
//delayMillis : 延遲時間
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
update();
}
}, 2000);//延遲多久給handler發送消息
//2.
//delayMillis:延遲時間
/*new Handler(){
public void handleMessage(android.os.Message msg) {
update();
};
}.sendEmptyMessageDelayed(0, 2000);*///延遲多久給handler發送消息
}
兩種上下文的區別
1.this 表明當前的activity,就是context的子類,只能在當前的activity中使用
2.getApplicationContext 返回值是Context,在整個應用中均可以使用,無論你是哪一個activity,都是能夠用的,在activity中可使用getApplicationContext代替this
特殊狀況
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
dialog不知道要顯示在哪一個activity中
若是是dialog的操做,必定要用this,不能使用getApplicationContext,由於要告訴dialog顯示在哪一個activity中
應用簽名打包apk (重點)
打包簽名apk才能上傳到應用市場
簽名打包
右鍵點擊項目 -> android tools -> export signed Application package -> 選擇當前應用 -> 建立簽名 -> 設置簽名信息 -> 簽名打包apk
注意事項:
更新版本:
1.包名必須一致
2.簽名必須一致
微信:com.weixin.qq
流氓程序:com.weixin.qq
獲得的結果:簽名文件不能丟,簽名密碼不能忘
首頁界面的搭建
<LinearLayout 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:orientation="vertical"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/blue_bkg"
>
<!-- layout_centerVertical : 垂直居中 -->
<ImageView
android:id="@+id/home_iv_logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/heima"
android:layout_centerVertical="true"
android:layout_marginLeft="15dp"
/>
<!-- layout_toRightOf : 在哪一個控件的右邊 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_toRightOf="@+id/home_iv_logo"
android:layout_centerVertical="true"
android:layout_marginLeft="15dp"
>
<!-- textStyle : 文本樣式
normal:默認樣式
bold : 加粗
italic :斜體
-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="傳智手機衛士"
android:textColor="#000000"
android:textSize="20sp"
android:textStyle="bold"
/>
<!-- singleLine : 單行顯示 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="傳智手機衛士,http://www.itcast.cn,真64核殺毒引擎,打開7次,能夠召喚神龍,輔助殺毒..."
android:textColor="#FF0000"
android:textSize="14sp"
android:textStyle="bold"
android:singleLine="true"
/>
</LinearLayout>
<!-- layout_margin : 距離父控件上下左右的距離 -->
<ImageView
android:id="@+id/home_btn_setting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/setting"
android:layout_alignParentRight="true"
android:layout_margin="4dp"
/>
</RelativeLayout>
<!-- numColumns : 設置顯示的列數 -->
<GridView
android:id="@+id/home_gv_gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="2"
></GridView>
</LinearLayout>
跑馬燈效果 (重點:自定義控件)
1.使用控件的屬性進行實現
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="傳智手機衛士,http://www.itcast.cn,真64核殺毒引擎,打開7次,能夠召喚神龍,輔助殺毒..."
android:textColor="#FF0000"
android:textSize="14sp"
android:textStyle="bold"
android:singleLine="true"
android:ellipsize="marquee"
android:focusableInTouchMode="true"
android:focusable="true"
android:marqueeRepeatLimit="marquee_forever"
/>
2.自定義控件,自定義textview,是textview天生帶有本身的焦點
2.1.自定義控件的建立
2.1.1.建立一個類繼承TextView
public class FocusTextView extends TextView {
//代碼中使用的時候調用
public FocusTextView(Context context) {
//super(context);
//FocusTextView focusTextView = new FocusTextView(context);
this(context,null);
}
//在佈局文件中使用的調用
//AttributeSet : 保存有控件的屬性
public FocusTextView(Context context, AttributeSet attrs) {
//super(context, attrs);
this(context,attrs,-1);
}
//是在控件內部被兩個參數的構造函數調用的
//defStyle : 樣式
public FocusTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
//進行的具體的實現
}
}
2.1.2.佈局文件中使用
<cn.itcast.mobliesafe05.FocusTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="傳智手機衛士,http://www.itcast.cn,真64核殺毒引擎,打開7次,能夠召喚神龍,輔助殺毒..."
android:textColor="#FF0000"
android:textSize="14sp"
android:textStyle="bold"
android:singleLine="true"
android:ellipsize="marquee"
android:focusableInTouchMode="true"
android:focusable="true"
android:marqueeRepeatLimit="marquee_forever"
/>
2.2.實現自定義textview的滾動效果
代碼實現效果根據在佈局文件中使用屬性是同樣的效果
//是在控件內部被兩個參數的構造函數調用的
//defStyle : 樣式
public FocusTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
//進行的具體的實現
//使用代碼進行屬性的設置
/**
* android:singleLine="true"
android:ellipsize="marquee"
android:focusableInTouchMode="true"
android:marqueeRepeatLimit="marquee_forever"
*/
setSingleLine();//代碼設置單行顯示
setEllipsize(TruncateAt.MARQUEE);//代碼設置滾動操做
setFocusableInTouchMode(true);//代碼設置觸摸獲取焦點
setMarqueeRepeatLimit(-1);//代碼設置滾動次數
}
//設置textview是否能夠天生帶有焦點,true:有,false:沒有
@Override
public boolean isFocused() {
// TODO Auto-generated method stub
return true;
}
2.3.設置當前強制搶奪焦點的時候,當前自定義textview焦點不被搶奪
//當textview的焦點發生變化的時候調用的
//focused : 發生變化焦點的狀態
//direction : 焦點的移動的方向
//previouslyFocusedRect : 焦點來自哪裏
@Override
protected void onFocusChanged(boolean focused, int direction,
Rect previouslyFocusedRect) {
//當textview失去焦點的時候,強制不能失去焦點
if (focused) {
//當焦點丟失的時候,不一樣讓系統幫助咱們轉移焦點
//當焦點丟失/擁有的時候,讓系統幫助咱們完成焦點的轉移/擁有操做
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
}
屬性動畫實現旋轉操做 (重點)
動畫種類:
1.幀動畫
xml -> 多張圖片
2.補間動畫
平移,旋轉,縮放
3.屬性動畫
3.0以後,能夠實現3D效果
屬性動畫實現旋轉效果
/**
* 實現logo旋轉動畫
* 2016-9-26 下午5:18:20
*/
private void setLogoAnimation() {
//屬性動畫實現
//setRotationX(rotationX) : 以x軸進行旋轉 setRotationY(rotationY) : 以y軸進行旋轉 .setRotation(rotation):以z軸進行旋轉
//mLogo.setRotation(rotation)
//target : 執行動畫的控件
//propertyName : 執行動畫的標示
//values : 動畫所需的值
ObjectAnimator animator = ObjectAnimator.ofFloat(mLogo, "rotationY", 0f,90f,270f,360f);
animator.setDuration(2000);//設置動畫的持續時間
animator.setRepeatCount(ObjectAnimator.INFINITE);//動畫執行的次數,INFINITE:一直執行
//RESTART : 每次都從開始的位置進行旋轉
//REVERSE : 從結束的位置開始旋轉
animator.setRepeatMode(ObjectAnimator.REVERSE);//動畫執行的類型
//執行動畫
animator.start();
}