adb常用命令

adb常用命令 1.adb devices , 获取设备列表及设备状态(adb -s 设备号 其他指令 adb -s devicel install xxx.apk) 2.adb get-state , 获取设备的状态 3.adb install 用于安装(此时需要用 -r 参数来重新安装。) 4.adb uninstall 用于卸载(adb uninstall 后面带的是应用的包名,而不是应用名。adb uninstall -k 表示保留数据) 5.adb shell pm list packages –f (查看系统所有应用的包名) 6.adb push 命令将PC机上的文件推到 DLT-RK3288 机器上; 7.adb pull 命令将DLT-RK3288机器上的文件拉到PC机上; { 例如: adb push d:/new.txt /sdcard/ 将D盘下new.txt文件 推到内部存储器 adb pull /sdcard/new.txt d:\ 将DLT-RK3288 内部存储器根目录下的new.txt 拉到D盘 } adb shell pm list package Package Manager , 可以用获取到一些安装在 Android 设备上得应用信息 -s:列出系统应用 -f:列出应用包名及对应的apk名及存放位置 9.adb shell { 通过adb shell 命令,就可以进入设备或者模拟器的shell环境了,在这个Linux shell中,我们就可以执行各种Linux命令了。 如果只想执行一条shell命令,就可以采用:adb shell [shell_command],在实际使用中,经常与grep或findstr一起使用,起到过滤作用,查看自己需要的关键信息。 常见命令: 如 ls, cd, rm, mkdir, touch, pwd, cp, mv, ifconfig, netstat, ping, ps, top等,进入adb shell即可执行,与linux相似 } 10.adb logcat { 一.在cmd窗口查看手机的Log日志 `有时候我们在手机程序上的日志要在其他地方调试,然后要看里面的Log日志。在cmd窗口中输入如下命令: //格式1:打印默认日志数据 ...

2020年8月13日 · 4 分钟 · 天边的星星

Android6.0运行时权限,拒绝了权限还返回获取成功

如题:禁用、询问的权限,居然还返回权限获取成功 推荐一个很好的项目:AndPermission 不用回来感谢了喂! 这个问题在项目中,一直存在, 主要是第三方厂商各种改,返回的状态不正常; 主要解决思路: 在第三方成功获取权限时, 再用系统原生的api去判断一下,是否真正获取了权限: /** 系统层的权限判断 @param context 上下文 @param permissions 申请的权限 Manifest.permission.READ_CONTACTS @return 是否有权限 :其中有一个获取不了就是失败了 */ public static boolean hasPermission(@NonNull Context context, @NonNull List permissions) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return true; for (String permission : permissions) { String op = AppOpsManagerCompat.permissionToOp(permission); if (TextUtils.isEmpty(op)) continue; int result = AppOpsManagerCompat.noteProxyOp(context, op, context.getPackageName()); if (result == AppOpsManagerCompat.MODE_IGNORED) return false; result = ContextCompat.checkSelfPermission(context, permission); if (result != PackageManager.PERMISSION_GRANTED) return false; } return true; } ...

2019年1月26日 · 3 分钟 · 天边的星星

Android图片之处理圆形圆角

# 概述 图片格式概述: BMP:高质量绘图 保证原图质量,用于相机等 BMP格式图片是有一个一个的像素点组成,每一个像素都是一个颜色.而每一个像素显示的颜色用的二进制位也不相同,这个像素位称之为位深,位深越大,表示每一个像素点所用的二进制位越多,显示的图像也就越清晰。 png:较高质量绘图 体积小,适用于网络传输 png图片是将bmp图片进行压缩,其压缩格式类似于rar压缩——将相同的byte信息合并表示。png图片可以还原,是无损的压缩方式。 jpg:良好的绘图质量 体积小,便于传输 jpg格式图片也是对bmp图片进行压缩,因为眼睛的精度是有限的,jpg利用这一点将很多颜色相近的用同一颜色标识,而对于一大块相同的颜色,则用一个值表示。jpg格式图片不能被还原。 ## 加载大图 <div class="top-box hide"> <div class="alert-info"> </div> </div> ``` hr && wr>1){ r = wr; } if(hr>wr && hr>1){ r = hr; } //压缩图片 options.inSampleSize = r;//设置压缩比 options.inJustDecodeBounds = false;//设置加载图片内容 Bitmap bm = BitmapFactory.decodeFile(path,options); iv.setImageBitmap(bm); " data-snippet-id=“ext.f5fc8efb9581248b791731039403eb80” data-snippet-saved=“false” data-codota-status=“done”>`ImageView iv = (ImageView) findViewById(R.id.iv); <span class=“hljs-comment”>/** 在Android中,每一个应用程序所占用的内存空间大小都会有一个固定的大小限制 假设此处加载的图片是2560*1440像素,图片位深是24的jpg格式图像 虽然此图占用的磁盘空间是1.3M,但图片在加载到内存中时,实际上会先转换成位图图像 那么这张图片加载到内存中的大小就是2560144032(位深24,windows系统中,使用24位字节表示一个颜色值:#000000, 但在Android中,每一个颜色值是用32位字节表示一个颜色值:#00000000),因此,这张图片加载到内存中所需要占用的内存 大小约为:14M,因此,占用内存是极大的.若是直接将图片加载到内存中,容易造成内存溢出 解决方案:按比例压缩图片 *按比例压缩图片首先就是要获取图片的大小 */</span> String path = <span class=“hljs-string”>“mnt/sdcard/1.jpg”</span>; <span class=“hljs-comment”>//用于设置图片渲染器参数</span> BitmapFactory.Options options = <span class=“hljs-keyword”>new</span> Options(); <span class=“hljs-comment”>//设置图片加载属性:不加载图片内容,只获取图片信息</span> options.inJustDecodeBounds = <span class=“hljs-literal”>true</span>; <span class=“hljs-comment”>//加载图片信息</span> BitmapFactory.decodeFile(path,options); <span class=“hljs-comment”>//获取图片宽高</span> <span class=“hljs-keyword”>int</span> picwidth = options.outWidth; <span class=“hljs-keyword”>int</span> picheight = options.outHeight; <span class=“hljs-comment”>//获取屏幕大小</span> <span class=“hljs-comment”>//获取窗口管理器</span> WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); <span class=“hljs-comment”>//获取默认显示设备</span> Display dis =wm.getDefaultDisplay(); <span class=“hljs-comment”>//获取屏幕宽高</span> <span class=“hljs-comment”>//dis.getSize(outSize);此方法适用于新版本Android系统</span> <span class=“hljs-keyword”>int</span> diswidth = dis.getWidth(); <span class=“hljs-keyword”>int</span> disheight = dis.getHeight(); <span class=“hljs-comment”>//计算压缩比</span> <span class=“hljs-keyword”>int</span> wr = picwidth/diswidth; <span class=“hljs-keyword”>int</span> hr = picheight/disheight; <span class=“hljs-keyword”>int</span> r = <span class=“hljs-number”>1</span>; <span class=“hljs-keyword”>if</span>(wr>hr && wr><span class=“hljs-number”>1</span>){ r = wr; } <span class=“hljs-keyword”>if</span>(hr>wr && hr><span class=“hljs-number”>1</span>){ r = hr; } <span class=“hljs-comment”>//压缩图片</span> options.inSampleSize = r;<span class=“hljs-comment”>//设置压缩比</span> options.inJustDecodeBounds = <span class=“hljs-literal”>false</span>;<span class=“hljs-comment”>//设置加载图片内容</span> Bitmap bm = BitmapFactory.decodeFile(path,options); iv.setImageBitmap(bm); ` ...

