Android 开发偷懒技巧之工具代码片

  1. Iconfont在Android中的使用
    阿里提供的Iconfont-国内功能很强大且图标内容很丰富的矢量图标库,提供矢量图标下载、在线存储、格式转换等功能。
    如何使用:

    • 从iconfont平台选择要使用到的图标
    • 下载代码,把iconfont.ttf文件导入到项目中的assets中的iconfont文件夹中
    • 用TextView代替ImageView,找到图标相对应的 HTML 实体字符码给textView设置
    • textview设置大小跟颜色,图标的大小颜色也会改变
    • 为Textview设置指定的ttf文字
    <TextView
        android:id="@+id/icon_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="&#xe66e"
        android:textColor="@color/red"
        android:textSize="50dp"/>
    
    //为TextView设置指定ttf文字
    Typeface iconfont = Typeface.createFromAsset(getAssets(), "iconfont/iconfont.ttf");
    TextView textview = (TextView)findViewById(R.id.icon_text);
    textview.setTypeface(iconfont);
    

    上述方法可以使用iconfont了,但是每次都给TextView设置指定setTypeface是不是也很繁琐,而且一直不断的在读取iconfont.ttf文字,也很浪费内存,所以就想到封装一个工具类。代码如下:

    public class FontHelper {
        public static final String DEF_FONT = "iconfont/iconfont.ttf";
    
        public static final void injectFont(View rootView) {
            injectFont(rootView, Typeface.createFromAsset(rootView.getContext().getAssets(),
                DEF_FONT));
        }
    
        private static void injectFont(View rootView, Typeface typeface) {
            if (rootView instanceof ViewGroup) {
                ViewGroup viewGroup = (ViewGroup) rootView;
                int childViewCount = viewGroup.getChildCount();
                for (int i = 0; i < childViewCount; i++) {
                    injectFont(viewGroup.getChildAt(i), typeface);
                }
            } else if (rootView instanceof TextView) {
                ((TextView) rootView).setTypeface(typeface);
            }
        }
    }
    

    这样我们每次调用FontHelper.injectFont(textview)就可以了,你可能会说这还不是我想要的,我连这行代码都不想多写,那好,接着往下看:我们可以自定义一个TextView然后初始化时setTypeface即刻,代码如下:

    public class TextViewIcon extends AppCompatTextView {
        public TextViewIcon(Context context) {
            super(context);
            init(context);
        }
        public TextViewIcon(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }
        public TextViewIcon(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context);
        }
        private void init(Context context) {
            setTypeface(Typeface.createFromAsset(context.getAssets(),"iconfont/iconfont.ttf"));
        }
    }
    

    现在我们在布局文件中写如下代码即可:

    <com.xxx.xxx.TextViewIcon 
        android:id="@+id/icon_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="&#xe66e"
        android:textColor="@color/red"
        android:textSize="50dp"/>
    

    可是我也想实现像普通textview动态改变文字一样动态改变iconfont的效果怎么办呢?也就是说在代码里动态的调整图标的大小颜色或改变图片,iconfont改变大小颜色这很简单直接调用TextView的setTextSize和setTextColor就可以了,动态设置图片是不是setText呢?
    textview.setText("");
    你会发现这并不会如你所愿显示对应的图片效果,因为这里涉及到unicode 字符的问题。所以将"&#x" 替换成 "\u",用 unicode 字符来表示,即代码如下:
    textview.settext("\ue66e");

  2. Scrollview 自动滚动到顶部或者底部

    • 设置默认滚动到顶部
      scrollView.post(new Runnable() {
      @Override
      public void run() {
      // TODO Auto-generated method stub
          scrollView.fullScroll(ScrollView.FOCUS_UP);
       }
      });
      
    • 设置默认滚动到底部
       scrollView.post(new Runnable() {
       @Override
       public void run() {
       // TODO Auto-generated method stub
             scrollView.fullScroll(ScrollView.FOCUS_DOWN);
       }
      });
      
  3. 判断App的运行状态

     /**
      * 返回app运行状态
      * 1:程序在前台运行
      * 2:程序在后台运行
      * 3:程序未启动
      * 注意:需要配置权限<uses-permission android:name="android.permission.GET_TASKS" />
      */
     public static int getAppSatus(Context context, String pageName) {
    
         ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
         List<ActivityManager.RunningTaskInfo> list = am.getRunningTasks(20);
    
         //判断程序是否在栈顶
         if (list.get(0).topActivity.getPackageName().equals(pageName)) {
             return 1;
         } else {
             //判断程序是否在栈里
             for (ActivityManager.RunningTaskInfo info : list) {
                 if (info.topActivity.getPackageName().equals(pageName)) {
                     return 2;
                 }
             }
             return 3;//栈里找不到,返回3
         }
     }
    
  4. 根据图片宽度自适应图片控件的高度

      /*将ImageView 根据宽度自适应高度(此处假设宽度>高度)*/
     public static void adaptiveHeightByWidth(ImageView view, int width){
         ViewGroup.LayoutParams lp = view.getLayoutParams();
         lp.width = width;
         lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
         view.setLayoutParams(lp);
         view.setMaxWidth(width);
         view.setMaxHeight(width);
     }
    
  5. Android 中如何调试webview

    • .在APP中启用 WebView 调试,开启调试后,Chrome DevTools才能对WebView进行远程调试;
      在对应的android页面中添加如下代码:
      WebView.setWebContentsDebuggingEnabled(true);
    • 通过Chrome浏览器访问chrome://inspect/#devices访问已启用调试的 WebView 列表;
    • 调试Webview与远程调试普通页面相同,远程调试普通页面也就是在安卓手机中安装Chrome浏览器,使用USB 连接 PC,然后在 PC 的 Chrome 浏览器中打开 chrome://inspect/#devices 即可。
    • 点击inspect 进入dev_tools 页面可能碰到404 Not Found错误,那是因为你在国内,FQ即可。
  6. Android按Home键避免重启程序
    问题描述:
    在App打开后按Home键后应用退至后台运行,此时点击应用图标再次打开App,发现App重新启动,难道打开程序的页面不应该是在按Home键之前的页面吗?
    解决方案:
    在启动页也就是应用程序刚进入的Activity 即大部分都为闪屏页,在OnCreate方法中是在setContentView之前加入下面的代码还是在setContentView之后加入一下代码都可以。

     if (!this.isTaskRoot()) {
        Intent mainIntent = getIntent();
        String action = mainIntent.getAction();
        if (mainIntent.hasCategory(Intent.CATEGORY_LAUNCHER) 
            && action.equals(Intent.ACTION_MAIN)) {
                finish();
                return;
         }
     }
    
  7. Android中使用Glide获取网络图片的宽高比

    public class ImageUtil {
     /**
      * 根据图片链接获取图片宽高比
      * @param context
      * @param imgUrl
      * @return  高/宽
      */
     public static void getAspectRatioByImgUrl(Context context, String imgUrl, ImageAspectRatioCallBack aspectRatioCallBack){
         if (TextUtils.isEmpty(imgUrl)){
             return;
         }
         //获取图片真正的宽高
         Glide.with(context)
                 .load(imgUrl)
                 .asBitmap()//强制Glide返回一个Bitmap对象
                 .into(new SimpleTarget<Bitmap>() {
                     @Override
                     public void onResourceReady(Bitmap bitmap, GlideAnimation<? super Bitmap> glideAnimation) {
                         int width = bitmap.getWidth();
                         int height = bitmap.getHeight();
                         Log.e(Constant.LOG_TAG, "width " + width);
                         Log.e(Constant.LOG_TAG, "height " + height);
                         if (width > 0 && aspectRatioCallBack != null){
                             aspectRatioCallBack.returnAspectRation((float) height/width);
                         }
                     }
                 });
      }
    
      public interface ImageAspectRatioCallBack {
         void returnAspectRation(float aspectRatio);
      }
    }
    
  8. Android中webview嵌套H5页面报错"Uncaught Error: Java exception was raised during method invocation"
    问题描述:
    客户端提供给H5一个方法供其修改原生页面标题的头部显示信息,代码如下:

       @JavascriptInterface
       public void resetTitle(String title2) {
        mTitleTv.setText(title2);
       }
    

    结果H5在调用该方法时就会报此错误,原因是因为@JavascriptInterface 注解的方法里面不能更新ui.
    解决方案:

       @JavascriptInterface
       public void resetTitle(String title2) {
        BrowserActivity.this.runOnUiThread(new Runnable() {
               @Override
                   public void run() {
                    mTitleTv.setText(title2);
                   }
               });
       }
    
  9. 查看android手机中安装apk的包名等信息

  • 方法一:
    进入cmd窗口,输入adb shell,进入手机,在输入ls /data/data,即能显示出手机中安装apk的包名。(需要root权限)
  • 方法二:
    查看手机中非系统的apk包名信息,adb shell pm list package -3,这个命令很实用。这和命令后面不加-3表示查看手机中使用的apk包名。
  • 方法三:
    在代码中获取Android设备中apk的包名等信息。
     /*获取Android手机中安装的应用*/
      public static void getAllAppPackages(Context context) {
          Intent intent = new Intent(Intent.ACTION_MAIN, null);
          intent.addCategory(Intent.CATEGORY_LAUNCHER);
          List<ResolveInfo> apps = context.getPackageManager().queryIntentActivities(intent, 0);
          //for循环遍历ResolveInfo对象获取包名和类名
          for (int i = 0; i < apps.size(); i++) {
              ResolveInfo info = apps.get(i);
              String packageName = info.activityInfo.packageName;
              CharSequence cls = info.activityInfo.name;
              CharSequence name = info.activityInfo.loadLabel(context.getPackageManager());
              Log.e(Constant.LOG_TAG,name+"----"+packageName+"----"+cls);
          }
      }
    
  1. 解决使用HttpURLConnection读取网络文件乱码问题
    public static void getRemoteMockApiData(final String mockdataUrl, final JsonCallBack jsonCallBack){
        final StringBuilder stringBuilder = new StringBuilder();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //构建URL地址
                    URL url = new URL(mockdataUrl);
                    try {
                        HttpURLConnection hcont = (HttpURLConnection) url.openConnection();
                        hcont.setRequestProperty("Content-Type", "application/json");
                        hcont.setDoOutput(true);
                        hcont.setRequestMethod("GET");
                        hcont.setRequestProperty("Accept-Charset", "utf-8");
                        hcont.setRequestProperty("contentType", "utf-8");
    
                        if (hcont.getResponseCode() == 200) {
                            InputStreamReader in = null;
                            in = new InputStreamReader(hcont.getInputStream(),"utf-8");
                            BufferedReader bufferedReader = new BufferedReader(in);
                            String line = null;
                            while ((line = bufferedReader.readLine()) != null) {
                                stringBuilder.append(line);
                            }
                        }
    
                        if (jsonCallBack != null){
                            jsonCallBack.getRemoteMockData(stringBuilder.toString());
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
    
  2. 基于android studio 3.1.4将library生成jar和arr文件
    其实Android Studio编译的时候会自动将library项目生成jar和aar的,分别在build/outputs/aarbuild/intermediates/packaged-classes文件夹下。
  • 在对应的module文件下的build.gradle中添加以下代码:
    task makeJar(type: Copy) {
    //删除存在的
     delete 'build/libs/react-native-bridge.jar'
    //设置拷贝的文件
     from('build/intermediates/packaged-classes/release/')
    //打进jar包后的文件目录
     into('build/libs/')
    //将classes.jar放入build/libs/目录下
     include('classes.jar')
     rename ('classes.jar','react-native-bridge.jar')
    }
    makeJar.dependsOn(build)
    
  • 选中library的Module,点击Build -> Make Module library,此时packaged-classes目录即可生成。
  • 在AS最下方的Terminal中输入命令即可。
    1. MAC电脑:
      ./gradlew makeJar
    2. Windows电脑:
      gradlew makeJar
  • 顺利的话就可以在build/libs文件夹下看到生成的jar文件。

ADB命令:

  • 获取手机CPU型号:
    adb shell getprop ro.product.cpu.abi
  • 获取当前栈顶Activity相关的信息:
    adb shell dumpsys activity top > info.txt

推荐阅读更多精彩内容