Android问题学习摘要
1. 善用API DEMO,初学者的需求基本在里面都可以满足,Eclipse导入API Demo工程出错的话可能原因是SDK版本过低,将target属性设高即可,然后prject——clean一下
2. Fragment属于APP,而不是VIEW,这在API Demo中也有体现,因为Fragment不仅仅是为了展示视图,在每一个Fragment中还可以对相应事件进行处理等
3. FragmentTransaction类中的addToBackStack(args)方法,是指当用户按下返回键时,系统会将当前该事务内的所有操作退回去,而不是把该事务保存起来
4. 各组件的生命周期很重要,目前理解还不是很深入,过段时间进行专门的补充
5. 当需要一个Context参数时可用getActivity()或者getActivity().getApplicationContext(),因为Activity与Application都继承与Context,Activity指一个活动的窗体,通过Activity可以获得Appliction
6. Fragment中如果要获得Context需要覆写在onActivityCreated()或该生命周期之后的函数中,不然会因为Activity尚未生成进而出现nullpointer异常
7. ConnectivityManager 操作移动数据网络,网上普遍的是通过自己设置正确参数来开启网络,设置错误参数进而关闭网络的方法,此方法不好或者霸道的一点在于当你设置了错误参数进去时用户自己想打开网络都开不了了,所以个人比较支持采用反射的方式来做,之后会参考网上大神写一篇博文。
8. NetworkInfo中的getTypeName()返回的值为小写的,如果有网络的话,同时如果当前无网络状态NetworkInfo会为null,记得处理,避免nullpointer异常,匹配网络情况的话避免出错请使用equalsIgnoreCase,忽略大小写,此处API 文档上的返回值是大写,自身测试是小写,不知为何
9. String实现了CharSequence接口,所以在需要CharSequence类型变量时直接用String即可
10. 写在onResume()中的操作可能会被重复调用,这涉及到生命周期问题
————————————————————————————————————————————————————————————————————————————
1. DialogFragment中无法再嵌套子DialogFragment,由于没有使用v4兼容包中的Fragment所以没有getChildFragmentManager,之后会再测试这方法可不可以,setDialogShow()方法再此情况下亦无效,目前使用AlertDialog.Builder来创建对话框,原因是DialogFragment中的id在我调用的时候其实尚未被系统所装载,所以会出现no view found的错误,设想如果提前把需要的资源装载应该可以解决问题,之后会针对这方面写一篇博文
2. AlertDialog.Builder中的OnClickListener()需要使用DialogInterface中的
3. BroadcastReceiver用于处理针对意图的操作,而Service多用于程序在后台运行处理数据、与用户交互等操作
4. AndroidManifest中的package=""属性指定了R文件生成的位置,也是该程序的唯一标识
——————————————————————————————————————————————————————————————————————————
1.广播接收者使用静态注册的方式比较好,首先有些Action是只能使用静态注册的,其次代码注册仅在程序开启过程中由我们来注册进而处理一些事情然后在程序结束或者在程序生命周期内的某个特定时候进行关闭时才使用,静态注册需要注意的一点(这是我自己做项目的过程中一开始没有想到的,也是经验不足的原因)就是有的朋友可能会问那静态注册了这个广播接收者,它不就一直在后台运行着,一直在处理事情吗,那我不想它处理了怎么办,其实我们可以通过采用参数的进行控制,比如将一个参数放入SharedPreferences中,然后广播接收者激活时获取一下参数值,根据参数值进行相应的操作
2.SharedPreferences的Mode之前理解错误以为是控制是否复写是否追加,其实是用来控制该XML配置文件的权限的
3.SVN版本控制,主开发于trunk目录中;branchs用于已发布版本基础上的bug调整等;tags用于保存发布版本,此目录只读
4.DDMS中是看不到真机中的data目录的,因为真机没有赋予DDMS这个权限,可通过adb shell查看
5.PendingIntent中的flags参数 指定PendingIntent的一些行为,比如只开启一次等
6.AlarmManagerService是service运行在systmen_server进程
7.Exported receiver does not require permission指自己定义的接收者没有设置权限,设置权限或者 android:exported="false" 即指定该接收者不能跨进程使用
8.AlarmManager 根据PendingIntent的requestcode来进行区分不同的闹钟,根据这个可以用来取消指定的闹钟任务
9.Calendar.getInstance(Locale.CHINA)之后可以获得本地化的数据,比如星期的第一天是星期一等,不过这个我使用了本地化之后get所取到的星期数依旧是从星期日开始的,不知为何,之后查到资料了补上
10.ListView的使用一定要记得进行优化(holder优化之后会写一篇博文总结)
11.刷新界面,在Activity中使用广播接收者,创建该Activity时注册,销毁该Activity时注销,但是这点没有实现出来,之后解决了专门写一篇博文总结
12.int month = c.get(Calendar.MONTH)+1; 因为算月份时是计算离第一个月差几个月,那么1月就是0
13.重点:AlarmManager.set方法的triggerAtTime如果type选择的是绝对值模式,则要使用目标时间的总毫秒数,而不是目标时间减去当前时间的毫秒数,否则会直接发送intent,因为相减之后的毫秒数代表着好早好早好早以前就应该发送意图了
_______________________________________________________________________________________________________________________________
1.在布局配置文件中,当权重有垂直时,每一个部分的layout_height必须为0dp;当权重为水平时,其每一部分的layout_width必须为0dp
2.使用SVN commit项目的时候bin、gen这类目录不用提交,是编译生成的文件目录
3.private 类名(){} 把构造函数私有化从而避免用户new
4.可以从sql_master表中获取目前sqlite中有哪些表进而判断是否需要重新创建我们需要的表
5.使用OnKeyDown()函数通过参数等方式来做出对后退等事件的处理
6.FragmentTransaction的remove()方法的Fragment类型参数中的fragment可以从碎片栈中通过add时设置的tag获取
7.使用当前的view来findViewById时只能获取当前这个view视图中的资源,使用getActivity()再去find可获得其他视图资源
______________________________________________________________________________________________________________________
1.资源文件命名只能小写,否则会报错生成不了R.java文件
2.R文件导包时应该导入自己工程的包,而不是android.R
3.数据库操作使用SqliteOpenHelper
4.values目录下自定义一个自己的xml文件,获取的方法是R.__横线处根据自定义XML中的子节点而定,比如<String />则就是R.String
5.Eclipse中CTRL+SHIFT+X与CTRL+SHIFT+Y为大小写转换
6.使用高度为1dp的<View>标签可实现分割线
7.当一个Fragment叠加在另一个Fragment上时可能存在事件穿透,此时设置上面的Fragment的clickable="true"即可
8.ImageButton通过设置background="#00000000"可变为透明,设置其背景与图片背景一样可更为美观,ImageButton需要设置clickable="true"
9.ConnctivityManager.Connectivity_ACTION为监听网络状态变化,是否是监听所有网络之后看了API说明再补上
WifiManager.NETWORK_STATE_CHANGED_ACTION为监听WIFI网络变化,包含开启与关闭两种状态
WifiManager.WIFI_STATE_CHANGED_ACTION为监听WIFI状态变化,包含开启中,已开启,关闭中,已关闭
10.遇到不需要嵌套的情况比如使用FrameLayout来创建布局所需的单一根节点时,可以使用<merge>标签来替代<FrameLayou>标签,当包含有merge标签的布局被添加到另一个布局时,该布局的merge节点会被删除,而该布局的子View会被直接添加到新的父布局中,merge标签结合include标签一起使用时尤其有用,include标签是用来把一个布局的内容插入到另一个布局中
11. ViewStub是一个隐藏的,不占用内存空间的视图对象,它可以在运行时延迟加载布局资源文件。当 ViewStub 可见,或者调用 inflate()函数时,才会加载这个布局资源文件。
12.关于Activity与Fragment的各自以及组合起来的生命周期之后会专门补上一篇博客
13.在对Fragment进行增删替换等操作之后可指定其动画,再根据需要选择是否添加到back栈中,最后commit()
14.在需要传入例如作为标志的参数时可以使用“|”来加入多个参数
15.创建一个类继承Application后可对整个应用程序的生命周期函数进行相应的处理,例如在整个应用程序启动时对数据库进行开启,当应用程序进程被终结时才关闭数据库,但是需要在Manifest清单文件中的application节点指定name属性,值为自己的类名
16.在一个广播接收者中若要再注册一个广播接收者,需要使用context.getApplicationContext().registerReceiver,可解决ReceiverCallNotAllowedException异常
17.当我们接收到一个intent时若要对该intent进行数据修改然后再发送出去,此时后面的接收者接收到该intent时是取不到数据的,因为默认情况下intent不能复用,数据会被过滤掉,可以使用flag标识不同的模式以进行复用
18.使用ComponentName与RemoteViews可对桌面插件视图进行更新
19.Application中的terminate函数不一定会被调用,如果不被调用数据库没有关闭的话,再重装的时候会报错,但不会提示给用户,仅会记录在日志中
20.目前遇到一个问题,当我用add的方式在原本已经有一个fragment的容器中再添加一个fragment时,后者不会显示,只能使用replace,同时popBackStack函数的实现原理也还需要学习,之后补上
21.使用.9.png
22.Manifest文件中使用installLocation属性可以指定是否允许或者首选将应用程序安装到外部存储器上(用户不能拒绝或取出SDK,否则应用程序将立即终止)
不适用于:具有Widget、Live Wallpaper和Live Folder的应用程序
提供不中断服务的应用程序
输入法引擎IME
设备管理器
______________________________________________________________________________________________________________________
1.proguard混淆:对与Activity等不应进行混淆,否则系统将找不到生命周期函数;JSON字符串要考虑混淆之后是否会影响字段名;native方法也不混淆,否则调用不到
2.ListView的onItemLongClickListener返回true时将不会再调用onItemClick
3.善用单例模式
4.分享会上所得:重要与紧急哪个优先处理,答案是优先处理重要的事情。处理事情的顺序应该是:重要又紧急,重要不紧急,紧急不重要,不紧急不重要。首先重要的事情一般都是正确的事情,而紧急去做的事情却不一定是正确的,其次重要有紧急的事情占的比例最小,不紧急不重要的事情最多,而如果我们选择先去处理紧急不重要的事情的话,那么之前重要不紧急的事情将会因为重要而变得紧急,那么我们就会陷入一个持续处理重要又紧急事件的循环中,这是一种非常不利的工作状态。
5.使用番茄来进行自我计划与训练
6.工程右键——Properties——Android,作为Library的项目要勾上is Library,要引入工程库的点击add(我的Eclipse存在问题,可能是自身配置原因,无法使用绝对路径的工程库,只能使用相对路径,之后查证下)
7.Application层位于最底层,系统层位于最高层,Application无法屏蔽Home键,而Dialog层比Application层等级高,所以可用一个透明的Dialog来实现屏蔽
8.当有莫名其妙的错误:如不可能的类型转换异常,已导包却报错等,尝试对工程进行clean或许可以解决
9.clampViewPositionVertical返回的是被拖动的子View的被拖动下一刻的位置,如果return 0 则拖动一下子View就会直接出现在最左侧
10.Automatic Target Mode: Unable to detect device compatibility. Please select a target device. 当其他项目都可以运行,但是有项目报这个错误时候,右键propertites选择Android,选择你手机系统版本,然后到清单文件中更改一下,再重新安装
11.
————————————————————————————Android 4高级编程学习摘要————————————————————————————————————
1.SharedPreferences中的apply方法是在API 9之后引入的,调用它会安全地异步写入SP Editor。因为它是异步的,所以是保存SP的首选方法。如果想要确保操作成功,或者想支持早期的Android版本,则可以调用commit方法,它会阻止调用线程,并在写入成功后返回true,在写入失败时返回false。
2.与标准UI布局不同,首选项定义在res/xml资源文件夹中
3.Android 3.0(API LEVEL 11)之前的Android平台不支持PreferenceHeader和Preference Fragment,在Preference Activity中直接添加PreferenceScreen
4.如果Activity被销毁,然后被重新启动,以处理硬件配置改变(如屏幕方向改变)的情况,那么可以请求保留Fragment状态。通过再Fragment的onCreate处理程序内调用setRetainInstance,就指定了当与Fragment关联的Activity被重新创建时,Fragment的实例不应该被终止和重新启动。因此,当设备的配置改变,并且与被保留Fragment关联的Activity被销毁和重新创建时,被保留Fragment的onDestroy与onCreate处理程序不会被调用。如果将大部分对象创建代码移入onCreate,同时使用onCreateView和已保存实例值中存储的值来更新UI,这可以显著提高效率
5.如果应用程序需要外部文件资源,那么可以通过将其放置在项目层次结构的res/raw文件夹中,从而在自己的分发包中包含它们。若要访问,使用Resouce对象的openRawResouce方法,以便基于所指定的文件接收一个InputStream,传入文件名(不带扩展名)作为R.raw类的变量名。
6.大型的、先前已存在的数据源(如字典)不适合(甚至不可能)转换到Android数据库中,此时,向资源层次结构添加原始文件是一种非常好的解决方法。
7.如果应用程序需要缓存临时文件,Android提供了一个可管理的内部缓存和(API 8开始)一个不能管理的外部缓存。分别调用getCacheDir和getExternalCacheDir方法可以从当前的上下文中访问他们。
8.SQLite在列定义中使用了一种松散类型的方法。即并不要求一列中的所有值都是同一类型;相反,在每一行中分别设置每个值的类型。这样当从每一行的每一列中分配或者提取值时就不需要进行严格的类型检查了。
9.等到需要数据库时再创建和打开这些数据库是一种很好的做法。SQLiteOpenHelper会在成功打开数据库实例后缓存它们,所以你可以再刚好要执行查询或事务前请求打开数据库,出于相同的原因,除非不再需要使用数据库否则无需关闭。
10.由于数据库操作需要较长的时间才能完成,因此,为了确保这些操作不会影响用户体验,应该使所有数据库事务异步执行
11.如果磁盘空间不够或者没有足够的权限,对getWritableDatabase的调用可能失败,因此如有必要,在需要查询数据库时应该使用getReadableDatabase作为后备。在大多数情况下,它将提供与getWritableDatabase相同的、已缓存的可写数据库实例,除非该数据库实例还不存在,或者存在相同的权限或者磁盘空间问题,那么它将返回一个只读的数据库实例副本。
12.在创建或者升级数据库之前,必须以可写形式打开数据库,因此一般来说,最好的做法是首先尝试打开可写数据库,如果不能成功打开,就再去尝试打开只读数据库。
______________________________________________________________________________________________________________________
Android中的优化
1. 对于ListView的优化
使用BindView函数专门处理数据与视图绑定的操作
getItem函数与getItemId函数不是在需要的时候才去重写的,而是必须根据自身应用的实际情况对其进行修改,比如getItemId,不一定是返回position,也可以返回list集合中的相应位置上元素的ID
视实际情况而定,当要适配到视图条目上的数据对象为空时,如有需要应该对视图也进行更新,否则到时候显示给用户的将是该条试图条目上原本的数据而不是空数据
使用自定义ViewHolder对控件进行初始化,避免多次findViewById2. Activity中控件以及桌面插件的界面刷新
目前操作过于繁琐而且也没有必要,可以统一通过对网络状态改变的事件进行监听,从而对APN、WIFI的界面显示进行相应的更新,同时可以考虑对中间状态也进行获取,并且当处于中间状态时控件应该是不可被操作的
以刷新Swicher为例:
- //定义对网络进行监控的广播接收者
- public class SwitcherNetworkStatusMonitor extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
- updateSwitchWifiView();
- } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
- updateSwitchApnView();
- }
- }
- }
- //更新Wifi控件函数
- public void updateSwitchWifiView() {
- if (switchWIFI != null) {
- WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
- int wifiStatus = wifiManager.getWifiState();
- if (wifiStatus == WifiManager.WIFI_STATE_ENABLED) {
- switchWIFI.setChecked(true);
- } else if (wifiStatus == WifiManager.WIFI_STATE_DISABLED) {
- switchWIFI.setChecked(false);
- }
- }
- }
- //更新Apn控件函数
- public void updateSwitchApnView() {
- if (switchAPN != null) {
- NetworkManager networkManager = new NetworkManager(
- getApplicationContext());
- if (networkManager.isApnOpened()) {
- switchAPN.setChecked(true);
- } else {
- switchAPN.setChecked(false);
- }
- }
- }
- //在onStart()函数中对BroadcastReceiver进行注册以及控件的初始化
- @Override
- protected void onStart() {
- super.onStart();
- switchAPN = (Switch) findViewById(R.id.apn_switcher);
- switchWIFI = (Switch) findViewById(R.id.wifi_switcher);
- mSwitcherNetworkStatusMonitor = new SwitcherNetworkStatusMonitor();
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
- intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
- registerReceiver(mSwitcherNetworkStatusMonitor, intentFilter);
- }
- //在onStop()函数中注销掉BroadcastReceiver
- @Override
- protected void onStop() {
- unregisterReceiver(mSwitcherNetworkStatusMonitor);
- super.onStop();
- }
3. 理解PendingIntent创建时flags参数的含义
4. 对于每个类、每个方法要明确它们的角色和分工,每个变量的位置也要放在适合它们的位置,比如视图变量就不应放在广播接收者中
5. 内部类和外部类学习
6. Static作用
静态代码块:在项目启动的时候项目代码块就会被执行,静态方法在类加载的时候就已经加载了,但是要在被调用的时候静态方法才会执行。
由于静态内部类只能访问外部类中的静态成员,而findViewById等方法都是非静态的,这样可以避免该类持有一些不必要的对象,长期地持有诸如控件等试图资源甚至是Activity或者上下文环境会导致这些资源长期驻扎在内存中得不到释放,最终导致内存泄露。
7. 数据库并行问题
通过扩展Application进而在整个应用程序的启动时开启数据库,终结时关闭数据库。应用程序的服务是运行在程序的进程上的,当程序进程被终结了,服务也就不存在了。
创建ENApplication类继承Application实现onCreate()与onTerminate()方法
- @Override
- public void onCreate() {
- super.onCreate();
- DatabaseUtil.openDatabase(getApplicationContext());
- }
- @Override
- public void onTerminate() {
- DatabaseUtil.closeDatabase();
- super.onTerminate();
- }
8. 扩展系统视图或者系统服务时,在创建时候应该让系统先创建自己的内容,进而再执行我们的操作,而在销毁时,应该先销毁我们的内容再执行系统的销毁操作。如在onCreate()函数时先调用super.onCreate(),在实现自己的操作,而在onDestroy()时,先销毁自定义的内容再调用super.onDestroy()