zl程序教程

您现在的位置是:首页 >  APP

当前栏目

Android小提示五

2023-02-26 10:17:39 时间

@[TOC]

【68.让ProgressDialog在setCancelable(false)时按返回键可dismiss】

主要是为 ProgressDialog 添加 KeyListener 来对返回键予以处理

(福利推荐:阿里云、腾讯云、华为云服务器最新限时优惠活动,云服务器1核2G仅88元/年、2核4G仅698元/3年,点击这里立即抢购>>>

private ProgressDialog progressDialog = null;  /**  * show loading progress dialog  */ public void showDialog() {     if (null == progressDialog) {         progressDialog = ProgressDialog.show(BaseActivity.this, "", "正在加载,请稍候...");         progressDialog.setCancelable(false);     } else {         progressDialog.show();     }     progressDialog.setOnKeyListener(onKeyListener); }  /**  * add a keylistener for progress dialog  */ private OnKeyListener onKeyListener = new OnKeyListener() {     @Override     public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {         if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {             dismissDialog();         }         return false;     } };  /**  * dismiss dialog  */ public void dismissDialog() {     if (isFinishing()) {         return;     }     if (null != progressDialog && progressDialog.isShowing()) {         progressDialog.dismiss();     } }  /**  * cancel progress dialog if nesseary  */ @Override public void onBackPressed() {     if (progressDialog != null && progressDialog.isShowing()) {         dismissDialog();     } else {         super.onBackPressed();     } }

【dialog监听back】

dialog.setCanceledOnTouchOutside(false);   //外部不行,back可以 dialog.setOnCancelListener(dialog->{     //监听back按钮的 })

【69.传递数据 Intent,LiveDataBus,EventBus】

  • 1.bundle内部实现是ArrayMap,在小数据存储的时候,效率比Hashmap高,而一般需要使用bundle的场景数据都比较小。
  • 2.bundle使用ParceLable序列化对象,而Hashmap是java的类,使用的是Serializable,效率上bundle高。

[https://blog.csdn.net/H291850336/article/details/50515705]()
在跨多个Activity进行传递数据时最好不要用Intent,容易造成内存泄漏。

  • 3.String类型效率比Serializable,Parcelable低。

枚举Enum序列化

private MyBean(Parcel in) {     mField = in.readInt();//普通整型     mMyEnum = MyEnum.values()[in.readInt()];//枚举类型,此枚举类不需要实现Parcelable }  @Override public void writeToParcel(Parcel dest, int flags) {     dest.writeInt(mField);//普通整型     dest.writeInt(mMyEnum.ordinal());//枚举类型 }
通信方案 优点 缺点
handler 系统原生,能实现线程间通信 高耦合 不利于维护 容易导致内存泄漏和空指针
broadcast 简单 性能差 传播数据有限 打乱代码的执行逻辑
interface 速度快,容易理解 实现复杂,不利于维护
rxBus 效率高,无内存泄漏 基于rxjava,学习成本高且依赖包太大,rxjava2.2M
EventBus 使用简单 混淆问题 无法感知组件生命周期 实现复杂
LiveDataBus 实现极其简单,代码量少
官方提供稳定的依赖代码
感知组件生命周期
不会造成内存泄漏

LiveDataBus:核心部分

Lifecycle
Lifecycle是Android官方推出的架构之一,它具有生命周期感知功能,不但能够监听Activity和Fragment的生命周期,还能回调相应方法,同时能够实时的获取当前Activity和Fragment的状态。
LiveData
LiveData是一个数据持有类,持有数据并且这个数据能够被观察者所监听到,而且他是和Lifecycle绑定的,具有生命周期感知,解决内存泄露和引用问题。

什么是Hook技术?

Hook即“钩子”,他可以在事件传送中截获并监控事件传输,将自身的代码与系统方法进行融入。这样当方法被调用时,也就可以执行我们自己的代码,这也是面向切面编程的思想(AOP)。
其实就是通过反射获取到“Hook”点,然后在Hook点执行我们要插入的方法或者改变其原本逻辑的参数,然后在接着执行它原本要执行的逻辑。

【70.资源警告No package identifier】

去除 No package identifier when getting name for resource number 0x00000000 错误信息

将所有颜色信息移动到color.xml内避免此错误

Glide位图警告 (未解决):
[https://github.com/bumptech/glide/issues/743]()

W/Bitmap: Called reconfigure on a bitmap that is in use! This may cause graphical corruption!
旧版 glide 4.9.0
crossFade(500) transition(DrawableTransitionOptions.withCrossFade(500))
transform(new GlideCircleTransform(v.getContext())) transform(new GlideCircleTransform())
bitmapTransform(new BlurTransformation(this, 23, 4)) apply(bitmapTransform(new BlurTransformation( 50, 8)))
listener(new RequestListener<String, GlideDrawable>()… listener(new RequestListener()…
  • glide 4.9.0 可以直接配置圆形和圆角图片 transforms(new CircleCrop())
  • 渐变设置和监听设置有更改
  • asBitmap() 需要设置在 load(url)之前
// 官方 Glide implementation 'com.github.bumptech.glide:glide:4.9.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0' // 高斯模糊和圆角等 implementation 'jp.wasabeef:glide-transformations:4.0.1'

GLide参考:[https://cloud.tencent.com/developer/article/1424574]()
[https://www.jianshu.com/p/fd464ce87c79]()
[https://muyangmin.github.io/glide-docs-cn/doc/getting-started.html?userCode=wrvvs1rm]()

替换Glide通讯组件为Okhttp并监控加载进度
[https://blog.csdn.net/huangxiaoguo1/article/details/78595627]()

【72.Handler警告】

  • 非静态Handler导致Activity泄漏
初始: public class ActivityA extends AppCompatActivity{     //泄露,一般置为 static     private Handler handler = new Handler(){         @Override         public void handleMessage(Message msg){             super.handleMessage(msg);         }     }      @Override     public void onCreate(Bundle savedInstanceState){         handler.postDelayed(new Runnable(){             @Override             public void run(){                 try{ Thread.sleep(10000); }                 catch(Exception e){...}             }         },3000);     } }  修改: private MyHandler handler;  protected void setUpData() {     handler = new MyHandler(this);     handler.sendEmptyMessageDelayed(0, 1000); }  @Override protected void onPause() {     super.onPause();     handler.removeMessages(0); }  static class MyHandler extends Handler {     private final WeakReference<Activity> mActivity;      public MyHandler(Activity activity) {         this.mActivity = new WeakReference<>(activity);     }      @Override     public void handleMessage(Message msg) {         super.handleMessage(msg);         Activity activity = mActivity.get();         if (activity != null) {          }     } }

【73.List集合 containsAll 方法】

1. java中的list是有contains方法: 判断列表中是否包含指定元素。如果列表中包含指定元素,则返回true,否则返回false。 list.add("菠萝"); //向列表中添加数据 String o = "苹果"; list.contains(o);   //返回false  2. java中的list是有containsAll方法: 判断B链表是不是A链表的子集,我们可以使用A.containsAll(B)来判断, 当返回值是true的时候就表明B链表是A链表的子集, 当返回值是false时候就表明B链表不是A链表的子集。 ArrayList<String> als = new ArrayList<String>(); als.add("a"); als.add("b"); ArrayList<String> alss = new ArrayList<String>(); alss.add("a"); alss.add("c"); System.out.println(als.containsAll(alss));  实验结果:false  源代码: public boolean containsAll(Collection<?> c) {     Iterator<?> e = c.iterator();     while (e.hasNext())         if (!contains(e.next()))         return false;     return true; }

【74.判断是否为 null】

//其中null代表某个变量 if("0".equals(null)){     //可以判断 } if(null.equals("0")){     //会崩溃 }  Integer null==1,还是 1==null都崩溃

【75.设置字体】

Android系统默认字体支持四种字体,分别为:

  • noraml (普通字体,系统默认使用的字体)
  • sans(非衬线字体)
  • serif (衬线字体)
  • monospace(等宽字体)

关于后三种字体的区别可以看:
[http://kb.cnblogs.com/page/192018/]()

  1. 在xml中修改字体
<!--  使用默认的sans字体--> <TextView     android:id="@+id/sans"     android:text="Hello,World"     android:textSize="20sp"     android:typeface="sans" />  <!--  使用默认的serifs字体--> <TextView     android:id="@+id/serif"     android:text="Hello,World"     android:textSize="20sp"     android:typeface="serif" />  <!--  使用默认的monospace字体--> <TextView     android:id="@+id/monospace"     android:text="Hello,World"     android:textSize="20sp"     android:typeface="monospace" />     
  1. 在java代码中修改字体
//设置serif字体 textView.setTypeface(Typeface.SERIF); //设置sans字体 textView.setTypeface(Typeface.SANS_SERIF); //设置monospace字体 textView.setTypeface(Typeface.MONOSPACE);
  1. 在Android中可以引入其他字体

在assets目录下新建fonts目录,把ttf字体文件放到这

//得到AssetManager AssetManager mgr=getAssets();  //根据路径得到Typeface Typeface tf=Typeface.createFromAsset(mgr, "fonts/pocknum.ttf"); //在实际使用中,字体库可能存在于SD卡上,可以采用createFromFile()来替代createFromAsset。 //String path =Environment.getExternalStorageDirectory().getAbsoluteFile() + File.separator + "xxx.ttf"; //Typeface typeface2 =Typeface.createFromFile(path);  //设置字体 textView.setTypeface(tf);

【76.布局优化】

Android布局优化:include 、merge、ViewStub的详细总结
merge标签必须使用在根布局,并且ViewStub标签中的layout布局不能使用merge标签.

事件拦截:
https://blog.csdn.net/weixin_37228152/article/details/103865151

【77.判断当前APP后台运行】

切换回界面输入密码等

//判断当前APP后台运行 private boolean isAppBg(Context context) {     ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);     //这是把所有进程全部取出了,【不行】     List<ActivityManager.RunningAppProcessInfo> appProcessList = am.getRunningAppProcesses();      if (appProcessList == null) {         return false;     }      for (ActivityManager.RunningAppProcessInfo appProcess :             appProcessList) {         if (appProcess.processName.equals(context.getPackageName())) {             if (appProcess.importance != ActivityManager.RunningAppProcessInfo                     .IMPORTANCE_FOREGROUND) {                 Log.e(context.getPackageName(), "处于后台" + appProcess.processName);                 return true;             } else {                 Log.e(context.getPackageName(), "处于前台" + appProcess.processName);                 return false;             }         }     }      return false; }

利用这个手机 多任务单进程,只会有一个在前台显示

public class BaseApplication extends Application {     private int appCount = 0;      @Override     public void onCreate() {         super.onCreate();         this.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {             @Override             public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {              }              @Override             public void onActivityStarted(@NonNull Activity activity) {                 appCount++;             }              @Override             public void onActivityResumed(@NonNull Activity activity) {              }              @Override             public void onActivityPaused(@NonNull Activity activity) {              }              @Override             public void onActivityStopped(@NonNull Activity activity) {                 appCount--;                 if (appCount == 0) {                     Toast.makeText(getApplicationContext(),"切入后台",Toast.LENGTH_SHORT).show();                 }             }              @Override             public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {              }              @Override             public void onActivityDestroyed(@NonNull Activity activity) {              }         });     } }

【78.Android第一次安装后Home键重启问题】未验证

Android应用第一次安装成功点击“打开”后Home键切出应用后再点击桌面图标返回导致应用重启问题

//isTaskRoot是Activity系统方法 if (!this.isTaskRoot()) {     Intent mainIntent = getIntent();     String action = mainIntent.getAction();     if (mainIntent.hasCategory(Intent.CATEGORY_LAUNCHER) && action.equals(Intent.ACTION_MAIN)) {         finish();         return;     } }      @Override     public void onCreate(Bundle savedInstanceState){         //Android第一次安装打开,home键再点击启动,程序重复启动         if (!isTaskRoot()){             finish();             return;         }     }

【番外:引入第三方包报错】
https://blog.csdn.net/chenlove1/article/details/60958886

【79.一些属性-横竖屏】

a)Aandroid设置横屏和竖屏的方法:

AndroidManifest.xml中:android:screenOrientation "unspecified":默认值 由系统来推断显示方向.判定的策略是和设备相关的,所以不同的设备会有不同的显示方向. "landscape":横屏显示(宽比高要长) "portrait":竖屏显示(高比宽要长) "user":用户当前首选的方向 "behind":和该Activity以下的那个Activity的方向一致(在Activity堆栈中的) "sensor":有物理的感应器来决定。假设用户旋转设备这屏幕会横竖屏切换。 "nosensor":忽略物理感应器。这样就不会随着用户旋转设备而更改了("unspecified"设置除外)。 

方法二:在java代码中设置

设置横屏代码:setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//横屏 设置竖屏代码:setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//竖屏  if(this.getResources().getConfiguration().orientation ==Configuration.ORIENTATION_PORTRAIT){    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); }

b)android:configChanges属性

  一些设备的配置可能会改变,如:横竖屏的切换、键盘的可用性等。这些事件一旦发生,当前活动的Activity会重新启动,其中的过程是:在销毁之前会先调用onSaveInstanceState()方法去保存你应用中的一些数据,然后调用onDestroy()方法,最后调用onCreate()、onStart()、onResume()等方法启动一个新的Activity。

“screenLayout”: 屏幕的显示发生了变化——不同的显示被激活
“screenSize”: 屏幕大小改变了
https://blog.csdn.net/hanyingjie327/article/details/21246545

AlarmManager定时闹钟的用法:
[https://www.cnblogs.com/ProtectedDream/p/6351447.html?userCode=wrvvs1rm]()

【80.if 与 switch】

  • 1.当分支较多时,当时用switch的效率是很高的。因为switch是随机访问的,就是确定了选择值之后直接跳转到那个特定的分支,但是if。。else是遍历所以得可能值,知道找到符合条件的分支。如此看来,switch的效率确实比ifelse要高的多。
  • 2.由汇编代码可知道,switch…case占用较多的代码空间,因为它要生成跳表,特别是当case常量分布范围很大但实际有效值又比较少的情况,switch…case的空间利用率将变得很低。
  • 3.switch…case只能处理case为常量的情况,对非常量的情况是无能为力的。例如 if (a > 1 && a < 100),是无法使用switch…case来处理的。所以,switch只能是在常量选择分支时比ifelse效率高,但是ifelse能应用于更多的场合,ifelse比较灵活。

一般5个选项(包括default)的情况下,switch和if/else if相同。低于5个选项if快,高于5给选项switch快。

在AndroidLibrary中view.getId不能用switch分支:
原因是:Resource IDs cannot be used in a switch statement in Android library modules
在Android library中不能使用switch-case语句访问资源ID,问题的原因是Android library中生成的R.java中的资源ID不是常数
在library中通过if-else-if条件语句来引用资源ID,这样就避免了这个错误。

public void onClick(View src){    int id = src.getId();    if (id == R.id.playbtn){        // ...    } else if (id == R.id.stopbtn){        // ...    } else if (id == R.id.btnmenu){        openOptionsMenu();    } }

【81.通知栏权限关闭 吐司不显示】

小米显示,华为,三星,魅族,乐视等不显示
Toast通知栏权限填坑指南
Android部分手机通知权限关闭无法打出Toast

Toast怎么支持点击事件?[https://github.com/getActivity/XToast]() 使用

// 判断是否为 Android 6.0 及以上系统并且有悬浮窗权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.canDrawOverlays(mToast.getView().getContext())) {     // 解决使用 WindowManager 创建的 Toast 只能显示在当前 Activity 的问题     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {         params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;     }else {         params.type = WindowManager.LayoutParams.TYPE_PHONE;     } }  /**  * 检查通知栏权限有没有开启  */ public static boolean isNotificationEnabled(Context context){     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {         return ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)).areNotificationsEnabled();     } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {         AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);         ApplicationInfo appInfo = context.getApplicationInfo();         String pkg = context.getApplicationContext().getPackageName();         int uid = appInfo.uid;          try {             Class<?> appOpsClass = Class.forName(AppOpsManager.class.getName());             Method checkOpNoThrowMethod = appOpsClass.getMethod("checkOpNoThrow", Integer.TYPE, Integer.TYPE, String.class);             Field opPostNotificationValue = appOpsClass.getDeclaredField("OP_POST_NOTIFICATION");             int value = (Integer) opPostNotificationValue.get(Integer.class);             return (Integer) checkOpNoThrowMethod.invoke(appOps, value, uid, pkg) == 0;         } catch (NoSuchMethodException | NoSuchFieldException | InvocationTargetException | IllegalAccessException | RuntimeException | ClassNotFoundException ignored) {             return true;         }     } else {         return true;     } }

注释的一些小技巧:[https://www.cnblogs.com/wangyun/p/9176356.html?userCode=wrvvs1rm]()

Android小提示五


本站部分内容转载自网络,版权属于原作者所有,如有异议请联系QQ153890879修改或删除,谢谢!
转载请注明原文链接:Android小提示五

你还在原价购买阿里云、腾讯云、华为云、天翼云产品?那就亏大啦!现在申请成为四大品牌云厂商VIP用户,可以3折优惠价购买云服务器等云产品,并且可享四大云服务商产品终身VIP优惠价,还等什么?赶紧点击下面对应链接免费申请VIP客户吧:

1、点击这里立即申请成为腾讯云VIP客户

2、点击这里立即注册成为天翼云VIP客户

3、点击这里立即申请成为华为云VIP客户

4、点击这里立享阿里云产品终身VIP优惠价

喜欢 (0)
[[email protected]]
分享 (0)