第二行代码学习总结 & 我遇到的BUG汇总

半年一更新,一更拖半年……前阶段直至在“不踏实”地学习Android知识;跟了不少视频,看了不少书;实际上学地都不踏实;直到今天彻底迷茫,不知道该怎样“系统地”学习Android;我想那不如把前阶段的收获总结分享一下吧:

如果你从中有所收获的话,请给我点个赞鼓励下吧!😀

一、Android Studio导入现有工程的几个步骤

这里是参考的:“Android Studio导入现有工程的几个步骤.”
概括以下四步:

  1. 根目录下的 build.gradle里定义了gradle tool的版本号;手动修改这里的版本号为当前支持的版本号:
  2. 根目录下的gradle\wrapper里的gradle-wrapper.properties文件修改为自己的gradle配置中的zip包的版本;
  3. 最后修改一下app模块下的build.gradle;对应的sdk的版本,build tool的版本号,以及一些依赖的jar包;
  4. 如果Android studio运行出错 compilation failed see the compiler error output for details.;点击下图圈圈;切换一下显示模式;就可以具体修改代码中的错误;在这里插入图片描述

二、这里推荐一篇好文

这篇文章里有不少经验分享和资料分享: Android小白学习成长路线.

三、四大应用组件之ContentProvider

不知道这里为什么会有这篇经验;如有侵权,请联系我立即删除!

  1. 理解
    1). 为会么要有ContentProvider?
    在这里插入图片描述
    2). ContentProvider是什么?
    在这里插入图片描述

  2. 相关API:

    1). ContentProvider: 内容提供者类
    在这里插入图片描述
    2). ContentResolver: 内容解析器类 :
    在这里插入图片描述
    3). Uri: 包含一个具有一定格式的字符串所对应资源的类
    在这里插入图片描述
    4). UriMatcher: 用来识别uri的一个uri容器
    在这里插入图片描述
    5). ContentUris: 操作uri的工具类
    在这里插入图片描述

  3. 自定义ContentProvider
    在这里插入图片描述

  4. 使用ContentResolver访问ContentProvider
    在这里插入图片描述

  5. 应用练习

    1). 使用 ConentResolver 查询得到所有联系人数据列表
    2). 使用 ListView + BaseAdapter 显示列表
    3). 使用带回调启动 Activity 和带结果的返回

四、Git

  1. 期间里用一周时间了解了一下Git;
  2. 学习资料当然是“业界公认"的: 廖雪峰的官方网站.
    我打起了广告?额……不管了,自己的学习总结而已;

五、View学习总结和BUG

  1. ListView

    • 设置一个ListView并找到;
    • 初始化数据(把数据装到集合里);
    • 数据设置到adapter中;
    • adapter 又设置给ListView;
    • 难点在于自定义adapter
      a. 自定义adapter继承与ArrayAdapter<或BaseAdapter>;并产生其构造器;
      b. 重写 .getView() ;此时 ListView 中每一个项目可用 .getItem() 获得;
      c. 其中重写了一个 ViewHolder 类;
      d. 难点 在于两步优化和 .getView() 的理解。
    • BUG:判断 ArrayList 中是否为空;绝不能用 mFruitList == null;
      要用 mFruitList.size() == 0 代替

    疑问:"com/example/listviewtest/FruitActivity.java:25"中;去重方法 写了;可是,每次打开软件都是重新填充数据,而不会用到去重方法。.

  2. BUG :List 使用 add 方法时;List集合add方法覆盖原来的内容 ;修改 用 addAll 复制得到的数据 arrayList 中 ,修改数据时,原数据也被修改;结果就是,最终添加的结果都一样,全都是最后一次add的效果,<都是Java基础不扎实的原因啊>
    a. 这是因为,arrayList 的性质!如果元素是引用类型,保存的是引用,如果是值类型,保存的是值本身。这里addAll 只是复制了地址,并非复制了全部的元素!同理,数据的add(),可以在set()前,也可在其后;
    b.解决方法:就是每次循环的时候,都把要添加的对象, new 一遍然后进行 set 等操作;如果元素是 值类型 ,那么就不许重复 new 对象;
    c. 那么如何复制 集合中的元素!还是老老实实的遍历吧……

  3. BUG

    Android报错:Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)
    Caused by:
    java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference
    

    解决方法
    1. 根据提示找到出错行;
    2. xml 布局文件中,id不能大写
    3. 资源名不能大写!
    4. 控件名称首字母要大写:< V iew
    5. View划横线:用的是 background

    如果你从中有所收获的话,请给我点个赞吧!😀

