Android 开发中遇到的坑

来源:互联网 发布:淘宝微淘粉丝抢红包 编辑:程序博客网 时间:2024/06/07 18:34

1、AlertDialog上弹Toast或者其它对话框,AlertDialog将消失,解决办法自定义对话框继承自Dialog。

2、style命名不能与控件同名:例如:

    <style name="Button"/>    <style name="Button.CommonButton" parent="Button">        <item name="android:layout_width">match_parent</item>        <item name="android:layout_height">45dp</item>        <item name="android:textColor">@color/white</item>        <item name="android:textSize">16sp</item>    </style>
<Button        style="@style/"Button.CommonButton"        android:text="扫描" />

如上代码,style将无法展示Button的效果,将Button重命名Btn就OK了

3、Fragment异步或延迟去showToast或者show一个对话框,且传的context是getActivity(),或者多次点击按钮show一个Toast或对话框,当点击后退键finish掉了这个activity,Fragment会报空指针异常:
java.lang.NullPointerException: Attempt to invoke virtual method ‘android.content.res.Resources android.content.Context.getResources()’ on a null object reference
或者
java.lang.NullPointerException: Attempt to invoke virtual method ‘android.view.LayoutInflater android.support.v4.app.FragmentActivity.getLayoutInflater()’ on a null object reference
解决办法:showToast时用Application的context,或者监听Fragment的onDestroyView生命周期,当视图销毁了,就不能再showView了

4、Eclipse的安卓项目切换到Android Studio,低版本的buildTools切换到高版本的buildTools可能会导致各种异常,比如权限申请问题,6.0及以上系统危险权限要求代码申请,又比如出现第3条的问题等。

Android中有很多权限,但并非所有的权限都是敏感权限,于是6.0系统就对权限进行了分类,一般为下述几类

正常(Normal Protection)权限
危险(Dangerous)权限
特殊(Particular)权限
其他权限(一般很少用到)

5、有时我们发现在写RecyclerView的Adapter的Item布局中,Width明明是用的match_parent属性,但界面却呈现的是wrap_content的效果,这时应该注意:(1)、根容器LinearLayout改为RelativeLayout (2)、具体的控件应该改为match_parent。
(3)、RecyclerView的item使用如下代码,item会占满屏,而ListView会自动适应Textview控件的高度

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <TextView        android:id="@+id/tv"        android:layout_width="wrap_content"        android:layout_height="wrap_content"/></LinearLayout>

