Android开发规范

前言
本手册以开发者为中心视角分为Java 语言规范(遵循《Java 开发手册》), Android 资源文件命名与使用,Android 基本组件,UI 与布局,进程、线程与消息通信, 文件与数据库,Bitmap、Drawable 与动画,安全,其他等九大部分,根据约束力强弱, 规约依次分为强制、推荐、参考三大类:

【强制】必须遵守,违反本约定或将会引起严重的后果;

【推荐】尽量遵守,长期遵守有助于系统稳定性和合作效率的提升;

【参考】充分理解,技术意识的引导,是个人学习、团队沟通、项目合作的方向。

一、Java 语言规范
遵循《Java 开发手册》

二、Android 资源文件命名与使用
1.【强制】资源文件需带模块前缀。

2.【强制】layout 文件的命名方式。

Activity 的 layout 以module_activity 开头  
Fragment 的layout 以module_fragment  开头  
Dialog 的 layout 以module_dialog 开头    
include 的layout 以module_include 开头  
ListView 的行 layout 以module_list_item 开头  
RecyclerView 的item layout 以module_recycle_item 开头  
GridView 的行 layout 以module_grid_item 开头

3.【强制】drawable 资源名称以小写单词+下划线的方式命名,根据分辨率不同存放在不同的 drawable 目录下,建议只使用一套,例如 drawable-xhdpi。采用规则:模块名_业务功能描述_控件描述_控件状态限定词。

// 正确示例:
usermodule_login_btn_pressed   
usermodule_tabs_icon_home_normal

4.【强制】anim 资源名称以小写单词+下划线的方式命名,采用以下规则:模块名_逻辑名称_[方向|序号]

// tween 动画资源: 尽可能以通用的动画名称命名  
module_fade_in , module_fade_out , module_push_down_in (动画+方向);
// frame 动画资源:尽可能以模 块+功能命名+序号。  
module_loading_grey_001

5.【强制】color 资源使用#AARRGGBB 格式,写入 module_colors.xml 文件中,命名格式采用以下规则:模块名_逻辑名称_颜色

<color name="module_btn_bg_color">#33b5e5e5</color>

6.【强制】dimen 资源以小写单词+下划线方式命名,写入 module_dimens.xml 文件中, 采用以下规则:模块名_描述信息

<dimen name="module_horizontal_line_height">1dp</dimen>

7.【强制】style 资源采用小写单词+下划线方式命名,写入 module_styles.xml 文件中, 采用以下规则:父 style 名称.当前 style 名称

<style name="ParentTheme.ThisActivityTheme">  
…  
</style>  

8.【强制】xml 文件中, 字符串以小写单词+下划线的方式命名,采用以下规则:模块名_逻辑名称

// 正确示例:
moudule_login_tips
module_homepage_notice_desc

9.【推荐】Id 资源原则上以驼峰法命名,View 组件的资源 id 需要以 View 的缩写作为前缀。常用缩写表如下:

控件 缩写

LinearLayout ll
RelativeLayout rl
ConstraintLayout cl
ListView lv
ScollView sv
TextView tv
Button btn
ImageView iv
CheckBox cb
RadioButton rb
EditText et

10.【推荐】大分辨率图片建议统一放在 xxhdpi 目录下管理,否则将导致占用内存成倍数增加。
正例:
将 144*144 的应用图标 PNG 文件放在 drawable-xxhdpi 目录

反例:
将 144*144 的应用图标 PNG 文件放在 drawable-mhdpi 目录

三、Android 基本组件
1.【强制】Activity 间的数据通信,对于数据量比较大的,避免使用 Intent + Parcelable的方式,可以考虑 EventBus 等替代方案,以免造成 TransactionTooLargeException。
2.【强制】Activity 间通过隐式 Intent 的跳转,在发出 Intent 之前必须通过 resolveActivity检查,避免找不到合适的调用组件,造成 ActivityNotFoundException 的异常。

