"xml里面定义了一个如下的view,怎么编译都不过,看报错是xml的问题,但是看起来没什么问题啊 这个问题坑过好几次一直没长记性,敲黑板View的首字母要大写 还是上面的例子,这是要画一条水平的虚线,drawable的定义如下 在定义好之后在IDE的预览模式下是OK的但是跑到真机上以后发现 ...."

安卓开发日常

  1. xml里面定义了一个如下的view,怎么编译都不过,看报错是xml的问题,但是看起来没什么问题啊
    <view
     android:layout_width="match_parent"
     android:layout_height="2dp"
     android:background="@drawable/network_line" />
    
    这个问题坑过好几次一直没长记性,敲黑板View的首字母要大写
  2. 还是上面的例子,这是要画一条水平的虚线,drawable的定义如下
    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="line">
     <stroke
         android:width="1dp"
         android:color="#555555"
         android:dashGap="5dp"
         android:dashWidth="5dp" />
    </shape>
    
    在定义好之后在IDE的预览模式下是OK的但是跑到真机上以后发现我的虚线变成实线了...解决办法如下:
    <View
     android:layout_width="match_parent"
     android:layout_height="2dp"
     android:background="@drawable/network_line"
     android:layerType="software" />
    
    加上android:layerType="software"就好了,和绘图相关
  3. GridView使用setSelection无效的问题

    在使用GridView的时候发现使用setSelection方法并没有效果,可以通过view.post(Runnable)的方法使其产生效果,另外从其他的view进入GridView的时候,如果反复select的是同一个position,也会导致没有效果的情况,这个时候可以在Gridview失去焦点的时候将其setSelcetion的参数置为-1。

  4. 安卓TextView高度和textSize大小不一致问题

    在设计安卓界面的时候我发现一个TextView在布局上占用的高度和属性textSize的大小不一样,要比textSize要来的大(比如textSize="12dp",实际的高度大概有14-16dp),仔细看的话会发现文字的上方和下发留有空白。

    这个问题我纠结了很久。。。因为这严重影响布局的效果啊。不过这么基础的问题网上竟然找不到资料。。。

    在安卓文档中发现一个TextView属性:android:includeFontPadding为上标和下标留出足够的空间,以取代字体上下标.默认为true.

    原来是TextView默认留下了上下的padding,是为了显示上标和下标。于是设置:android:includeFontPadding="false",问题解决

  5. 安卓GridLayout设置item间距无效的问题

    安卓4.0以后增加了网格布局,比起之前的tablelayout,这个会更高效一些,关于具体的API之类的网上已经很多了,这里只对开发过程中遇到的一些问题作说明:设置item间距方式。

    1、刚开始的实验,为item设置margin,没有作用

    2、接着查看其实现发现问题:Gridlayout内部的组件不能直接设置LinearLayout.LayoutParams, 否则除了控件大小,其他一概不收,Margin自然也就不生效了;于是改正,问题解决

     LinearLayout.LayoutParams ll = new LinearLayout.LayoutParams(381, 206);
     GridLayout.LayoutParams gl = new GridLayout.LayoutParams(ll);
     gl.rightMargin = 37;
     gl.bottomMargin = 37;
     textView.setLayoutParams(gl);
    
  6. 读取U盘apk文件信息,拔掉U盘导致进程被杀

电视管家迭代到2.1版本以后增加了直接读取外部设备的APK文件进行管理的功能,功能模块很快就做完了,但是一直遗留了一个大BUG,拔掉外部设备以后进程会被系统杀掉,根据Log分析问题的原因

