美文网首页
Android 规范编程

Android 规范编程

作者: xuefeng_apple | 来源:发表于2021-06-16 19:13 被阅读0次

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
    或者其他形式自定义的线程池),不允许在应用中自行显式创建线程。

相关文章

  • Android 开发规范

    前言 本文参考Google Java编程规范和阿里巴巴Java规范,Android编码规范部分参考Android开...

  • Android 代码命名规范

    前言 根据 Google Java 编程规范 & Google 官方 Android 编码规范,整理一份全面 & ...

  • 【Android 进阶】 代码规范

    前言 这份文档参考了 Google Java 编程风格规范和 Google 官方 Android 编码风格规范。该...

  • Android编程规范

    命名规范 1. 基本原则 (1) 代码风格与android源码保持一致(2) 命名要清晰明了、有明确含义(3) ...

  • Android 编程规范

    架构&分包 -- 原则 包名应让人一目知意:英文命名描述其功能。 分包层次应尽可能的低,减短包名长度。 Model...

  • Android 编程规范

    前言 通过建立代码编写规范,形成Android编码约定,提高程序的可靠性、可读性、可修改性、可维护性、一致性,保证...

  • Android 规范编程

    1.Android 资源文件命名与使用 2.Android 基本组件 2.1 Activity IntentAct...

  • [最新] Android 代码规范大全(Android开发速看)

    编程不规范,亲人两行泪。今天就来分享一下最新的 Android 代码规范大全。原文地址:代码规范大全[https:...

  • Dart Memo for Android Developers

    Dart Memo for Android Developers Dart语言一些语法特点和编程规范. 本文适合:...

  • 聊聊Android编程规范

    (1)每个公司,每个部门,每个团队都喜欢搞一套编程规范,初衷很美好,然而定出来的东西从来都没人看。道理很简单,既然...

网友评论

      本文标题:Android 规范编程

      本文链接:https://www.haomeiwen.com/subject/oxgxyltx.html