OCNYang の 博客

Android 开发者,亦涉猎 Flutter

0%

Android初级躲不开的那些坑

这里是作者(OCN.Yang)在Android初级阶段遇到的那些坑坑洼洼,有些还是开发中要知道的小技巧。相信大多数初学者难免也会遇到相同的坑,大家大概看看有者避之,还没遇到的就躲之。大牛和已经进阶的朋友可以绕道(相信你们很忙的)。

1、Ctrl + O快捷键

查看代码的大纲 即类的方法列表。

2、layout_weight

  • android:layout_weight的真实含义是:
    一旦View设置了该属性(假设有效的情况下),那么该 View的宽度等于原有宽度(android:layout_width)加上剩余空间的占比!
  • 如果width设置了match_parent ,那么,加上的是负的长度(相当于减去一部分长度)
  • 如果width设置了warp_content ,那么,剩余空间是“父容器总长度”减去“组件的内容占的长度”,然后再按比重值分。  

3、Background=”@null”

可以给背景设置一个null值,在一定情况下这样做是有必要的。

4、判断String是否为空

TextUtils.isEmpty(String str)

5、Int/int 还是等于整型,太容易出错了。

6、LinearLayout中的orientation & gravity

当LinearLayout布局中设置**orientation=”vertical”**属性:

  • 如果子组件设置**layout_gravity=”center_vertical”**是无效的;
  • 如果LinearLayout中设置**gravity=”center_vertical”**是可以起到作用将子组件垂直居中的。水平布局同理

7、单例模式的Activity

设置为单例模式的Activity,会单独开一个任务栈单独存放这个activity,这个任务栈只会在程序退出后消除。

8、选择手机中的图片并显示在ImageView上

Intent intent = new Intent();  
/* 开启Pictures画面Type设定为image */  
intent.setType("image/*");  
/* 使用Intent.ACTION_GET_CONTENT这个Action */  
intent.setAction(Intent.ACTION_GET_CONTENT);   
/* 取得相片后返回本画面 */  
startActivityForResult(intent, 1);  


@Override  
protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
    if (resultCode == RESULT_OK) {  
        Uri uri = data.getData();  
        ContentResolver cr = this.getContentResolver();  
        try {  
            Bitmap bitmap = BitmapFactory.decodeStream(cr.openInputStream(uri));  
            ImageView imageView = (ImageView) findViewById(R.id.iv01);  
            /* 将Bitmap设定到ImageView */  
            imageView.setImageBitmap(bitmap);  
        } catch (FileNotFoundException e) {  
            Log.e("Exception", e.getMessage(),e);  
        }  
    }  
    super.onActivityResult(requestCode, resultCode, data);  
}

9、notifyDataSetChanged() 刷新Adaper.

10、ListView 的优化

主要方法:

  1. ListView设置固定高度,
  2. convertView判空,
  3. SetTag:convertView.setTag(viewHolder),
  4. 内部类ViewHolder,
  5. 分页加载

11、R文件编译报错 & 找不到ID报错

R文件的编译原理:当资源文件或id命名中其中一个文件的命名不满足规范时,R文件整体就不会再编译。

12、列表里的CheckBox


注意: Spinner:如果item中有能够获得焦点的控件(例如CheckBox),则在item获得点击事件之后会继续传递给能够获得焦点的控件.
想让item在被点击后Spinner收回去,需要在布局(例如LinearLayout)中加上属性后代是否可以获得焦点:

android:descendantFocusability="blocksDescendants"//阻止后代获得焦点  

13、获取xml资源文件中定义的数组

getResources().getStringArray(R.array.city)  

14、安卓默认字体大小:

15、java 字符串split有很多坑

Java代码

System.out.println(":ab:cd:ef::".split(":").length);//末尾分隔符全部忽略    
System.out.println(":ab:cd:ef::".split(":",-1).length);//不忽略任何一个分隔符    
System.out.println(StringUtils.split(":ab:cd:ef::",":").length);//最前面的和末尾的分隔符全部都忽略,apache commons    
System.out.println(StringUtils.splitPreserveAllTokens(":ab:cd:ef::",":").length);//不忽略任何一个分隔符 apache commons     
输出:    
4    
6    
3    
6    