六、fragment 和 Framelayout

学习资源来自 郭神《第一行代码Ⅱ》4.2.2 动态加载碎片 P148
原图如下(注意右边半拉):
在这里插入图片描述
设置了点击事件,当点击button时,会动态载入碎片:
main_activity.xml 使用 <FrameLayout 布局时,得到的是正常的结果:在这里插入图片描述
如果使用 fragment 碎片;得到的结果没有用新界面完全代替就界面,如下:在这里插入图片描述
原因:
a. 因为默认的这层 right_fragment,使用的 linear layout 填充的,而这个layout里面只有一个text view,当你设置的点击事件直接使用碎片 fragment ,来动态加载碎片时,就只能在这个textview之下。
b. 要想动态加载碎片,就必须用另一个 FrameLayout 替换 LinearLayout,而后往 layout 中填充碎片。到此问题解决。

七、关于广播接收器的注册销毁

学习资源来自 郭神《第一行代码Ⅱ》5.5 最佳实践 P190 下

关于广播接收器的注册和销毁

  1. 广播接收器都是在 .onCreate() 中注册,在 .onDestroy() 中销毁;
  2. 但是本次实例,是要接受一个,强制下线的广播,只需要保证:处在栈顶位置的活动能接收到广播,非栈顶活动不需要接受;
  3. 所以本处用到了 activitycollect 和 BaseActivity 写的十分巧妙;来看一下 activity 的生命周期在这里插入图片描述