6、Fragment使用Add、Show、Hide方式,如果退到后台待机过长或操作了耗内存的应用,或者横竖切屏导致Activity被重新创建时,Fragment就会出现重叠,因为宿主Activity会被杀死,Fragment的View也会被销毁再重新创建,而Fragment的实例却还被保存在FragmentManager里面,当Activity重新onCreate的时候,hide和show方法却管控不到以前Fragment的实例了。
解决方案一:
注释掉如下两个方法的任意一个super,防止保存Fragment的实例

 @Override    protected void onSaveInstanceState(Bundle outState) {    //    super.onSaveInstanceState(outState);      }    或者    @Override    protected void onRestoreInstanceState(Bundle savedInstanceState) {    //    super.onRestoreInstanceState(savedInstanceState);     }

解决方案二:
根据onCreate方法判断savedInstanceState是否为空,如果不为空,就用fragmentManager通过之前绑定的TAG找到相应的fragment,然后赋值,不再去重新add这几个fragment,前提:首次add之前需要加tag调用如下方法:
例如:transaction.add(R.id.fl_content, homeFragment, HomeFragment.class.getName());。

manager = getSupportFragmentManager();if(savedInstanceState != null){        mChide= (ChideFragment)manager.findFragmentByTag(ChideFragment.class.getName());        mGuangde = (GuangdeFragment)  manager.findFragmentByTag(GuangdeFragment.class.getName());        mWode = (WodeFragment) manager.findFragmentByTag(WodeFragment.class.getName());        mLiaode = (LiaodeFragment) manager.findFragmentByTag(LiaodeFragment.class.getName());         //然后去show或者hide   } else {        mChide = new ChideFragment();        mGuangde = new GuangdeFragment();        mWode = new WodeFragment();        mLiaode = new LiaodeFragment();        //再去show或者hide   }

解决方案三:
方案二的升级版,控制show和hide是在BaseFragment里面
Fragment重叠的根本原因在于FragmentState没有保存Fragment的显示状态,即mHidden,导致页面重启后,该值为默认的false,即show状态,所以导致了Fragment的重叠。根据这个原因,我们手动维护一个mSupportHidden不就行了吗?因此,需要先写一个BaseFragment,例如:

public class BaseFragment extends Fragment {    // 任意字符串常量即可    private static final String HIDDEN = "HIDDEN";    @Override    public void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstancestate);        if (savedInstanceState != null) {            boolean isHidden = savedInstanceState.getBoolean(HIDDEN);            FragmentTransaction ft = getFragmentManager().beginTransaction();            if (isHidden) {                ft.hide(this);            } else {                ft.show(this);             }            ft.commit();        }    }    @Override    public void onSaveInstanceState(Bundle outState) {        super.onSaveInstanceState(outState);        outState.putBoolean(HIDDEN, isHidden());    }}

然后,在Activity的onCreate回调中判断:

@Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        // 这里判断savedInstanceState为null 或者判断getSupportFragmentManager().findFragmentByTag("tag")为null都可以        if(savedInstanceState == null){              //才去new 新的实例              //然后再hide或者show        } else {            //否则从tag中获取实例            mChide= (ChideFragment)manager.findFragmentByTag(ChideFragment.class.getName());        mGuangde = (GuangdeFragment)  manager.findFragmentByTag(GuangdeFragment.class.getName());        mWode = (WodeFragment) manager.findFragmentByTag(WodeFragment.class.getName());        mLiaode = (LiaodeFragment) manager.findFragmentByTag(LiaodeFragment.class.getName());         //不需要再去控制hide或者show,因为BaseFragment自动控制好了        }    }

优点:不管多深的嵌套Fragment、同级Fragment等场景,全都可以正常工作,不会发生重叠!
缺点:暂未发现

7、单独调用下面的代码,Toolbar设置标题不显示
toolbar.setTitle(resId);
toolbar.setTitle(CharSequence title);
需要在设置标题后加上:setSupportActionBar(toolbar);

8、ExpandableListView的GroupItem布局文件中不能有Button,否则点击GroupItem无法展开ChildItem。

9、Android应用程序(APK)在Dalvik可执行文件的形式包含可执行的字节码文件(DEX)文件,其中包含已编译的代码来运行你的应用程序。Dalvik可执行规格限制一个Dex文件包含65536个方法:包括Android框架方法、Library方法的总数、和你自己的代码方法总数。因为65536等于64×1024,这一限制被称为“64k引用限制”。 这个极限就要求我们配置应用程序的构建过程,需要生成多个DEX文件,所以称为multidex 配置。

引用块内容 http://www.jb51.net/article/92479.htm , https://github.com/singwhatiwanna/dynamic-load-apk
插件式开发框架

解决方法分Android 5.0及以上系统和5.0以下系统怎么做
一、Android 5.0以下的版本
Android 5.0(API leve 21)之前的系统使用Dalvik执行应用程序代码。默认情况下,Dalvik限制一个apk只有一个Dex文件。为了绕过这个限制, 我们可以使用multidex support library,它成为我们APK的主要DEX文件的一部分,负责管理我们APK访问其他DEX文件和代码。
注意: 如果咱的项目minSdkVersion是20或更低,运行到Android 4.4(API leve 20)或者更低版本的设备上时需要禁用AndroidStudio的即时运行
二、Android 5.0和更高版本
Android 5.0(API leve 21)和更高的系统使用runtime是ART ,原生支持从应用的apk文件加载多个DEX文件。ART在安装应用时预编译应用程序,会扫描多个classes(..N).dex文件编译成一个.oat的文件。更多Android5.0 runtime的更多信息,请参见即时运行-instant-run。
注意: 如果你使用即时运行 , AndroidStudio自动配置你的应用程序,你应用程序的minSdkVersion应该设置为21或更高。因为即时只工作在你APP的Debug版本,你任然需要配置你的release版本构建时用multidex避免64k的限制。
三、尽量避免64k限制
在配置我们的App启用64k或者更多方法引用之前,我们可以减少应用代码内的调度总数,包括我们自身应用的方法和第三方的库,下面的几个策略或许可以帮到你:
•检查你的APP的直接和间接的过度依赖关系:有时候我们用到某个Libaray的某几个方法或者功能时这个库非常大,减少这种依赖可能对与避免64k的问题非常有效。
•在正式打包构建的时候,使用代码混淆器ProGuard混淆移除未使用的代码,也就是不把没有使用的代码打包到我们的apk中。
使用上面的方法可以帮助我们避免在应用程序中生成太多无用的方法和减小我们apk的大小,这对于用自己服务器做app更新升级的同学是非常有帮助的。
四、解决64k问题
在Android SDK Build Tools 21.1或者更高版本的build工具中用Android plugin gradle。确保你更新Android SDK build tools和Android support到最新版本,然后用multidex配置应用程序。我们必须要做两步。
(1)你的Application继承自MultiDexApplication,或者在你的Application里面加入如下代码:

protected void attachBaseContext(Context base) {     super.attachBaseContext(base);     MultiDex.install(this);}

(2)在App的gradle里面加入代码: multiDexEnabled true

10、实体类用Parcelable序列化,读写的顺序必须一致,否则报如下异常:
java.lang.RuntimeException: Parcel android.os.Parcel: Unmarshalling unknown type code

11、Android 5.0以上系统隐式意图直接启动组件会报异常:
IllegalArgumentException: Service Intent must be explicit。
解决办法:

Intent intent = new Intent();ComponentName component = new ComponentName("包名",                "完整路径类名");intent.setComponent(component);startService(intent) 或者 startActivity(intent);