看了下jdk里String类的**public String[] split(String regex,int limit)**方法,感觉平时不太会用这方法,以为在用正则表达式来拆分时候,如果匹配到的字符是最后一个字符时,会拆分出两个空字符串,
例如”o”split(“o”,5) or “o”split(“o”,-2)时候 结果是”” “” 也就是下图中红框里的内容,所以平时一般都用split(String regex) 方法,其实也就等同于split(String regex,0)方法,把结尾的空字符串丢弃!

16、Android Studio 的全局变量和强转的快捷键

  • Findviewbyid(R.id.XXX).cast(强转转换) 强转后点击回车回到行尾
  • .field 全局变量
  • .var 局部变量

17、TextView添加滚动条

18、数组适配器

////xListView上滑刷新,下滑加载更多///swapListView侧滑删除/

19、Viewstub

只能inflatay一次。不然会报错。

20、补间动画的旋转的圆心计算方法

以图片的左上角为坐标(0,0),分别计算出pivotX和pivotY的数值:50%是图片本身大小的一半,50%p是父窗体宽高的一半长度。然后在图片的左上角的基础上加上这两个数组

位移也是同样的计算方式

21、插件

ButterKnife Gosn android.selector.generat

22、margin & padding

android 中的控件的margin 和 padding 都是不会影响控件的设置宽高。(这点和网页设计是不一样的)

23、R文件出错。

当布局或id报找不到的错时,可能就是R文件出错。

  • 一种可能是你导入了命名不规范的资源文件,导致R文件不能自动编译了。
  • 一种可能是你导入了import android.R系统的R文件导致报错

24、ListView的多类型item

自定义ListView中,如果item采用多种类型的布局。那么在getItemType中的下标一定要从0开始。不然会报下标越界异常。

25、java怎么在一个字符串里截取一个正则表达式字段

public static void main(String[] args) {
    String str = "<div><h3 ..>dsijiswer*dfhjgf</h3></div><table><h3>sdsd</h3></table>";
    Pattern p = Pattern.compile("<h3.*?/h3>");
    Matcher m = p.matcher(str);
    while (m.find()) {
        System.out.println(m.group());
    }
}

26、事件机制:分发 消费 电梯机制:向上分发 ,向下消费

27、LinearLayout内部子控件之间的间隔 设置为等同的

在drawer文件夹下创建一个shape的图形文件

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >
    <size android:width="15dp" />
    <solid android:color="@android:color/transparent" />
</shape>  

在linearLayout里设置属性divider为上图形,同时设置showdivider属性

28、TextView 上设置的图片 设置图片大小的方法:

txtZQD = (TextView) findViewById(R.id.txtZQD);  
Drawable[] drawable = txtZQD.getCompoundDrawables();  //获取它前后左右的图片
// 数组下表0~3,依次是:左上右下  
drawable[1].setBounds(100, 0, 200, 200);  
txtZQD.setCompoundDrawables(drawable[0], drawable[1], drawable[2],drawable[3]);  

29、android中内部存储和外部存储的理解和路径获取

30、自定义组合控件

在加载布局的时候要用 View.inflate(context,R.layout.img_share,this);
或者 LayoutInflater.from(context).inflate(R.layout.img_share,this);
不能用 LayoutInflater.from(context).inflate(R.layout.img_share,null);这样加载不上。

31、foreground 前景色生效

32、添加第三方依赖报错

配置错误原因:1、导包有误。2、少导包。3、重复导包。

33、布局里的ListView|GridView抢占焦点

Scrollview里嵌套Gridview,Gridview抢焦点问题(显示布局的时候老是先从Gridview的第一个item显示)

解决方法:在获取inflate view之后,代码给GridView.setFocusable(false)就可以了

这里的listview的item里嵌套了横向滑动的scrollview的gridview,

同样的问题,同样的解决方案:在listview的adapter中在加载完item之后对gridview设置setFocusable(false)。
这里需要注意的是,是在抢焦点的列表的父容器建立之后就对列表设置取消焦点。

例如:
在ListView中嵌套GridView中:

convertView = LayoutInflater.from(mContext).inflate(R.layout.item_listview_home, null);
viewHolder = new ViewHolder(convertView);
viewHolder.mGridIilh.setFocusable(false);  

在fragment布局中存在列表抢占焦点:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_cheapsale, null);
    ButterKnife.inject(this, view);
    mGridFragmentCheapsale.setFocusable(false);  

