1、null问题
当对象(基本数据类型、定义的Class对象)只声明未实例化时,其为null.
如:
Date a; //此时给a在栈中分配一个空间保存a变量,a为null。
a=new Date(); //此时在堆中开辟Date对象的数据空间,并把该空间的首地址赋值给a。
Date b=a; //b引用a,将a保存的地址赋给b。在单线程中,a,b的改变同步。即此时改变b中的数据,a中数据同步改变。
在调试中,经常抛出null引用问题。其原因是
:当对象为null时,无法执行任何方法,常见的是执行String.clear()、String.add()等。解决方法
:当有null数据需要进行操作时,先进行if语句的判断。
2、Fragment增删动态更新问题。
当用ViewPage+(FragmentList-FragmentAdapter)时,存在Fragment动态更新问题。造成原因是FragmentPagerAdapter的源码当中的instantiateItem()方法,其根据tag查找对应的Fragment, 如果找到,那么就通过当前的Transaction进行attach操作,这个fragment就会显示了,如果没有找到,就用getItem()从你的Fragment列表中获取一个然后Transaction进行add操作。(自己看一下FragmentAdapter的源码就知道怎么回事了,很清晰简单)网上教程是通过Transaction删除fragment,但该方法存在问题或没有解释完整。通过调试发现其删除fragment的逻辑如下图所示,其删除了fragment,但该位置仍然存在,Fragment重排序后存在一个空fragment。
如此导致当再增加一个Fragment后,第三个位置将直接attach一个空Fragment。新增的Fragment无效。
解决方法
:对于删除Fragment后有再增加Fragment的需求,再删除操作中应直接通过Transaction删除所有内存中的Fragment,重新实例化FragmentAdapter对象刷新内存,可避免空Fragment的存在。
对于Fragment内容更新,则直接获取FragmentList中的Fragment,利用Handle将其在主线程中修改内容即可更新UI。
3、==
判断
在对String进行相等条件判断是,误用“==”
进行相等判断出现bug。问题原因
:“==”
比教的是两个非null对象的地址。使用==判断的情况一般用于基本数据类型及对象为null。对两个String对象进行判断时应使用String.equals()方法。equals()方法比较的是两个对象的内容值。导致后果
:不会出现程序异常,当会导致逻辑错误。
[color=#FF0000]解决方法[/color]:使用equals()方法比较是否相等。
4、非UI线程更改UI组件
UI界面的创建与修改都是在UI线程中,界面创建后,各种事件(如点击事件)的处理方法是在UI线程中的,故此时可修改UI组件。但当需要在其他线程中修改UI组件的情境中,如新建网络请求线程,获取数据后更新UI组件显示,此时对UI组件的修改需要通过handle运行在主线程中。
在weather模块中遇到两处网络请求线程中更新UI组件操作,第一是请求城市,用返回的城市列表数据更新RecycleAdapter,第二处是请求天气,用返回的天气数据更新Fragment。由于部分更新操作未放到UI线程中出错。解决方法
:在主线程中创建Handle,用handle.post() 或handle.handleMessage()将在其他线程中更新UI组件的操作放到UI线程中 关于对UI组件的更改包括常见的(1)UI组件内容修改;(2)UI组件的增删及visible属性设置;(3)notifydatasetchanged(); 对于像Adapter中list的修改(weather中的recycleAdatper),之后调用notifydatasetchanged();都应放到主线程中,否则会出错,实际过程中遇到了网络请求线程结束后UI界面有时改变有时不改变,好像是线程的时序问题。总之所有在非UI线程中涉及的对UI界面的任何修改都应放到主线程中
。
5、多线程共享数据的同步
<本段仅作为个人项目问题小节,估计只有自己能看懂写的啥>
<总之有数据共享时,多线程条件下务必保持数据“可见性”,这是由于java内存机制的原理导致的,具体说明可直接看给出的参考链接>
在weather模块中,为了获得界面显示的所有天气信息,需要请求多个url,多次更新特定位置上一个Fragment上不同位置的内容,且网络请求的响应速度不同,对界面的更新顺序无法保证,为保证代码的共用性,对Fragment上的不同位置的更新使用同一个更新方法,且使用相同的共享数据类型。如此便在多个线程中使用同一个对象WeatherBean,因此必须保证共享数据的可见性。否则会产生错误。
问题原因:程序中的数据存储在主内存中,每个线程有自己的工作内存,当线程需要使用共享数据时,会将主内存中的数据拷贝至自己的工作内存中,之后的操作会使用拷贝的数据,而不会使用主内存中的数据。如:
共享数据WeatherBean为:share={tmp=null,air=null};
线程1与线程2同时获取share, 两个线程分别读取share,并且把share存到了各自的工作内存中,然后线程1获取了tmp数据为10,赋值给share的tmp,此时线程1中share={tmp=10,air=null},并且把tmp的值写回到主存中。但是线程2中工作内存的share={tmp=null,air=null},当线程2获取了air数据为“晴”,其share={tmp=null,air=“晴”},线程1获取数据后进行Fragment.update(share),此时fragment中tmp显示10,air显示空,线程2获取数据后进行Fragment.update(share),此时fragment中tmp显示空,air显示“晴”,所以导致fragment无法正确更新。解决方法
:使用volatile修饰需要共享的数据