//正确示例: 
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) {
		try { 
			startActivity(intent);
		} catch (ActivityNotFoundException e) { if (Config.LOGD) {
			Log.d(LOGTAG, "activity not found for " + mimeType + " over " + Uri.parse(url). getScheme(), e);
		}
	}
}

// 错误示例:
Intent intent = new Intent();
intent.setAction("com.great.activity_intent.Intent_Demo1_Result3");

3.【强制】避免在 Service#onStartCommand()/onBind()方法中执行耗时操作,如果确实有需求,应改用 IntentService 或采用其他异步机制完成。

// 正确示例:
public class MainActivity extends Activity { 

	@Override
	public void onCreate(Bundle savedInstanceState) { 
		super.onCreate(savedInstanceState); 
		setContentView(R.layout.main);
	}

	public void startIntentService(View source) {
		Intent intent = new Intent(this, MyIntentService.class); 
		startService(intent);
	}
}

public class MyIntentService extends IntentService { 
	public MyIntentService() {
		super("MyIntentService");
	}

	@Override
	protected void onHandleIntent(Intent intent) { 
		synchronized (this) {
			try {
				......
			} catch (Exception e) {
			}
		}
	}
}

4.【强制】避免在 BroadcastReceiver#onReceive()中执行耗时操作,如果有耗时工作, 应该创建 IntentService 完成,而不应该在 BroadcastReceiver 内创建子线程去做。

// 正确示例:
IntentFilter filter = new IntentFilter(); 
filter.addAction(LOGIN_SUCCESS); 
this.registerReceiver(mBroadcastReceiver, filter); 
mBroadcastReceiver = new BroadcastReceiver() {
	@Override
	public void onReceive(Context context, Intent intent) { 
		Intent userHomeIntent = new Intent(); 
		userHomeIntent.setClass(this, UseHomeActivity.class); 
		this.startActivity(userHomeIntent);
	}
};

// 错误示例:
mBroadcastReceiver = new BroadcastReceiver() { 
	@Override
	public void onReceive(Context context, Intent intent) {
		MyDatabaseHelper myDB = new MyDatabaseHelper(context);
		myDB.initData();
		// have more database operation here
	}
};

5.【强制】避免使用隐式 Intent 广播敏感信息,信息可能被其他注册了对应BroadcastReceiver 的 App 接收。

// 正确示例:
Intent intent = new Intent("my-sensitive-event");
intent.putExtra("event", "this is a test event");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

// 错误示例:
Intent intent = new Intent(); 
v1.setAction("com.sample.action.server_running"); 
v1.putExtra("local_ip", v0.h);
v1.putExtra("port", v0.i);
v1.putExtra("code", v0.g); 
v1.putExtra("connected", v0.s);
v1.putExtra("pwd_predefined", v0.r); 
if (!TextUtils.isEmpty(v0.t)) {
	v1.putExtra("connected_usr", v0.t);
}
context.sendBroadcast(v1);

7.【推荐】不要在 Activity#onDestroy()内执行释放资源的工作,例如一些工作线程的销毁和停止,因为 onDestroy() 执行的时机可能较晚。可根据实际需要,在Activity#onPause()/onStop()中结合 isFinishing()的判断来执行。

8.【推荐】Service 需要以多线程来并发处理多个启动请求,建议使用 IntentService, 可避免各种复杂的设置。

9.【推荐】当前Activity 的onPause 方法执行结束后才会执行下一个Activity 的onCreate 方法,所以在 onPause 方法中不适合做耗时较长的工作,这会影响到页面之间的跳转效率。

10.【强制】Activity 或者 Fragment 中动态注册BroadCastReceiver 时,registerReceiver()和 unregisterReceiver()要成对出现。

// 正确示例:
public class MainActivity extends AppCompatActivity {
	private static MyReceiver myReceiver = new MyReceiver();