在Activity布局中存在列表抢占焦点:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_sale);
    ButterKnife.inject(this);
    mListviewHome.setFocusable(false);

34、列表抢占焦点问题

在gridview和listview初始化数据时自动调用或者我们显示调用notifyDataSetChanged的时候第一个item会被选中并会抢焦点。
android4.4在调用notifyDataSetChanged的时候注释掉了判断touchmode的代码,导致一调用notifyDataSetChanged就模拟用户点击了gridview。
我们继承gridview或者listview重写里面的isInTouchMode方法:

[java] view plaincopy
/**
 * 屏蔽android4.4 setAdapter时View抢焦点的BUG
 */  
@Override  
public boolean isInTouchMode() {  
    if(19 == Build.VERSION.SDK_INT){  
        return !(hasFocus() && !super.isInTouchMode());  
    }else{  
        return super.isInTouchMode();  

35、去除Listview滚动背景变黑,item点击默认背景

listview默认背景和系统窗口一样是透明的,如果给listview加上背景图片,或者背景颜色时,滚动时listview会黑掉,因为滚动时,列表里面的view重绘用的依旧是系统默认的透明色,颜色值为#FF191919
解决办法:

  • 调用listview的setCacheColorHint(0),颜色值设置为0
  • 设置xml文件中listView的属性
  • *Android:cacheColorHint=”#00000000”**,滚动时,重绘View的时候就不会有背景颜色。
  • android:listSelector=”#00000000”*
    进行上面的设置之后,ListView点击item时就没有任何现象了

36. 开启Android系统程序设置页面

Intent intent = new Intent();
intent.setClassName("com.android.settings","com.android.settings.ManageApplications");
intent.setAction("android.intent.action.MAIN");
try {
    startActivity(intent);
} catch (Exception e) {
    e.printStackTrace();
}  

37、禁止EditText自动获取布局焦点

解决之道:在EditText的父级控件中找一个,设置成

android:focusable="true"  
android:focusableInTouchMode="true"  

这样,就把EditText默认的行为截断了!

38、RadioButton设置默认选中

如果RadioGroup中设置默认选中一个RadioButton后,在选择时会选中两个的问题
解决方法:
不需要设置RadioButton的默认选中, 这样会使RadioButton一直处于选中状态.
我们应该给RadioGroup设置选中的RadioButton,
也就是说把radioButton.setCheck(true);
更改为radioGroup.check(radioButton.getId());

39、实现ImageView宽度填满屏幕,高度自适应

1、自定义ImageView重写View的onMeasure方法

public class ResizableImageView extends ImageView {  

    public ResizableImageView(Context context) {  
        super(context);  
    }  

    public ResizableImageView(Context context, AttributeSet attrs) {  
        super(context, attrs);  
    }  

    @Override  
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){  
        Drawable d = getDrawable();  

        if(d!=null){  
            // ceil not round - avoid thin vertical gaps along the left/right edges  
            int width = MeasureSpec.getSize(widthMeasureSpec);  
            //高度根据使得图片的宽度充满屏幕计算而得  
            int height = (int) Math.ceil((float) width * (float) d.getIntrinsicHeight() / (float) d.getIntrinsicWidth());  
            setMeasuredDimension(width, height);  
        }else{  
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
        }  
    }  

}  

2、设置ImageView的属性

//宽度填满屏幕
android:layout_width=”match_parent”
android:scaleType=”fitXY”
android:layout_height=”wrap_content”
//保持比例,一定要设置
android:adjustViewBounds=”true”

40、Glide加载网络图片填充到39中的ImageView中

因为Glide加载图片的规则是根据imageview的大小调整图片。但是ImageView的大小为ImageView宽度填满屏幕,高度自适应的时候,Glide加载的图片就会显示不出来,为此我们选择了一种迂回的方式加载:先请求图片为bitmap,这个时候图片就有一定的尺寸了,再设置到ImageView中就可以自适应了:

Glide.with(GraphicDetailsFragment.this)
                    .load((new StringBuffer(Const.URL_HEAD).append(mStringList.get(position))).toString())
                    .asBitmap()
                    .into(new SimpleTarget<Bitmap>() {
                        @Override
                        public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
                            viewHolder.mImageView.setImageBitmap(resource);
                        }
                    });

大大小小的坑,无处不在,防不胜防。后续会继续更新这篇博文的。
本博客是作者(OCN.Yang)原创
转载请标明原地址: