Android—开发过程中的相关注意事项
查看測試機顯示的內容所對應的Activity
先在環境變量Path中添加sdk所在的路徑。
adb?shell?dumpsys?activity?包名?|?findstr?ACTIVITY
App打包apk安裝后重復啟動根界面的問題
設我們應用啟動頁面會有一個SplashActivity啟動界面,經過3s跳轉到主界面MainActivity。
當我們點擊apk文件安裝app,安裝完成界面點擊打開按鈕,點擊Home鍵,進入系統桌面,此時app退到后臺,再點擊桌面上啟動圖標時。
在bug情況下啟動app時,SplashActivity(app的根Activity)再次創建并疊加到Task任務棧上了。
解決方法:
在app的SplashActivity(app的根Activity)的onCreate方法中通過isTaskRoot()方法來判斷是否是任務棧中的根Activity,如果是就不做任何處理,如果不是則直接finish掉;
PackageManager類
說明: 獲得已安裝的應用程序信息 ??梢酝ㄟ^getPackageManager()方法獲得。 常用方法: public abstract PackageManager getPackageManager() 功能:獲得一個PackageManger對象 public abstract Drawable getApplicationIcon(String packageName) 參數: packageName 包名 功能:返回給定包名的圖標,否則返回nullpublic abstract ApplicationInfo getApplicationInfo(String packageName, int flags) 參數:packagename 包名flags 該ApplicationInfo是此flags標記,通??梢灾苯淤x予常數0即可 功能:返回該ApplicationInfo對象public abstract List<ApplicationInfo> getInstalledApplications(int flags) 參數:flag為一般為GET_UNINSTALLED_PACKAGES,那么此時會返回所有ApplicationInfo。我們可以對ApplicationInfo的flags過濾,得到我們需要的。 功能:返回給定條件的所有PackageInfopublic abstract List<PackageInfo> getInstalledPackages(int flags) 參數如上 功能:返回給定條件的所有PackageInfopublic abstract ResolveInfo resolveActivity(Intent intent, int flags) 參數: intent 查尋條件,Activity所配置的action和categoryflags: MATCH_DEFAULT_ONLY :Category必須帶有CATEGORY_DEFAULT的Activity,才匹配GET_INTENT_FILTERS :匹配Intent條件即可GET_RESOLVED_FILTER :匹配Intent條件即可 功能 :返回給定條件的ResolveInfo對象(本質上是Activity)public abstract List<ResolveInfo> queryIntentActivities(Intent intent, int flags) 參數同上 功能 :返回給定條件的所有ResolveInfo對象(本質上是Activity),集合對象public abstract ResolveInfo resolveService(Intent intent, int flags) 參數同上 功能 :返回給定條件的ResolveInfo對象(本質上是Service)public abstract List<ResolveInfo> queryIntentServices(Intent intent, int flags) 參數同上 功能 :返回給定條件的所有ResolveInfo對象(本質上是Service),集合對象利用應用程序打開目標類型文件
播放視頻
Intent intent = new Intent(Intent.ACTION_VIEW);Uri uri = Uri.parse("file:///sdcard/media.mp4");intent.setDataAndType(uri, "video/*");startActivity(intent);預防App調用第三方應用程序出現Crash處理方式
開發中我們經常會用到第三方應用程序的Activity和Service,但是你無法保證用戶設備上安裝了特定的某個應用軟件,或者設備上有能夠處理你的Intent請求的程序。
所以我們一般在調用前確定下是否可以將三方啟動的界面解析為一個Activity,并判斷它能否啟動該intent
public void viewUrl(String url, String mimeType) {Intent intent = new Intent(Intent.ACTION_VIEW);intent.setDataAndType(Uri.parse(url), mimeType);if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {startActivity(intent);}else {// 找不到指定的Activity} }廣播安全
對于只用于應用內的廣播,優先使用LocalBroadcastManager 來進行注冊和發送,LocalBroadcastManager 安全性更好,同時擁有更高的運行效率。
對于使用Context#sendBroadcast()等方法發送全局廣播的代碼進行提示。如果該廣播僅用于應用內,則可以使用LocalBroadcastManager 來避免廣播泄漏以及廣播被攔截等安全問題,同時相對全局廣播本地廣播的更高效。
registerReceiver()和unregisterReceiver()要成對出現,onResume內注冊廣播則應該在onPause注銷,onResume和onPause是成對的,如果在onDestory會出現多次注冊一次注銷的情況。
OnPause
當前Activity 的onPause 方法執行結束后才會創建(onCreate)或恢復(onRestart)別的Activity,所以在onPause 方法中不適合做耗時較長的工作,這會影響到頁面之間的跳轉效率。
Toast
使用 Toast 時,建議定義一個全局的 Toast 對象,這樣可以避免連續顯示 Toast 時不能取消上一次 Toast 消息的情況(如果你有連續彈出 Toast 的情況,避免使用 Toast.makeText)。
ViewHolder
使用 Adapter 的時候,如果你使用了 ViewHolder 做緩存,在 getView() 的方法中無論這項 convertView 的每個子控件是否需要設置屬性(比如某個 TextView 設置的文本可能為 null,某個按鈕的背景色為透明,某控件的顏色為透明等),都需要為其顯式設置屬性(TextView 的文本為空也需要設置 setText(“”),背景透明也需要設置),否則在滑動的過程中,因為 adapter item 復用的原因,會出現內容的顯示錯亂。
@Override public View getView(int position, View convertView, ViewGroup parent) {ViewHolder myViews;if (convertView == null) {myViews = new ViewHolder();convertView = mInflater.inflate(R.layout.list_item, null);myViews.mUsername = (TextView) convertView.findViewById(R.id.username);convertView.setTag(myViews);} else {myViews = (ViewHolder) convertView.getTag();}Info p = infoList.get(position);String dn = p.getDisplayName;myViews.mUsername.setText(StringUtils.isEmpty(dn) ? "" : dn);return convertView; }static class ViewHolder {private TextView mUsername; }?Dialog
在 Activity 中顯示對話框或者彈出浮層時,盡量使用 DialogFragment,而非 Dialog/AlertDialog,這樣便于隨 Activity 生命周期管理對話框/彈出浮層的生命周期。
public void showPromptDialog(String text) {DialogFragment promptDialog = new DialogFragment() {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);View view = inflater.inflate(R.layout.fragment_prompt, container);return view;}};promptDialog.show(getFragmentManager(), text); }SQLite
多線程操作寫入數據庫時,需要使用事務,以避免出現同步問題。
public void insertUserPhoto(SQLiteDatabase db, String userId, String content) {ContentValues cv = new ContentValues();cv.put("userId", userId);cv.put("content", content);db.beginTransaction();try {db.insert(TUserPhoto, null, cv); // 其他操作db.setTransactionSuccessful();} catch (Exception e) {// TODO} finally {db.endTransaction();} }執行 SQL 語句時,應使用 SQLiteDatabase#insert()、update()、delete(),不要使用 SQLiteDatabase#execSQL(),以避免 SQL 注入風險。?
public int updateUserPhoto(SQLiteDatabase db, String userId, String content) {ContentValues cv = new ContentValues();cv.put("content", content);String[] args = {String.valueOf(userId)};return db.update(TUserPhoto, cv, "userId=?", args); }如果 ContentProvider 管理的數據存儲在 SQL 數據庫中,應該避免將不受信任的外部數據直接拼接在原始 SQL 語句中,可使用一個用于將 ?作為可替換參數的選擇子句以及一個單獨的選擇參數數組,會避免 SQL 注入。
String mSelectionClause = "var = ?"; String[] selectionArgs = {""}; selectionArgs[0] = mUserInput;Bitmap
加載大圖片或者一次性加載多張圖片,應該在異步線程中進行。圖片的加載,涉及到 IO 操作,以及 CPU 密集操作,很可能引起卡頓。
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {...// 在后臺進行圖片解碼@Overrideprotected Bitmap doInBackground(Integer... params) {final Bitmap bitmap = BitmapFactory.decodeFile("some path");return bitmap;}... }在 ListView,ViewPager,RecyclerView,GridView 等組件中使用圖片時,應做好圖片的緩存,避免始終持有圖片導致內存泄漏,也避免重復創建圖片,引起性能問題。建議使用?Fresco、Glide等圖片庫。
png 圖片使用 tinypng 或者類似工具壓縮處理,減少包體積。
Animation
在 Activity.onPause() 或 Activity.onStop() 回調中,關閉當前 activity 正在執行的動畫。
public class MyActivity extends Activity {ImageView mImageView;Animation mAnimation;Button mBtn;/*** 首次創建 activity 時調用*/@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);mImageView = (ImageView) findViewById(R.id.ImageView01);mAnimation = AnimationUtils.loadAnimation(this, R.anim.anim);mBtn = (Button) findViewById(R.id.Button01);mBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mImageView.startAnimation(mAnimation);}});}public void onPause() {//頁面退出,及時清理動畫資源mImageView.clearAnimation();} }在動畫或者其他異步任務結束時,應該考慮回調時刻的環境是否還支持業務處理。例如 Activity 的 onStop() 函數已經執行,且在該函數中制動釋放了資源,此時回調中如果不做判斷就會空指針崩潰。
package com.niles.ndkdemo;public class MyActivity extends Activity {private ImageView mImageView;private Animation mAnimation;/*** 首次創建 activity 時調用*/@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);mImageView = (ImageView) findViewById(R.id.ImageView01);mAnimation = AnimationUtils.loadAnimation(this, R.anim.anim);mAnimation.setAnimationListener(new AnimationListener() {@Overridepublic void onAnimationEnd(Animation arg0) {//判斷一下資源是否被釋放了if (mImageView != null) {mImageView.clearAnimation();}}});mImageView.startAnimation(mAnimation);} }大圖片資源不要直接打包到 apk,可以參考通過文件倉庫遠程下載,減小包體積。
PendingIntent
使用 PendingIntent 時,禁止使用空 Intent,同時禁止使用隱式 Intent。
asyncTask 的execute和executeOnExecutor 方法
一個AsyncTask對象只能執行一次。
execute()方法,必須在UI線程調用,子線程可以只能在串行運行。
executeOnExecuter()方法子線程并行運行。
Activity中添加Fragment不能立刻獲取到Fragment的上下文。
?
總結
以上是生活随笔為你收集整理的Android—开发过程中的相关注意事项的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 遵循五大设计理念 打造出色设计师
- 下一篇: C语言return关键字