12 16:37:26.686 D/Vold    (  126): Volume sda1 state changing 4 (Mounted) -> 5 (Unmounting)  
02-12 16:37:26.686 D/MountService(  476): sendStorageIntent Intent { act=android.intent.action.MEDIA_EJECT dat=file:///storage/external_storage/sda1 (has extras) } to UserHandle{-1}  
02-12 16:37:27.686 D/Vold    (  126): Volume::unmountVol partitions=0x80000000 type=3  
02-12 16:37:27.686 W/Vold    (  126): Failed to unmount /storage/external_storage/sda1 (Device or resource busy, retries 2, action 1)  
02-12 16:37:27.836 E/ProcessKiller(  126): Process com.xx.xxx.xxxxx (771) has open file /storage/external_storage/sda1/antutu-benchmark-v560.apk  
02-12 16:37:27.836 W/ProcessKiller(  126): Sending SIGHUP to process 771  
02-12 16:37:27.956 I/ActivityManager(  476): Process com.xx.xxx.xxxxx (pid 771) has died.

当U盘拔掉之后,apk文件依旧被占用,从而系统发出了sighup,kill信号,导致当前进程被杀掉,也就是说我们读取apk信息时,资源未能及时释放。
结合以下命令,也可以看出确实是电视管家的进程持有了对apk文件的引用,进一步断定是APK文件信息获取的代码出了问题

  ls -al /proc/12247/fd | grep .apk

具体代码如下

public static ApkInfo getBasicApkInfo(Context context, String apkPath) {
        PackageManager pm = context.getPackageManager();
        PackageInfo info = pm.getPackageArchiveInfo(apkPath,
                PackageManager.GET_ACTIVITIES);
        ApkInfo apkInfo = null;
        if (info != null) {
            apkInfo = new ApkInfo();
            ApplicationInfo appInfo = info.applicationInfo;
            appInfo.sourceDir = apkPath;
            appInfo.publicSourceDir = apkPath;
            apkInfo.apkName = appInfo.loadLabel(pm).toString();
            apkInfo.pkgName = info.packageName;
            apkInfo.apkVersionCode = info.versionCode;
            apkInfo.apkVersion = info.versionName==null?"0":info.versionName;
            apkInfo.apkStatus = getApkStatus(context, apkInfo.pkgName, apkInfo.apkVersionCode);
            apkInfo.apkPath = apkPath;
            apkInfo.apkIcon = appInfo.loadIcon(pm);
        }
        return apkInfo;
    }

通过排除法最终定位导致问题的代码是:

apkInfo.apkName = appInfo.loadLabel(pm).toString();
apkInfo.apkIcon = appInfo.loadIcon(pm);

最终解决方案如下:

public static ApkInfo getBasicApkInfo(Context context, String apkPath) {
        PackageManager pm = context.getPackageManager();
        PackageInfo info = pm.getPackageArchiveInfo(apkPath,
                PackageManager.GET_ACTIVITIES);
        ApkInfo apkInfo = null;
        if (info != null) {
            apkInfo = new ApkInfo();
            ApplicationInfo appInfo = info.applicationInfo;
            appInfo.sourceDir = apkPath;
            appInfo.publicSourceDir = apkPath;
//            apkInfo.apkName = appInfo.loadLabel(pm).toString();
            apkInfo.pkgName = info.packageName;
            apkInfo.apkVersionCode = info.versionCode;
            apkInfo.apkVersion = info.versionName==null?"0":info.versionName;
            apkInfo.apkStatus = getApkStatus(context, apkInfo.pkgName, apkInfo.apkVersionCode);
            apkInfo.apkPath = apkPath;
//            apkInfo.apkIcon = appInfo.loadIcon(pm);

            AssetManager assetManager = new AssetManager();
            assetManager.addAssetPath(apkPath);
            Resources resources = new Resources(assetManager, context.getResources().getDisplayMetrics(), context.getResources().getConfiguration());
            try {
                apkInfo.apkIcon = resources.getDrawable(appInfo.icon);
                apkInfo.apkName = resources.getString(appInfo.labelRes);
            } catch (Exception e) {
                Print.d(e);
            } finally {
                assetManager.close();
            }
        }
        return apkInfo;
    }

首先对比一下我获取appName跟appIcon,注释的是我之前会出错的写法,然后再看看我现在获取的方式,首先先看出错的写法,我们用到了PackageManager(pm)跟PackageInfo(pakinfo),而现在的获取方式只是通过PackageInfo,我们进源码可以看到PackageInfo只是一个javaBean实现了Parcelable接口,也就是说PackageInfo只是用来放置apk里面的信息数据的,并没有进行实际的文件操作,我的理解是,读取apk文件信息的操作应该可能是放在PackageManager里面进行的,当我们用PackageManager来获取图标或者应用名时,PackageManager因为被我们引用了从而无法回收释放资源,而我们只用到PackageInfo,PackageManager也就能成功释放掉了,也就不会再占用U盘文件了。

0     1     0     0     0    
0 回帖