	@Override
	protected void onResume() { 
		super.onResume();
		IntentFilter filter = new IntentFilter("com.example.myservice"); 
		registerReceiver(myReceiver, filter);
	}

	@Override
	protected void onPause() {
		super.onPause(); 
		unregisterReceiver(myReceiver);
	}
}

// 错误示例:
public class MainActivity extends AppCompatActivity { 
	private static MyReceiver myReceiver; 

	@Override
	protected void onResume() { 
		super.onResume();
		myReceiver = new MyReceiver();
		IntentFilter filter = new IntentFilter("com.example.myservice"); 
		registerReceiver(myReceiver, filter);
	}

	@Override
	protected void onDestroy() { 
		super.onDestroy(); 
		unregisterReceiver(myReceiver);
	}
}

四、UI 与布局
1.【强制】布局中不得不使用 ViewGroup 多重嵌套时,不要使用 LinearLayout 嵌套, 改用 RelativeLayout,可以有效降低嵌套数。

// 正确示例:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout>
	<RelativeLayout>
		<TextView/>
		<ImageView/>
	</RelativeLayout>
</android.support.constraint.ConstraintLayout>

// 错误示例:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout>
	<LinearLayout>
		<RelativeLayout>
			<TextView/>
			<ImageView/>
		</RelativeLayout>
	</LinearLayout>
</LinearLayout>

2.【推荐】在 Activity 中显示对话框或弹出浮层时,尽量使用 DialogFragment,而非Dialog/AlertDialog,这样便于随Activity 生命周期管理对话框/弹出浮层的生命周期。

// 正确示例:
public void showPromptDialog(String text){
	DialogFragment promptDialog = new DialogFragment() { 
		@Override
		public 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);
}

3.【强制】禁止在设计布局时多次设置子 view 和父 view 中为同样的背景造成页面过度绘制,推荐将不需要显示的布局进行及时隐藏。

4.【推荐】在需要时刻刷新某一区域的组件时,建议通过以下方式避免引发全局 layout刷新:

 1)设置固定的 view 大小的高宽,如倒计时组件等;

 2)调用 view 的 layout 方式修改位置,如弹幕组件等;

 3)通过修改 canvas 位置并且调用 invalidate(int l, int t, int r, int b)等方式限定刷新区域;

 4)通过设置一个是否允许 requestLayout 的变量,然后重写控件的 requestlayout、onSizeChanged 方法, 判断控件的大小没有改变的情况下, 当进入requestLayout 的时候,直接返回而不调用 super 的 requestLayout 方法。

5.【推荐】尽量不要使用 AnimationDrawable,它在初始化的时候就将所有图片加载到内存中,特别占内存,并且还不能释放,释放之后下次进入再次加载时会报错。

6.【强制】不能使用 ScrollView 包裹 ListView/GridView/ExpandableListVIew;因为这样会把 ListView 的所有 Item 都加载到内存中,要消耗巨大的内存和 cpu 去绘制图面。

五、进程、线程与消息通信
1.【强制】不要通过 Intent 在 Android 基础组件之间传递大数据(binder transaction缓存为 1MB),可能导致 OOM。

2.【强制】子线程中不能更新界面,更新界面必须在主线程中进行,网络操作不能在主线程中调用。

3.【 推荐】 禁止在多进程之间用 SharedPreferences 共享数据, 虽然可以(MODE_MULTI_PROCESS),但官方已不推荐。

六、文件与数据库
1.【强制】任何时候不要硬编码文件路径,请使用 Android 文件系统 API 访问。

// 正确示例:
public File getDir(String alName) {
	File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), alName);
	if (!file.mkdirs()) {
		Log.e(LOG_TAG, "Directory not created");
	}
	return file;
}

// 错误示例:
public File getDir(String alName) {
	// 任何时候都不要硬编码文件路径,这不仅存在安全隐患,也让 app 更容易出现适配问题
	File file = new File("/mnt/sdcard/Download/Album", alName); 
	if (!file.mkdirs()) {
		Log.e(LOG_TAG, "Directory not created");
	}
	return file;
}

2.【强制】当使用外部存储时,必须检查外部存储的可用性。

// 读/写检查
public boolean isExternalStorageWritable() {
	String state = Environment.getExternalStorageState(); 
	if (Environment.MEDIA_MOUNTED.equals(state)) {
		return true;
	}
	return false;
}

// 只读检查
public boolean isExternalStorageReadable() {
	String state = Environment.getExternalStorageState(); 
	if (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
	 return true;
	}	
	return false;
}

3.【推荐】SharedPreference 中只能存储简单数据类型(int、boolean、String 等),复杂数据类型建议使用文件、数据库等其他方式存储。

4.【 推荐】 SharedPreference 提交数据时, 尽量使用 Editor#apply() ,而非Editor#commit()。一般来讲,仅当需要确定提交结果,并据此有后续操作时,才使用 Editor#commit()。

5.【强制】数据库 Cursor 必须确保使用完后关闭,以免内存泄漏。

6.【强制】多线程操作写入数据库时,需要使用事务,以免出现同步问题。

7.【强制】执行 SQL 语句时,应使用 SQLiteDatabase#insert()、update()、delete(), 不要使用 SQLiteDatabase#execSQL(),以免 SQL 注入风险。

七、Bitmap、Drawable 与动画
1.【强制】加载大图片或者一次性加载多张图片,应该在异步线程中进行。图片的加载,涉及到 IO 操作,以及 CPU 密集操作,很可能引起卡顿。

// 正确示例:
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
	// 在后台进行图片解码
	@Override
	protected Bitmap doInBackground(Integer... params) {
		final Bitmap bitmap = BitmapFactory.decodeFile("some path"); return bitmap;
	}
}

// 错误示例:
Button btnLoadImage = (Button) findViewById(R.id.btn); 
btnLoadImage.setOnClickListener(new OnClickListener(){
	public void onClick(View v) {
		Bitmap bitmap = BitmapFactory.decodeFile("some path");
	}
});

2.【强制】在 Activity.onPause()或 Activity.onStop()回调中,关闭当前 activity 正在执行的的动画。

八、其他
1.【强制】不要通过Msg 传递大的对象,会导致内存问题。

2.【强制】Log 的 tag 不能是" "。

// 正确示例:
private static String TAG = "LoginActivity";
Log.e(TAG, "Login failed!");

// 错误示例:
Log.e("", "Login failed!");
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android开发规范主要分为以下几个方面:Java语言规范Android资源文件命名与使用、Android基本组件、UI与布局、进程、线程与消息通信、文件与数据库、Bitmap、Drawable与动画、安全等。这些规范根据约束力的强弱分为强制、推荐和参考三大类。 其中,Java语言规范主要遵循《Java开发手册》,涵盖了Java的语法、命名规范和编码风格等方面的约定。Android资源文件命名与使用规范指导开发人员如何命名和使用资源文件,以提高代码的可读性和维护性。Android基本组件规范包括了对Activity、Fragment、Service等组件的使用规范,以及对生命周期和事件处理的要求。UI与布局规范涵盖了界面设计、布局文件的编写和使用等方面的约定。进程、线程与消息通信规范指导开发人员在多线程环境下进行进程间通信和消息传递的正确方法。文件与数据库规范包括了对文件操作和数据库访问的规范和最佳实践。Bitmap、Drawable与动画规范涵盖了对图片资源的处理和动画效果的实现。安全规范指导开发人员如何处理Android安全机制的升级和防止安全漏洞的发生。 总结来说,遵循Android开发规范能够帮助开发人员编写出高质量、高效率的Android应用程序,提高代码的可读性、可维护性和安全性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Android开发规范](https://blog.csdn.net/zty762357419/article/details/121118281)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [Android中webview和js之间的交互调用](https://download.csdn.net/download/jianxin882000/88222550)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值