編輯:關於android開發
根據功能模塊劃分(Android開發推薦此方法)
- Activity mobilesafe.activty
- 後台服務 mobilesafe.service
- 廣播接受者 mobilesafe.receiver
- 數據庫 mobilesafe.db.dao
- 對象(java bean) mobilesafe.domain/bean
- 自定義控件 mobilesafe.view
- 工具類 mobilesafe.utils
- 業務邏輯 mobilesafe.engine
閃屏頁面(Splash)作用:
- 展示logo,公司品牌
- 項目初始化
- 檢測版本更新
- 校驗程序合法性(比如:判斷是否有網絡,有的話才運行)
AndroidMinifest.xml 四大組件都需要在這裡配置
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.mxn.mobilesafe" 4 android:versionCode="1" //版本號 5 android:versionName="1.0" > //版本名 6 7 <uses-sdk 8 android:minSdkVersion="16" 9 android:targetSdkVersion="21" /> 10 //項目所需的權限 11 <uses-permission android:name="android.permission.INTERNET" /> 12 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 13 <uses-permission android:name="android.permission.READ_PHONE_STATE" /> 14 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> 15 <uses-permission android:name="android.permission.READ_CONTACTS" /> 16 <uses-permission android:name="android.permission.SEND_SMS" /> 17 <uses-permission android:name="android.permission.RECEIVE_SMS" /> 18 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 19 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 20 <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" /> 21 <uses-permission android:name="android.permission.VIBRATE" /> 22 <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /> 23 <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/> 24 <uses-permission android:name="android.permission.GET_PACKAGE_SIZE"/> 25 <uses-permission android:name="android.permission.CLEAR_APP_CACHE"/> 26 27 <application 28 android:allowBackup="true" 29 android:icon="@drawable/ic_launcher" 30 android:label="@string/app_name" 31 android:theme="@style/AppTheme" > //主題
//activity的注冊 32 <activity 33 android:name="com.mxn.mobilesafe.activity.SplashActivity" 34 android:label="@string/app_name" > 35 <intent-filter> //起始的activity 36 <action android:name="android.intent.action.MAIN" /> 38 <category android:name="android.intent.category.LAUNCHER" /> 39 </intent-filter> 40 </activity> 41 <activity android:name="com.mxn.mobilesafe.activity.HomeActivity" /> 42 <activity android:name="com.mxn.mobilesafe.activity.SettingActivity" /> 43 <activity android:name="com.mxn.mobilesafe.activity.LostFindActivity" > 44 </activity> 45 <activity android:name="com.mxn.mobilesafe.activity.Setup1Activity" > 46 </activity> 47 <activity android:name="com.mxn.mobilesafe.activity.Setup2Activity" > 48 </activity> 49 <activity android:name="com.mxn.mobilesafe.activity.Setup3Activity" > 50 </activity> 51 <activity android:name="com.mxn.mobilesafe.activity.Setup4Activity" > 52 </activity> 53 <activity android:name="com.mxn.mobilesafe.activity.ContactActivity" > 54 </activity> 55 <activity android:name="com.mxn.mobilesafe.activity.AtoolsActivity" > 56 </activity> 57 <activity android:name="com.mxn.mobilesafe.activity.AddressActivity" > 58 </activity> 59 <activity android:name="com.mxn.mobilesafe.activity.CallSafeActivity" > 60 </activity> 61 <activity android:name="com.mxn.mobilesafe.activity.AppManagerActivity" > 62 </activity> 63 <activity android:name="com.mxn.mobilesafe.activity.TaskManagerActivity"> 64 </activity> 65 <activity android:name="com.mxn.mobilesafe.activity.TaskManagerSettingActivity"> 66 </activity> 67 <activity android:name="com.mxn.mobilesafe.activity.AntivirusActivity"></activity> 68 <activity android:name="com.mxn.mobilesafe.activity.AppLockActivity"></activity> 69 <activity android:name="com.mxn.mobilesafe.activity.CleanCacheActivity"></activity> 70 //廣播接收者的 注冊 71 <receiver android:name=".receiver.BootCompleteReceiver" > 72 <intent-filter> 73 <action android:name="android.intent.action.BOOT_COMPLETED" /> 74 </intent-filter> 75 </receiver> 76 <receiver android:name=".receiver.SmsReceiver" > 77 <intent-filter android:priority="2147483647" > 78 <action android:name="android.provider.Telephony.SMS_RECEIVED" /> 79 </intent-filter> 80 </receiver> 81 <!-- 82 <receiver android:name=".receiver.OutCallReceiver" >靜態注冊的廣播 83 <intent-filter> 84 <action android:name="android.intent.action.NEW_OUTGOING_CALL" /> 85 </intent-filter> 86 </receiver> 87 --> 88 //服務的注冊 89 <service android:name="com.mxn.mobilesafe.service.LocationService" > 90 </service> 91 <service android:name="com.mxn.mobilesafe.service.AddressService" > 92 </service> 93 <service android:name="com.mxn.mobilesafe.service.KillProcessService"></service> 94 <service android:name="com.mxn.mobilesafe.service.WatchDogService"></service>
95 </application> 96 97 </manifest>
activity_splash.xml
<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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.mxn.mobilesafe.SplashActivity"
android:background="@drawable/launcher_bg"
android:id="@+id/rl_root">
<TextView
android:id="@+id/tv_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="202dp"
android:textSize="22sp"
android:textColor="#000"
android:shadowColor="#f00" //對版本號設置陰影
android:shadowDx="1"
android:shadowDy="1"
android:shadowRadius="1"
android:text="版本號:1.0" />
<ProgressBar
android:id="@+id/progressBar1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/tv_version"
android:layout_centerHorizontal="true"
android:layout_marginTop="54dp" />
<TextView
android:id="@+id/tv_progress"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:textColor="#f00"
android:textSize="16sp"
android:text="下載進度" />
</RelativeLayout>
SplashActivity.java
1 public class SplashActivity extends Activity {
2
3 protected static final int CODE_UPDATE_DIALOG;
4 protected static final int CODE_URL_ERROR;
5 protected static final int CODE_NET_ERROR;
6 protected static final int CODE_JSON_ERROR;
7 protected static final int CODE_ENTER_HOME;
8
9 private TextView tvVersion;
10 private TextView tvProgress;// 下載進度展示
11 // 服務器返回的信息
12 private String mversionName;// 版本名
13 private int mversionCode;// 版本號
14 private String mDesc;// 版本描述
15 private String mdowmloadurl;// 下載地址
16
17 private Handler mHandler = new Handler() {
18 public void handleMessage(android.os.Message msg) {
19 switch (msg.what) {
20 case CODE_UPDATE_DIALOG:
21 showUpdateDialog();//顯示升級對話框
22 break;
23 case CODE_URL_ERROR:
24 Toast.makeText(SplashActivity.this, "url錯誤", Toast.LENGTH_SHORT).show();
25 enterHome();
26 break;
27 case CODE_NET_ERROR:
28 Toast.makeText(SplashActivity.this, "網絡錯誤", Toast.LENGTH_SHORT).show();
29 enterHome();
30 break;
31 case CODE_JSON_ERROR:
32 Toast.makeText(SplashActivity.this, "json數據解析解析錯誤", Toast.LENGTH_SHORT).show();
33 enterHome();
34 break;
35 case CODE_ENTER_HOME:
36 enterHome();
37 break;
38 default:
39 break;
40 }
41 };
42 };
43 private SharedPreferences sp;
44 private RelativeLayout rlRoot;
45
46 @Override
47 protected void onCreate(Bundle savedInstanceState) {
48 super.onCreate(savedInstanceState);
49 setContentView(R.layout.activity_splash);
50
51 tvVersion = (TextView) findViewById(R.id.tv_version);
52 tvProgress = (TextView) findViewById(R.id.tv_progress);// 默認隱藏
53 tvVersion.setText("版本號:" + getVersionCode());//給版本號設置內容,動態獲取的值
54
55 rlRoot = (RelativeLayout) findViewById(R.id.rl_root);
56
57
58 //判斷是否需要自動更新
59 sp = getSharedPreferences("config", MODE_PRIVATE);
60 boolean autoUpdate = sp.getBoolean("auto_update", true);
61
62 copyDB("address.db");//拷貝歸屬地查詢數據庫
63 copyDB("antivirus.db");//拷貝病毒庫
64 //更新病毒庫
65 updateVirus();
66
67 if(autoUpdate){
68 checkVersion();
69 }else{
70 mHandler.sendEmptyMessageDelayed(CODE_ENTER_HOME, 2000);
71 }
72
73 //閃屏頁漸變動畫效果
74 AlphaAnimation anim = new AlphaAnimation(0.3f, 1f);
75 anim.setDuration(2000);
76 rlRoot.startAnimation(anim);
77 }
78
79
80 //更新病毒數據庫
81 private void updateVirus() {
82 //聯網從服務器獲取到最近數據的MD5的特征碼
83 HttpUtils httputils = new HttpUtils();
84 String url = "http://172.28.3.112:8080/virus.json";
85 httputils.send(HttpMethod.GET, url, new RequestCallBack<String>(){
86
87 @Override
88 public void onFailure(HttpException arg0, String arg1) {
89 // TODO Auto-generated method stub
90
91 }
92
93 @Override
94 public void onSuccess(ResponseInfo<String> arg0) {
95 // TODO Auto-generated method stub
96 //System.out.println(arg0.result);
97
98 // JSONObject jsonobject = new JSONObject(arg0.result);
99 // String md5 = jsonobject.getString("md5");
100 // String desc = jsonobject.getString("desc");
101
102 }
103
104
105
106 });
107
108 }
109
110
111
112 // 獲取本地版本號
113 private int getVersionCode() {
114 PackageManager packgeManager = getPackageManager();//拿到包的管理者。。包管理器,獲取手機裡面每個apk的信息(清單文件信息)
115 try {// 獲取包的信息。。 getPackageName()當前應用程序的包名 等於 package="com.mxn.mobilesafe"
116 PackageInfo packageInfo = packgeManager.getPackageInfo(getPackageName(), 0);
117 int versionCode = packageInfo.versionCode;
118 String versionName = packageInfo.versionName;
119 System.out.println("versionname=" + versionName + ";" + "versioncode=" + versionCode);
120 return versionCode;
121 } catch (NameNotFoundException e) {
122 // 沒有找到包名時
123 e.printStackTrace();
124 }
125 return -1;
126
127 }
128
129 // 從服務器獲取版本信息進行校驗
130 private void checkVersion() {
131 final long startTime = System.currentTimeMillis();
132
133 new Thread() {// 網絡訪問在分線程異步加載數據
134 public void run() {
135 Message msg = Message.obtain();
136 HttpURLConnection con = null;
137 try {// 本機地址:localhost 如果用模擬器加載本機的地址:用10.0.0.2來替換
138 URL url = new URL("http://10.0.2.2:8080/update.json");
139 // 打開連接
140 con = (HttpURLConnection) url.openConnection();
141 con.setRequestMethod("GET");//設置請求方法
142 con.setConnectTimeout(5000);// 設置連接超時,5S
143 con.setReadTimeout(5000);// 設置響應超時,鏈接上了,但服務器遲遲沒有響應
144 con.connect();// 鏈接服務器
145
146 int responseCode = con.getResponseCode();//獲取響應碼
147 if (responseCode == 200) {
148 // 獲取返回值
149 InputStream inputStream = con.getInputStream();
150 // 流轉化為字符串
151 String result = StreamUtils.readFormStream(inputStream);//自己定義的StreamUtils工具類
152 System.out.println("網絡結果返回:" + result);
153 //result是一個json字符串,進行解析
154 // 解析json
155 JSONObject jo = new JSONObject(result);
156 mversionName = jo.getString("versionName");//拿到服務器端的版本名
157 mversionCode = jo.getInt("versionCode");//拿到服務器端的版本號
158 mDesc = jo.getString("description");//拿到服務器端的版本描述
159 mdowmloadurl = jo.getString("downloadUrl");//拿到服務器端的下載鏈接
160
161 System.out.println(mDesc);
162 System.out.println(mversionCode);
163 // 服務器的大於 本地的,判斷是否有更新,如果大於 則有更新需要更新,彈出升級對話框
164 if (mversionCode > getVersionCode()) {
165 System.out.println("進行比較,有版本更新");
166 msg.what = CODE_UPDATE_DIALOG;
167 // showUpdateDialog();//這句是在子線程更新界面,android不能在子線程更新界面,要想在子線程更新界面所以用到handler.
168 } else {// 如果沒有版本更新
169 msg.what = CODE_ENTER_HOME;
170 }
171 }
172 } catch (MalformedURLException e) {// url錯誤的異常
173 msg.what = CODE_URL_ERROR;
174 e.printStackTrace();
175 } catch (IOException e) {//網絡錯誤異常
176 // 這個是可以攜帶數據的msg.obj =
177 msg.what = CODE_NET_ERROR;// what只是一個標識,用來區分消息!
178 e.printStackTrace();
179 } catch (JSONException e) {// json解析失敗
180
181 msg.what = CODE_JSON_ERROR;
182 e.printStackTrace();
183 } finally {
184 long endTime = System.currentTimeMillis();
185 long timeUsed = endTime - startTime;// 訪問網絡花費的時間
186 if (timeUsed < 2000) {
187 try {// 強制休眠2s,保證閃屏頁面2S
188 Thread.sleep(2000 - timeUsed);
189 } catch (InterruptedException e) {
190 // TODO Auto-generated catch block
191 e.printStackTrace();
192 }
193 }
194
195 mHandler.sendMessage(msg);// 消息發送出去,在handlemessage裡進行相應的處理
196 if (con != null) {
197 con.disconnect();
198 }
199
200 }
201 }
202
203 }.start();
204
205 }
206
//升級對話框
207 private void showUpdateDialog() {
208 System.out.println("正在升級對話框");
209 // 升級對話框
210 AlertDialog.Builder builder = new AlertDialog.Builder(this);//context對象
211 builder.setTitle("最新版本" + mversionName);
212 builder.setMessage(mDesc);
213 // builder.setCancelable(false);//不讓用戶取消對話框,用戶體驗太差
214 builder.setPositiveButton("立即更新", new OnClickListener() {
215 @Override
216 public void onClick(DialogInterface dialog, int which) {
217 // TODO Auto-generated method stub
218 System.out.println("立即更新");
219 // download方法
220 download();
221 }
222 });
223 builder.setNegativeButton("以後再說", new OnClickListener() {
224 @Override
225 public void onClick(DialogInterface dialog, int which) {
226 enterHome();
227 }
228 });
229 builder.setOnCancelListener(new OnCancelListener() {
230 // 設置取消監聽,用戶點擊返回鍵時觸發
231 @Override
232 public void onCancel(DialogInterface dialog) {
233 enterHome();
234 }
235 });
236 builder.show();
237 }
238
239 protected void download() {// 下載服務器端的apk文件
240 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
241 // 判斷是否有sd卡,sd卡掛載的時候才可以
242 tvProgress.setVisibility(View.VISIBLE);// 顯示進度
243
244 String target = Environment.getExternalStorageDirectory() + "/update.apk";//把文件下載到哪個路徑下,sd卡的根目錄
245 // xutils框架,使用HttpUtils工具下載文件,下載一個jar包
246 HttpUtils utils = new HttpUtils();
247 utils.download(mdowmloadurl, target, new RequestCallBack<File>() {
248 @Override // 文件下載進度
249 public void onLoading(long total, long current, boolean isUploading) {
250 // TODO Auto-generated method stub
251 super.onLoading(total, current, isUploading);
252 System.out.println("下載進度:" + current + "/" + total);
253 tvProgress.setText("下載進度:" + current * 100 / total + "%");
254 }
255
256 @Override
257 public void onSuccess(ResponseInfo<File> arg0) {
258 // TODO Auto-generated method stub
259 Toast.makeText(SplashActivity.this, "下載成功", Toast.LENGTH_SHORT).show();
260 // 下載完成之後,跳到系統的安裝界面。。Intent.ACTION_VIEW 是xml的action 標簽
261 Intent intent = new Intent(Intent.ACTION_VIEW);//系統的安裝界面
262 intent.addCategory(Intent.CATEGORY_DEFAULT);
263 intent.setDataAndType(Uri.fromFile(arg0.result),
264 "application/vnd.android.package-archive");
265 // startActivity(intent);
266 startActivityForResult(intent, 0);// 如果用戶取消安裝,會返回結果,回調方法onActivityResult,下文定義
267 }
268
269 @Override
270 public void onFailure(HttpException arg0, String arg1) {
271 // TODO Auto-generated method stub
272 Toast.makeText(SplashActivity.this, "下載失敗", Toast.LENGTH_SHORT).show();
273 }
274 });
275 } else {
276 Toast.makeText(SplashActivity.this, "沒有SD卡", Toast.LENGTH_SHORT).show();
277 }
278 }
279
280 @Override//用戶取消安裝,回調此方法
281 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
282 // TODO Auto-generated method stub
283 System.out.println("出現安裝界面,用戶點擊取消時。");
284 enterHome();
285 super.onActivityResult(requestCode, resultCode, data);
286 }
287
288 private void enterHome() {// 進入主界面
289 Intent intent = new Intent(this, HomeActivity.class);
290 startActivity(intent);
291 finish();
292 }
293
294
295
296
297 //拷貝數據庫,從assets目錄下拷貝到data/data/com.mxn.mobilesafe/files目錄下
298 private void copyDB(String dbName){
299 //獲取文件路徑
300 File destFile = new File(getFilesDir(),dbName);
301
302 if(destFile.exists()){
303 System.out.println("已存在");
304 }
305
306
307 FileOutputStream out = null;
308 InputStream in = null;
309
310 try {
311 in = getAssets().open(dbName);
312
313 out = new FileOutputStream(destFile);
314 int len = 0;
315 byte[] buffer = new byte[1024];
316
317 while((len = in.read(buffer))!=-1){
318 out.write(buffer,0,len);
319 }
320
321
322 } catch (IOException e) {
323 // TODO Auto-generated catch block
324 e.printStackTrace();
325 }finally{
326 try {
327 in.close();
328 out.close();
329 } catch (IOException e) {
330 // TODO Auto-generated catch block
331 e.printStackTrace();
332 }
333
334 }
335
336 }
337 }
StreamUtils.java
1 /*
2 * 讀取流的工具
3 * 把流對象轉換成字符串對象
4 */
5 public class StreamUtils {
6 //將輸入流讀取成String後返回
7 public static String readFormStream(InputStream in) throws IOException{
8 // 定義字節數組輸出流對象
9 ByteArrayOutputStream out = new ByteArrayOutputStream();
10 // 定義讀取的長度
11 int len = 0 ;
12 // 定義讀取的緩沖區
13 byte[] buffer = new byte[1024];
14 // 按照定義的緩沖區進行循環讀取,直到讀取完畢為止
15 while((len=in.read(buffer))!=-1){
16 // 根據讀取的長度寫入到字節數組輸出流對象中
17 out.write(buffer,0,len);
18 }
19 String result = out.toString();
20 // 關閉流
21 in.close();
22 out.close();
23 return result;
24 // // 把讀取的字節數組輸出流對象轉換成字節數組
25 // byte data[] = out.toByteArray();
26 // // 按照指定的編碼進行轉換成字符串(此編碼要與服務端的編碼一致就不會出現亂碼問題了,android默認的編碼為UTF-8)
27 // return new String(data, "UTF-8");
28
29 }
30
31 }
系統安裝界面的activity的配置:
<activity android:name=".PackageInstallerActivity"
android:configChanges="orientation|keyboardHidden"
android:theme="@style/Theme.Transparent">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
<data android:scheme="file" />
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
</activity>
我們服務器用的是tomcat,裡面放置 新版本的apk和update.json:

將代碼打包為apk文件:

涉及的知識點:
PackageManager 包管理器,獲取手機裡面每個apk的信息(清單文件信息)
版本更新流程:

網絡請求
> * URL
> * HttpUrlConntetion
JSON解析
> * JSONObject 專門用來解析json
> * JSONArray
對話框彈出
> AlertDialog
> AlertDialog.Builder
子線程更新UI
> * Handler + message
> * runOnUiThread(runnable)
頁面之間的跳轉Intent
GitHub 一個開源的網站,下載xUtils框架,將下載的jar包導入工程。
AlertDialog.Builder(this)
子類擁有父類的所有方法, 而且可以有更多自己的方法。父類無法有子類的方法
Activity(token), Context(沒有token)
平時,要獲取context對象的話, 優先選擇Activity, 避免bug出現, 盡量不用getApplicationContext()
activity是context的子類
Andorid中.9.png圖片的使用及制作
Andorid中.9.png圖片的使用及制作 我們有一個TextView,其裡面的內容是可以通過代碼動態改變的,我們想用一張圖片作為TextView的背景,實現類似於手
Android 觸摸及手勢操作GestureDetector
Android 觸摸及手勢操作GestureDetector 現在的智能手機不敢說百分百的都是觸摸屏,也應該是百分之九九以上為觸摸屏了,觸摸屏為我們操作
Android之控件使用,android控件
Android之控件使用,android控件 Android系統為我們提供了大量的控件,例如:開關控件、單選按鈕、多選按鈕、單選菜單等等,那麼這些控件如何使用呢?本篇我
Java 正則表達式詳解,java正則表達式詳解
Java 正則表達式詳解,java正則表達式詳解一、正則表達式基礎知識 我們先從簡單的開始。假設你要搜索一個包含字符“cat”的字符串,搜索用