2018年12月23日 · 6 分钟 · 天边的星星

Retrofit2 使用FastJson作为Converter

Retortfit2 Retrofit是由Square公司出品的针对于Android和Java的类型安全的Http客户端,网络服务基于OkHttp 。 个人觉得更为准确的说法是,Retrofit是OkHttp的一个包装工具类,可以更加方便的调用Restful API。 Retrofit2 默认提供的Converter Gson: com.squareup.retrofit2:converter-gson Jackson: com.squareup.retrofit2:converter-jackson Moshi: com.squareup.retrofit2:converter-moshi Protobuf: com.squareup.retrofit2:converter-protobuf Wire: com.squareup.retrofit2:converter-wire Simple XML: com.squareup.retrofit2:converter-simplexml Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars 下面就来讲解如何扩展Converter 首先创建FastJsonConverterFactory 类,并继承Converter.Factory,重写其中的responseBodyConverter方法与requestBodyConverter方法。 import java.lang.annotation.Annotation; import java.lang.reflect.Type; import okhttp3.RequestBody; import okhttp3.ResponseBody; import retrofit2.Converter; import retrofit2.Retrofit; public class FastJsonConverterFactory extends Converter.Factory{ public static FastJsonConverterFactory create() { return new FastJsonConverterFactory(); } /** 需要重写父类中responseBodyConverter,该方法用来转换服务器返回数据 */ @Override public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { return new FastJsonResponseBodyConverter<>(type); } /** ...

2018年11月24日 · 1 分钟 · 天边的星星

使用BottomNavigationView底部导航栏、添加数量角标提醒

度娘了一圈发现基本上都是TabLayout或者其他的导航栏添加角标,所以写这篇博客记录下来。 先来看下实现的效果图: 代码也是很简单的 BottomNavigationMenuView中的每一个Tab就是一个FrameLayout,所以我们可以在上面随意添加View、这样也就可以实现我们的角标了。 //获取整个的NavigationView BottomNavigationMenuView menuView = (BottomNavigationMenuView) navigationView.getChildAt(0); //这里就是获取所添加的每一个Tab(或者叫menu), View tab = menuView.getChildAt(3); BottomNavigationItemView itemView = (BottomNavigationItemView) tab; //加载我们的角标View,新创建的一个布局 View badge = LayoutInflater.from(this).inflate(R.layout.menu_badge, menuView, false); //添加到Tab上 itemView.addView(badge); menu_badge.xml file: 这里这个布局的大小,其实也就是每一个Tab的大小了。把显示数量的TextView水平居中,这样也就刚好在Tab的中间了(剩下就看你自己想怎么放了….) <?xml version=”1.0″ encoding=”utf-8″?> <LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android” android:layout_width=”match_parent” android:layout_height=”match_parent” android:orientation=”vertical”> <TextView android:id=”@+id/tv_msg_count” android:layout_width=”15dp” android:layout_height=”15dp” android:layout_gravity=”center” android:layout_marginLeft=”@dimen/dp_10″ android:layout_marginTop=”@dimen/dp_3″ android:background=”@drawable/bg_red_circle_10″ android:gravity=”center” android:textColor=”@color/white” android:textSize=”@dimen/sp_12″ android:visibility=”gone” /> 设置角标的数量 TextView count = (TextView) badge.findViewById(R.id.tv_msg_count); count.setText(String.valueOf(1)); //如果没有消息,不需要显示的时候那只需要将它隐藏即可 count.setVisibility(View.GONE); - 在点击事件中完成各个menu的点击事件,实现Fragment的替换,另外三个点击事件内容类似 <div class="top-box hide"> <div class="alert-info"> </div> </div> ``` `<span class=“hljs-comment”>// 去掉menu大于3个后的动画</span> BottomNavigationViewHelper.disableShiftMode(bottomNavigationView); ...

2018年11月11日 · 2 分钟 · 天边的星星

Android studio项目java文件过大导致的问题记录

最近在做一个项目的时候,出现了一个很奇怪的问题,我的java文件前面出现了一个奇怪的蓝色j, 这使得我的代码其他地方无法对它进行调用,所以程序一运行,调用到它的地方就会报错,(因为我的这个代码是用protobuffer协议自动生成的java文件,比较大,大概有5M多)。 后来上网查了一下,发现是IDEA对能关联的文件大小做了限制,主要是为了保护内存,默认值为2500kb或者5000kb,对于一般的java文件也够用了,只是这里我用protocbuf生成的java文件过大,所以要对它这个默认的值进行修改。 找到Android studio 的安装目录下bin 下的idea.properties文件(默认安装路径:C:\Program Files\Android\Android Studio\bin)。 打开这个文件,对里面的idea.max.intellisense.filesizej进行设置,保存( 单位是kb) 然后重启Android studio即可。

2018年10月28日 · 1 分钟 · 天边的星星

解决 Mac OSX 无法识别 Android 设备

在终端输入命令,进入用户目录 ``` $ cd ~ ``` 测试adb,开启终端,输入命令,显示出”Android Debug Bridge version 1.0.39″ 为配置成功 ``` $ adb version ``` 第二步工作是:创建、修改 adb_usb.ini 文件,这里也分为2小步 打开终端,输入命令,查看设备信息 ``` $ system_profiler SPUSBDataType ``` 1.2 得到自己对应的设备信息,其中Vendor ID 中的信息,需要保留,等下使用 ``` SAMSUNG_Android: Product ID: 0x6753 Vendor ID: 0x05e4 (Samsung Electronics Co., Ltd.) Version: 6.00 Serial Number: 7d0076027c174055 Speed: Up to 420 Mb/sec Manufacturer: SAMSUNG Location ID: 0x13200000 / 10 Current Available (mA): 400 Current Required (mA): 86 Extra Operating Current (mA): 0 </div> 2.创建、修改adb_usb.ini文件,可以在终端输入命令,也可以查找文件 2.1 查找adb_usb.ini文件 2.1.1输入命令 <div class="cnblogs_code"> vi ~/.android/adb_usb.ini ...

2018年10月19日 · 1 分钟 · 天边的星星

Android动态化框架App Bundles

摘要: Android App Bundles 在今年的Google I/O大会上,Google向 Android 引入了新 App 动态化框架(即Android App Bundle,缩写为AAB),与Instant App不同,AAB是借助Split Apk完成动态加载,使用AAB动态下发方式,可以大幅度减少应用体积。 ## Android App Bundles 在今年的Google I/O大会上,Google向 Android 引入了新 App 动态化框架(即Android App Bundle,缩写为AAB),与Instant App不同,AAB是借助Split Apk完成动态加载,使用AAB动态下发方式,可以大幅度减少应用体积。现在只须在 Android Studio 中构建一个应用束 (app bundle),就可以将应用所需的全部内容 (适用于所有设备) 都涵盖在内:所有语言、所有设备屏幕大小、所有硬件架构。 下面是Dynamic Delivery示意效果图: 不过要想体验Dynamic Delivery,需要先下载 Android Studio 3.2 学习Android App Bundles可以将它和Split Apks来对比学习。 Split Apks split apks是Android 5.0开始提供多apk构建机制,借助split apks可以将一个apk基于ABI和屏幕密度两个维度拆分城多个apk,这样可以有效减少apk体积。当用户下载应用程序安装包时,只会包含对应平台的so和资源。因为需要google play支持,所以国内就没戏了。针对不同cpu架构问题,国内应用开发商大部分都会将so文件只放在armabi目录下,如此做虽然可以有效减少包体积,但可能带来性能问题。split apks详细的内容可以访问下面的链接:[https://link.zhihu.com/?target=https%3A//developer.android.com/studio/build/configure-apk-splits%3Fauthuser%3D2](https://link.zhihu.com/?target=https%3A//developer.android.com/studio/build/configure-apk-splits%3Fauthuser%3D2) Split Apks的运作原理有点类似于Android的组件化,安装应用程序时,首先安装base apk,然后安装split apks。为了说明splite apks运作原理,来看一下Android 5.0关于splite apks的源码。 打开[ApplicationInfo](http://androidxref.com/5.0.0_r2/xref/frameworks/base/core/java/android/content/pm/ApplicationInfo.java)类中,可以看到如下信息: `/** * Full paths to zero &lt;span class="hljs-keyword">or&lt;/span> more &lt;span class="hljs-keyword">split&lt;/span> APKs that, &lt;span class="hljs-keyword">when&lt;/span> combined with the base * APK &lt;span class="hljs-keyword">defined&lt;/span> in {@link &lt;span class="hljs-comment">#sourceDir}, form a complete application.&lt;/span> *&lt;span class="hljs-regexp">/ public String[] splitSourceDirs; /&lt;/span>** * Full path to the publicly available parts of {@link &lt;span class="hljs-comment">#splitSourceDirs},&lt;/span> * including resources &lt;span class="hljs-keyword">and&lt;/span> manifest. This may be different from * {@link &lt;span class="hljs-comment">#splitSourceDirs} if an application is forward locked.&lt;/span> *&lt;span class="hljs-regexp">/ public String[] splitPublicSourceDirs;&lt;/span>` [LoadeApk](http://androidxref.com/5.0.0_r2/xref/frameworks/base/core/java/android/app/LoadedApk.java)中有PathClassLoader和Resources创建过程。LoadedApk#mClassLoader是PathClassLoader实例引用,接着看PathClassLoader的创建过程。 zipPaths = new ArrayList<>(); final ArrayList<String> libPaths = new ArrayList<>(); ....... zipPaths.add(mAppDir); //将split apk路径追加到zipPaths中 if (mSplitAppDirs != null) { Collections.addAll(zipPaths, mSplitAppDirs); } libPaths.add(mLibDir); ...... final String zip = TextUtils.join(File.pathSeparator, zipPaths); final String lib = TextUtils.join(File.pathSeparator, libPaths); ...... //如果mSplitAppDirs不为空,则zip将包含split apps所有路径。 mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, lib, mBaseClassLoader); StrictMode.setThreadPolicy(oldPolicy); } else { if (mBaseClassLoader == null) { mClassLoader = ClassLoader.getSystemClassLoader(); } else { mClassLoader = mBaseClassLoader; } } return mClassLoader; } }" data-snippet-id="ext.b0abcb7003a3d76aeb1ae260fba2afe7" data-snippet-saved="false" data-codota-status="done">`&lt;span class="hljs-function">&lt;span class="hljs-keyword">public&lt;/span> ClassLoader &lt;span class="hljs-title">getClassLoader&lt;/span>&lt;span class="hljs-params">()&lt;/span> &lt;/span>{ &lt;span class="hljs-keyword">synchronized&lt;/span> (&lt;span class="hljs-keyword">this&lt;/span>) { &lt;span class="hljs-keyword">if&lt;/span> (mClassLoader != &lt;span class="hljs-keyword">null&lt;/span>) { &lt;span class="hljs-keyword">return&lt;/span> mClassLoader; } &lt;span class="hljs-keyword">if&lt;/span> (mIncludeCode && !mPackageName.equals(&lt;span class="hljs-string">"android"&lt;/span>)) { ...... &lt;span class="hljs-keyword">final&lt;/span> ArrayList&lt;String&gt; zipPaths = &lt;span class="hljs-keyword">new&lt;/span> ArrayList&lt;&gt;(); &lt;span class="hljs-keyword">final&lt;/span> ArrayList&lt;String&gt; libPaths = &lt;span class="hljs-keyword">new&lt;/span> ArrayList&lt;&gt;(); ....... zipPaths.add(mAppDir); &lt;span class="hljs-comment">//将split apk路径追加到zipPaths中&lt;/span> &lt;span class="hljs-keyword">if&lt;/span> (mSplitAppDirs != &lt;span class="hljs-keyword">null&lt;/span>) { Collections.addAll(zipPaths, mSplitAppDirs); } libPaths.add(mLibDir); ...... &lt;span class="hljs-keyword">final&lt;/span> String zip = TextUtils.join(File.pathSeparator, zipPaths); &lt;span class="hljs-keyword">final&lt;/span> String lib = TextUtils.join(File.pathSeparator, libPaths); ...... &lt;span class="hljs-comment">//如果mSplitAppDirs不为空,则zip将包含split apps所有路径。&lt;/span> mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, lib, mBaseClassLoader); StrictMode.setThreadPolicy(oldPolicy); } &lt;span class="hljs-keyword">else&lt;/span> { &lt;span class="hljs-keyword">if&lt;/span> (mBaseClassLoader == &lt;span class="hljs-keyword">null&lt;/span>) { mClassLoader = ClassLoader.getSystemClassLoader(); } &lt;span class="hljs-keyword">else&lt;/span> { mClassLoader = mBaseClassLoader; } } &lt;span class="hljs-keyword">return&lt;/span> mClassLoader; } }` 在创建PathClassLoader时,dex文件路径包含base app和split apps路径,LoadedApk#mResources是Resources实例引用,Resources的源码如下: `&lt;span class="hljs-function">&lt;span class="hljs-keyword">public&lt;/span> Resources &lt;span class="hljs-title">getResources&lt;/span>(&lt;span class="hljs-params">ActivityThread mainThread&lt;/span>) &lt;/span>{ &lt;span class="hljs-keyword">if&lt;/span> (mResources == &lt;span class="hljs-literal">null&lt;/span>) { mResources = mainThread.getTopLevelResources(mResDir, mSplitResDirs, mOverlayDirs, mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, &lt;span class="hljs-literal">null&lt;/span>, &lt;span class="hljs-keyword">this&lt;/span>); } &lt;span class="hljs-keyword">return&lt;/span> mResources; }` 可以发现:split apks资源路径(LoadedApk#mSplitResDirs)也会被增加至Resources中。 Android App Bundles 下面再来看Android App Bundles,Android App Bundle 支持模块化,通过Dynamic Delivery with split APKs,将一个apk拆分成多个apk,按需加载(包括加载C/C++ libraries),这样开发者可以随时按需交付功能,而不是仅限在安装过程中。 Android App Bundle 通常会包括以下几个文件: - Base Apk:首次安装的apk,公共代码和资源,所以其他的模块都基于Base Apk; - Configuration APKs:native libraries 和适配当前手机屏幕分辨率的资源; - Dynamic feature APKs:不需要在首次安装就加载的模块。 ![这里写图片描述](https://img-blog.csdn.net/20180516221843565) AAB并不是一个插件化框架,它利用的是Android Framework提供的split apks技术来完成的,而所有安装split apk工作均是通过IPC交由google play完成。 具体使用时,在Android Studio新增一项module——Dynamic Feature Module。 在创建dynamic_feature时,有两个选项是默认勾选的,当然我们也可以更改其状态。 ...

2018年10月16日 · 4 分钟 · 天边的星星

Glide填坑指南

一、前言:再优秀的开源库都有坑要填 手上的项目使用的图片加载框架是:Universal-Image-Loader+业务需要定制化的一些代码。Universal-Image-Loader 这个框架是一个非常经典好用的框架,唯一的问题是是作者很久之前就不再更新了。所以综合考虑下,确定使用Glide+封装代替当前的图片加载框架。 二、困惑: 在没有真正使用 Glide 之前,我所看到的文章基本都是赞美这个库的功能强大,加载流畅。然而,当我用上了以后,才发现并不完美。遇到了不少的坑,需要自己填。 2.1 Glide 配合 OKHttp 使用的坑: 需要在Gradle中引入: compile “com.github.bumptech.glide:glide:3.7.0” compile “com.github.bumptech.glide:okhttp3-integration:1.4.0@aar” 这里就有一个坑,如果你用到自定义的 GlideModule,这里的可能会失效,被com.github.bumptech.glide:okhttp3-integration:1.4.0@aar默认的替换 解决方法是升级版本号: compile “com.github.bumptech.glide:okhttp3-integration:1.4.0@aar” -》 compile “com.github.bumptech.glide:okhttp3-integration:1.5.0” 注意,没有@arr 2.2 OKHttpClient 超时设置导致图片无法加载坑: 因为Glide本身只负责图片加载,网络请求图片数据由网络框架决定。网络请求一般会有超时的问题,坑的是OKHttp默认的超时时间太短了,如果不修改,网络状态比较差 就很容易请求超时,图片自然就加载不出来。我设置的参数是60,60,30这个可以自己根据实际情况确定。 `//这个是源码里面的,默认超时时间,都是10s,10000ms connectTimeout = 10_000; readTimeout = 10_000; writeTimeout = 10_000; //手动设置超时时间 OkHttpClient client=new OkHttpClient.Builder() .connectTimeout(HTTP_CONNECT_TIMEOUT, TimeUnit.SECONDS) .readTimeout(HTTP_READ_TIMEOUT, TimeUnit.SECONDS) .writeTimeout(HTTP_WRITE_TIMEOUT, TimeUnit.SECONDS) .build;` 2.3 Glide 查看 log 的坑: 如果你使用 Glide 经常出现图片加载不出来或者加载有问题,你需要查看 Glide 本身的 log,不过这个必须通过 adb 命令开启,详情百度,需要注意如果是请求图片问题,关注请求的 log,图片加载||转换的问题,关注图片加载||转换的log。 ...

2018年9月14日 · 1 分钟 · 天边的星星

Android hdpi ldpi mdpi xhdpi xxhdpi适配详解

1、了解几个概念 (1)分辨率。分辨率就是手机屏幕的像素点数,一般描述成屏幕的“宽×高”,安卓手机屏幕常见的分辨率有480×800、720×1280、1080×1920等。720×1280表示此屏幕在宽度方向有720个像素,在高度方向有1280个像素。 (2)屏幕大小。屏幕大小是手机对角线的物理尺寸,以英寸(inch)为单位。比如某某手机为“5寸大屏手机”,就是指对角线的尺寸,5寸×2.54厘米/寸=12.7厘米。 (3)密度(dpi,dots per inch;或PPI,pixels per inch)。从英文顾名思义,就是每英寸的像素点数,数值越高当然显示越细腻。假如我们知道一部手机的分辨率是1080×1920,屏幕大小是5英寸,你 能否算出此屏幕的密度呢?哈哈,中学的勾股定理派上用场啦!通过宽1080和高1920,根据勾股定理,我们得出对角线的像素数大约是2203,那么用 2203除以5就是此屏幕的密度了,计算结果是440。440dpi的屏幕已经相当细腻了。 2、实际密度与系统密度 尚未发现他处使用“实际密度”和“系统密度”这两个词汇,暂时由我如此定义吧。 “实际密度”就是我们自己算出来的密度,这个密度代表了屏幕真实的细腻程度,如上述例子中的440dpi就是实际密度,说明这块屏幕每寸有440个 像素。5英寸1080×1920的屏幕密度是440,而相同分辨率的4.5英寸屏幕密度是490。如此看来,屏幕密度将会出现很多数值,呈现严重的碎片 化。而密度又是安卓屏幕将界面进行缩放显示的依据,那么安卓是如何适配这么多屏幕的呢? 其实,每部安卓手机屏幕都有一个初始的固定密度,这些数值是120、160、240、320、480,我们权且称为“系统密度”。大家发现规律没 有?相隔数值之间是2倍的关系。一般情况下,240×320的屏幕是低密度120dpi,即ldpi;320×480的屏幕是中密度160dpi,即 mdpi;480×800的屏幕是高密度240dpi,即hdpi;720×1280的屏幕是超高密度320dpi,即xhdpi;1080×1920的 屏幕是超超高密度480dpi,即xxhdpi。 安卓对界面元素进行缩放的比例依据正是系统密度,而不是实际密度。 3、一个重要的单位dp dp也可写为dip,即density-independent pixel。你可以想象dp更类似一个物理尺寸,比如一张宽和高均为100dp的图片在320×480和480×800的手机上“看起来”一样大。而实际 上,它们的像素值并不一样。dp正是这样一个尺寸,不管这个屏幕的密度是多少,屏幕上相同dp大小的元素看起来始终差不多大。 另外,文字尺寸使用sp,即scale-independentpixel的缩写,这样,当你在系统设置里调节字号大小时,应用中的文字也会随之变大变小。 4、dp与px的转换 在安卓中,系统密度为160dpi的中密度手机屏幕为基准屏幕,即320×480的手机屏幕。在这个屏幕中,1dp=1px。 100dp在320×480(mdpi,160dpi)中是100px。那么100dp在480×800(hdpi,240dpi)的手机上是多少 px呢?我们知道100dp在两个手机上看起来差不多大,根据160与240的比例关系,我们可以知道,在480×800中,100dp实际覆盖了 150px。因此,如果你为mdpi手机提供了一张100px的图片,这张图片在hdpi手机上就会拉伸至150px,但是他们都是100dp。 中密度和高密度的缩放比例似乎可以不通过160dpi和240dpi计算,而通过320px和480px也可以算出。但是按照宽度计算缩放比例不适 用于超高密度xhdpi和超超高密度xxhdpi了。即720×1280中1dp是多少px呢?如果用720/320,你会得出1dp=2.25px,实 际这样算出来是不对的。dp与px的换算要以系统密度为准,720×1280的系统密度为320,320×480的系统密度为 160,320/160=2,那么在720×1280中,1dp=2px。同理,在1080×1920中,1dp=3px。 大家可以记住下面这个比例,dp与px的换算就十分easy啦! ldpi:mdpi:hdpi:xhdpi:xxhdpi=3:4:6:8:12,我们发现,相隔数字之间还是2倍的关系。计算的时候,以mdpi 为基准。比如在720×1280(xhdpi)中,1dp等于多少px呢?mdpi是4,xhdpi是8,2倍的关系,即1dp=2px。反着计算更重 要,比如你用PhotoShop在720×1280的画布中制作了界面效果图,两个元素的间距是20px,那要标注多少dp呢?2倍的关系,那就是 10dp! 当安卓系统字号设为“普通”时,sp与px的尺寸换算和dp与px是一样的。比如某个文字大小在720×1280的PS画布中是24px,那么告诉工程师,这个文字大小是12sp。 5、建议在xdhpi中作图 安卓手机有这么多屏幕,我到底依据哪种屏幕作图呢?没有必要为不同密度的手机都提供一套素材,大部分情况下,一套就够了。 现在手机比较高的分辨率是1080×1920,你可以选择这个尺寸作图,但是图片素材将会增大应用安装包的大小。并且尺寸越大的图片占用的内存也就 越高。如果你不是设计ROM,而是做一款应用,我建议大家用PS在720×1280的画布中作图。这个尺寸兼顾了美观性、经济性和计算的简单。美观性是 指,以这个尺寸做出来的应用,在720×1280中显示完美,在1080×1920中看起来也比较清晰;经济性是指,这个分辨率下导出的图片尺寸适中,内 存消耗不会过高,并且图片文件大小适中,安装包也不会过大;计算的简单,就是1dp=2px啊,多好计算啊! 做出来的图片,记着让界面工程师放进drawable-xhdpi的资源文件夹中。 6、屏幕的宽高差异 在720×1280中作图,要考虑向下兼容不同的屏幕。通过计算我们可以知道,320×480和480×800的屏幕宽度都是320dp,而 720×1280和1080×1920的屏幕宽度都是360dp。它们之间有40dp的差距,这40dp在设计中影响还是很大的。如下图蝴蝶图片距离屏幕 的左右边距在320dp宽的屏幕和360dp宽的屏幕中就不一样。 不仅宽度上有差异,高度上的差异更加明显。对于天气等工具类应用,由于界面一般是独占式的,更要考虑屏幕之间的比例差异 如果想消除这些比例差异,可以通过添加布局文件来实现。一般情况下,布局文件放在layout文件夹中,如果要单独对360dp的屏幕进行调整,你 可以单做做一个布局文件放在layout-w360dp中;如果你想对某个特殊的分辨率进行调整,那么你可以将布局文件放在标有分辨率的文件夹中,如 layout-854×480。 7、几个资源的文件夹 在720×1280中做了图片,要让开发人员放到drawable-xhdpi的资源文件夹中,这样才可以显示正确。个人认为仅提供一套素材就可以 了,可以测试一下应用在低端手机上运行是否流畅,如果比较卡顿,可以根据需要提供部分mdpi的图片素材,因为xhdpi中的图片运行在mdpi的手机上 会比较占内存。 以应用图标为例,xhdpi中的图标大小是96px,如果要单独给mdpi提供图标,那么这个图标大小是48px,放到drawable-mdpi 的资源文件夹中。各个资源文件夹中的图片尺寸同样符合ldpi:mdpi:hdpi:xhdpi:xxhdpi=3:4:6:8:12的规律。 如果你把一个高2px的分割线素材做成了9.png图片,你想让细线在不同密度中都是2px,而不被安卓根据密度进行缩放,怎么办?你可以把这个分 割线素材放到drawable-nodpi中,这个资源文件夹中的图片,将按照实际像素大小进行显示,而不会被安卓根据密度进行缩放。即在mdpi中细线 是2px(2dp),在xhdpi中细线是2px(1dp)。 ...

2018年8月22日 · 2 分钟 · 天边的星星