八、一些小的注意事项

  1. 代码顺序,由上而下一定要有逻辑,.findViewById() 一定要先写,不然程序闪退。

  2. 学习存储的时候,因为无法使用DDMS查看手机的文件,而大费周章,原来就在 AS右下边有一个竖条形的键,就是打开文件存储的快捷方式。

  3. manifest 中申请权限;一定要加 uses- uses- permission android:name=“android.permission.READ_CONTACTS”

  4. BUG :关于 String 判空

    错误: if (mResponseData.equals(null) || mResponseData.length() == 0) {
    正确: if (mResponseData == null || mResponseData.equals("")) {
    或者: if (!TextUtils.isEmpty(restoreText)) {
    
  5. 真机安装 apk 失败;在 gradle.properties 文件添加一句 android.injected.testOnly = false

  6. 真机(Android9)安装后闪退:Failed resolution of: Lorg/apache/http/params/BasicHttpParams;;解决办法:在AndroidManifest.xml 文件的 application 标签下添加:<uses-library android:name="org.apache.http.legacy" android:required="false" />

  7. java生成随机数有两种方法:

    1、使用Math方法,
        int num = (int) (Math.random() * 15);
    	(int) (Math.random() * num) 	//生成的是 0 ~ num-1
        (int) (Math.random() * num + 1) //得到的是 1 ~ num
    2、使用Random方法,
        Random random = new Random();
        int length = random.nextInt(20) + 1;
    
  8. 自定义控件使用:

    a. 编写 title.xml 文件;
    b. 编写自定义控件 类 在构造器中引入.xml
     	LayoutInflater.from(context).inflate(R.layout.title, this);
    c. 在需要引用自定义控件的 xml 中引用(LinearLayout);
    	<com.example.myapplication200122.TitleLayout
    				...
    
  9. 碎片的使用:

    a. 编写布局 fragment.xml; 
    b. 编写碎片 类 ;.onCreate() 中使用 .inflate() 将碎片布局引入;
      View view = inflater.inflate(R.layout.fragment, container, false);
    c. 在需要使用碎片的 xml 中使用:
        <fragment
            android:name="com.example.fragmenttest.LeftFragment"
                    ...
    
  10. View 和ViewGroup 的区别
    首件删除了笔记,现场直编……

    1. 如果点击事件出问题,不响应或者响应其他控件时;应该 检查 xml 的布局,是否控件被覆盖;
    2. View 不能对其子空间进行操作,而 ViewGroup 可以,所以如果出现,动画已经从页面消失,而仍然响应点击;可以考虑
      a. 把 View 更改成 ViewGroup ,然后遍历其子控件,当子控件消失设置其不可点;
      b. 或者使用 属性动画(ObjectAnimator) 代替 值动画;
  11. Android编译出错:app:checkDebugDuplicateClasses;检查是不是依赖包重复了;

  12. 当我打不开“https://developer.android.com/reference/android/view/View.html”时;
    把".com" 换成".google.cn" 就可以了

  13. 导入GitHub上项目报错:

    Could not resolve all dependencies for configuration ':app:debugRuntimeClasspath'
    

    在根目录下 build.gradle 文件中,加上 “google() mavenCentral()” 写成:

    buildscript {
    repositories {
        jcenter()
        google()
        mavenCentral()
    }
    allprojects {
    repositories {
        google()
        jcenter()
        mavenCentral()
    	}
    }
    

九、数据库学习中遇见的BUG

  1. 先看代码:

    报错:org.litepal.exceptions.DatabaseGenerateException: can not find a class named com.coolweather.android.db.Province
    
    问题在于:数据库知识掌握不扎实;litepal.xml 文件中结构。如此 stupid 问题……
    <litepal>
    <dbname value="cool_weather" />
    <version value="1" />
    <list>
    <mapping class="com.example.coolweather.db.Province" />    //放数据库所在 包名
    <mapping class="com.example.coolweather.db.City" />
    <mapping class="com.example.coolweather.db.County" />
    </list>
    </litepal>
    

    这是因为数据库中定义的名称和 .java 文件中名称不一致,找不到;

  2. 学习资源来自 郭神《第一行代码Ⅱ》14.5.3 将天气显示到界面上 P520

    报错:Attempt to read from field 'java.lang.String com.example.coolweather.gson.Basic.cityName' on a null object reference
    java.lang.NullPointerException: Attempt to read from field 'java.lang.String com.example.coolweather.gson.Basic.cityName' on a null object reference
    

    这是因为:在JSON中的一些字段可能不太适合直接作为java字段来命名,因此使用了 @SerializedName 注解的方式来让JSON 字段和Java字段之间建立映射关系;而JSON的数据是键值对的格式存在的,我们在Json格式文件中写的 键,和java文件中的取值 键 不对应;所以无法获取到对应的值。

十、inflate 方法

  1. 介绍
    LayouInflater 中 inflate 方法两个参数和三个参数
    LayoutInflater.from(RecylerActivity.this).inflate(R.layout.my_text_view,viewGroup,false);
    View.inflate(RecylerActivity.this, R.layout.my_text_view, null);
    
  2. 如果我们采用 convertView = inflater.inflate(R.layout.item_list, null);方式填充视图,item布局中的根视图的layout_XX属性会被忽略掉,然后设置成默认的包裹内容方式;
  3. 如果要保证item的视图中的参数不被改变,我们需要使用convertView = inflater.inflate(R.layout.item_list, parent,false);进行填充;
  4. 除了这种方式,我们还可以设置item布局的根视图为包裹内容,然后设置内部控件的高度等属性,这样就不会修改显示方式。
    总之推荐用inflater.inflate(R.layout.item, parent, false);
    关于这节内容你应该是看不懂,推荐你看: inflate方法两个参数和三个参数的区别;.

如果你从中有所收获的话,请帮我点赞收藏分享鼓励我吧!😀

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章