1.Android 资源文件命名与使用
2.Android 基本组件
2.1 Activity Intent
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) {
startActivity(intent);
}else {
// 找不到指定的 Activity
}
}
2.2Service 执行耗时操作
避免在 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 {
// add this here
} catch (Exception e) {
}
}
}
}
2.3 使用显示广播
避免使用隐式 Intent 广播敏感信息,信息可能被其他注册了对应
BroadcastReceiver 的 App 接收。
敏感信息被别的监听app 接受:
// 发送sendBroadcast 携带了敏感信息
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);
---------------------------------------------------------------------------------
final class MyReceiver extends BroadcastReceiver {
public final void onReceive(Context context, Intent intent) {
if (intent != null && intent.getAction() != null) {
String s = intent.getAction();
if (s.equals("com.sample.action.server_running") {
String ip = intent.getStringExtra("local_ip");
String pwd = intent.getStringExtra("code");
String port = intent.getIntExtra("port", 8888);
boolean status = intent.getBooleanExtra("connected", false);
}
}
}
}
2.4 intentservice和service区别
推荐使用intentservice,下面是intentservice 的源码
IntentService 是继承于 Service 并处理异步请求的一个类,在 IntentService 内有一个工作线程来处理耗时操作,启动 IntentService 的方式和启动传统 Service 一样,同时,当任务执行完后,IntentService 会自动停止,而不需要我们去手动控制。另外,可以启动 IntentService 多次,而每一个耗时操作会以工作队列的方式在IntentService 的 onHandleIntent 回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。
// IntentService源码中的 onCreate() 方法
@Override
public void onCreate() {
super.onCreate();
// HandlerThread继承自Thread,内部封装了 Looper
//通过实例化andlerThread新建线程并启动
//所以使用IntentService时不需要额外新建线程
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//获得工作线程的 Looper,并维护自己的工作队列
mServiceLooper = thread.getLooper();
//将上述获得Looper与新建的mServiceHandler进行绑定
//新建的Handler是属于工作线程的。
mServiceHandler = new ServiceHandler(mServiceLooper);
}
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
//IntentService的handleMessage方法把接收的消息交给onHandleIntent()处理
//onHandleIntent()是一个抽象方法,使用时需要重写的方法
@Override
public void handleMessage(Message msg) {
// onHandleIntent 方法在工作线程中执行,执行完调用 stopSelf() 结束服务。
onHandleIntent((Intent)msg.obj);
//onHandleIntent 处理完成后 IntentService会调用 stopSelf() 自动停止。
stopSelf(msg.arg1);
}
}
////onHandleIntent()是一个抽象方法,使用时需要重写的方法
@WorkerThread
protected abstract void onHandleIntent(Intent intent);
使用intentservice 进行实际例子:
===============启动service ======================
Intent intent = new Intent(this, MIntentService.class);
intent.putExtra("info", "good good study");
startService(intent);
====================MIntentService ===============
public class MIntentService extends IntentService {
public MIntentService(){
super("MIntentService");
}
public MIntentService(String name) {
super(name);
}
public void onCreate() {
Log.e("MIntentService--", "onCreate");
super.onCreate();
}
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("MIntentService--", "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
protected void onHandleIntent(Intent intent) {
Log.e("MIntentService--", Thread.currentThread().getName() + "--" + intent.getStringExtra("info") ); //这里进入实际操作
for(int i = 0; i < 100; i++){ //耗时操作
Log.i("onHandleIntent--", i + "--" + Thread.currentThread().getName());
}
}
@Override
public void onDestroy() {
Log.e("MIntentService--", "onDestroy");
super.onDestroy();
}
}
===================测试结果============================
10-25 16:54:58.852 27135-27135/com.example.lenovo.myintentservicedemo E/MIntentService--﹕ onCreate
10-25 16:54:58.852 27135-27135/com.example.lenovo.myintentservicedemo E/MIntentService--﹕ onStartCommand
10-25 16:54:58.856 27135-27354/com.example.lenovo.myintentservicedemo E/MIntentService--﹕ IntentService[MIntentService]--good good study
10-25 16:54:58.879 27135-27135/com.example.lenovo.myintentservicedemo E/MIntentService--﹕ onDestroy
service 如何处理耗时操作的呢:
例子:
public class HelloService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
new Thread(new Runnable() {
@Override
public void run() {
//操作语句, 耗时操作
}
}).start();
}
}
**2.5 onPause **
当前 Activity 的 onPause 方法执行结束后才会创建(onCreate)或恢复
(onRestart)别的 Activity,所以在 onPause 方法中不适合做耗时较长的工作,这
会影响到页面之间的跳转效率。
2.5 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);
}
}
2.6基础组件 隐式调用
Android 基础组件如果使用隐式调用,应在 AndroidManifest.xml 中使用
<intent-filter> 或在代码中使用 IntentFilter 增加过滤。
举个例子:
正确的写法:
// 将 intent scheme URL 转换为 intent 对象
Intent intent = Intent.parseUri(uri);
// 禁止没有 BROWSABLE category 的情况下启动 activity
intent.addCategory("android.intent.catjmotgory.BROWSABLE");
intent.setComponent(null);
intent.setSelector(null);
// 使用 intent 启动 activity
context.startActivityIfNeeded(intent, -1);
---------------------------------------------------------------------------------
不建议的写法:
Intent intent = Intent.parseUri(uri.toString().trim().substring(15), 0);
intent.addCategory("android.intent.category.BROWSABLE");
context.startActivity(intent);
说明:intent.setComponent(); //设定包名,对应包的activity
前名一个参数是应用程序的包名,后一个是这个应用程序的主Activity名
Intent intent=new Intent();
intent.setComponent(newComponentName("com", "com.Vortex"));
startActivity(intent);
3.Android UI 与布局
3.1嵌套
布局中不得不使用 ViewGroup 多重嵌套时,不要使用 LinearLayout 嵌套,
改用 RelativeLayout,可以有效降低嵌套数。
View 都需要经过 measure、layout、draw 三个步骤,尽量扁平 。 在设计中使用 Android Studio Monitor里的 Hierarchy Viewer 工具,可视化的查看所有的 view
**3.2 显示dialog **
[非系统dialog ]不能在 Activity 没有完全显示时显示 PopupWindow 和 Dialog
Android Activity 创建时的生命周期,按照 onCreate()->onStart()->onResume() ->onAttachedToWindow()->onWindowFocusChanged() 的顺序,其中在
Activity-onAttachedToWindow() 时,Activity 会与它的 Window 关联,这时 UI 才
会开始绘制,在 Activity-onWindowFocusChanged() 时,UI 才变成可交互状态,
可以提示用户使用。如果在 Window 未关联时就创建对话框,UI 可能显示异常。
推荐的做法是在 Activity-onAttachedToWindow() 之 后 ( 其 实 最 好 是
Activity-onWindowFocusChanged() 之后)才创建对话框。
3.3 AnimationDrawable and ScrollView
AnimationDrawable:尽量不要使用 AnimationDrawable,它在初始化的时候就将所有图片加载到内存中,特别占内存,并且还不能释放,释放之后下次进入再次加载时会报错.
ScrollView :不能使用 ScrollView 包裹 ListView/GridView/ExpandableListVIew;因为这样会把 ListView 的所有 Item 都加载到内存中,要消耗巨大的内存和 cpu 去绘制图面。
不要在Android 的 Application 对象中缓存数据。基础组件之间的数据共享
请使用 Intent 等机制,也可使用 SharedPreferences 等数据持久化机制。
3.4 Adapter
使用 Adapter 的时候,如果你使用了 ViewHolder 做缓存,在 getView()的
方法中无论这项 convertView 的每个子控件是否需要设置属性(比如某个 TextView
设置的文本可能为 null,某个按钮的背景色为透明,某控件的颜色为透明等),都需
要为其显式设置属性(Textview 的文本为空也需要设置 setText(""),背景透明也需要
设置),否则在滑动的过程中,因为 adapter item 复用的原因,会出现内容的显示错
乱。
正确例子:
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;
}
4.进程间通信
- 不要通过 Intent 在 Android 基础组件之间传递大数据(binder transaction
缓存为 1MB),可能导致 OOM。 - 新建线程时,必须通过线程池提供(AsyncTask 或者 ThreadPoolExecutor
或者其他形式自定义的线程池),不允许在应用中自行显式创建线程。
网友评论