Android静态扫描出的问题


http://godeyes.duapp.com/scanrule.jsp#a_title9
http://godeyes.duapp.com/scanrule.jsp#a_title9


系统API兼容性隐患
1.1.1 摘要

问题:在Android平台的一个系统版本中调用了该版本中不存在或不合适的系统API,必然会出现调用失败或运行结果不符合预期,进而导致软件运行发生Crash或产生错误。

解决方案:在这些API使用时,加上Android系统版本判断,避免不兼容API的调用。

1.1.2 示例
对于如下代码:

private void setUpActionBar() {

        ActionBar actionBar = getActionBar();

        actionBar.setDisplayHomeAsUpEnabled(true);

}

该方法中,调用了ActionBar.setDisplayHomeAsUpEnabled()方法,而在Android官方文档中有如下描述:
public abstract void setDisplayShowHomeEnabled (boolean showHome)

Added in API level 11

Set whether to include the application home affordance in the action bar. Home is presented as either an activity icon or logo.

To set several display options at once, see the setDisplayOptions methods.

Parameters

showHome

true to show home, false otherwise.

See Also

·         setDisplayOptions(int)

·         setDisplayOptions(int, int)

从描述可知该方法在API Level 11(Android 3.0)中引入,若在API Level 10(Android 2.3.3)以下系统中运行该方法必然会出现因不存在该API而调用失败,进而导致软件Crash。
1.1.3 推荐方案
由于在Android系统中向下兼容性比较差,但是一个应用APP经过处理还是可以在各个版本间运行的。为了应用APP有更好的兼容性,可以利用高版本的SDK开发应用,并在程序运行时(Runtime)对应用所运行的平台判断,旧平台使用旧的API,而新平台可使用新的API,这样可以较好的提高软件兼容性。 在我们自己开发应用过程中,常常使用如下的代码形式判断运行新API还是旧的API:

private void setUpActionBar() {

           // Make sure we're running on Honeycomb or higher to use ActionBar APIs

       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {

       // 包含新API的代码块

       ActionBar actionBar = getActionBar();

       actionBar.setDisplayHomeAsUpEnabled(true);

       }

else

{

// 包含旧的API的代码块

}

}

2. 【OOM】大图片解析导致OOM的隐患
2.1.1 摘要

问题:当图片过大或图片数量较多时使用BitmapFactory解码图片会出java.lang.OutOfMemoryError: bitmap size exceeds VM budget,导致app出现Crash。

解决方案:对过大的图片进行压缩或者通过先设置缩放选项,再读取缩放的图片数据到内存,规避了内存引起的OOM。

2.1.2 示例
在下面代码中,在每一个item中加了一个imageview控件,图片的src在xml中就定好了,在添加到list中的时候报错了,异常导致app crash。

LayoutInflater inflater=getLayoutInflater();

list= new ArrayList<View>();

list.add(inflater.inflate(R.layout.item1, null));//就在这!

2.1.3 推荐方案
对过大的图片进行压缩或修改采样值BitmapFactory.Options.inSampleSize,设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize。修改如下:

BitmapFactory.Options opts= new BitmapFactory.Options();

opts. inJustDecodeBounds = true;

Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts);

……

3. 【异常】格式化数字异常未捕获的隐患
3.1.1 摘要

问题:在格式化数字时,无法将其转化为合适的数字,导致抛出NumberFormatException异常。

解决方案:在任何用到格式化数字时,捕捉异常,对异常情况进行处理。

3.1.2 示例
在下面代码中,使用Float.parseFloat对String进行格式化时,出现了NumberFormatException。

public static String formatMileage(String mAverageSpeed) {       

float mileage;

              DecimalFormat fnum = null;

              mileage = Float.parseFloat(mAverageSpeed);

              fnum = new DecimalFormat("###,###,###.##");

3.1.3 推荐方案
在任何用到格式化数字时,捕捉异常,对异常情况进行处理,修改如下:

float mileage;

              DecimalFormat fnum = null;

              try {

                     mileage = Float.parseFloat(mAverageSpeed);

                     fnum = new DecimalFormat("###,###,###.##");

              catch (Exception e) {

                     e.printStackTrace();

                     return MILEAGE_EMPTY;

    }

4. 【判空】ArrayList对象使用未判空隐患
4.1.1 摘要

问题:在Java代码实现时,定义一个ArrayList对象,并初始化为null,通过调用方法返回的ArrayList对象赋值给开始定义的对象,直接使用时可能出现java.lang.NullPointerException异常,app出现Crash。

解决方案:在使用ArrayList对象前,判断该对象是否为null,并进行异常处理。

4.1.2 示例
在下面代码中,程序调用getDataWithSeq(i).get()方法时抛出了java.lang.NullPointerException异常而导致app crash。

if(curCount>=(position+1)){

// getDataWithSeq返回null,空指针异常

return getDataWithSeq(i).get(position-(curCount-counts[i]));

}

 

public ArrayList<MylocResultListPoisPoiType> getDataWithSeq(int seq){

ArrayList<MylocResultListPoisPoiType> result = null;

       if (seq > 0) {

 result = mCacheStatus;

}

return result;

}

4.1.3 推荐方案
在对象使用前,先进行判空操作,并进行异常处理,修改如下:

if(curCount>=(position+1)){

// getDataWithSeq返回null,空指针异常

if (getDataWithSeq(i) != null) {

return getDataWithSeq(i).get(position-(curCount-counts[i]));

}

}

 

public ArrayList<MylocResultListPoisPoiType> getDataWithSeq(int seq){

ArrayList<MylocResultListPoisPoiType> result = null;

       if (seq > 0) {

 result = mCacheStatus;

}

return result;

}

5. 【越界】使用String.split结果未判断长度隐患
5.1.1 摘要

问题:在使用String.split得到的结果数组前,未对数组进行长度检查,取字段的时候可能发生越界而导致 Crash。

解决方案:在使用 split 结果数组前,添加对数组长度的判断。

5.1.2 示例
在下面代码中,由于source切分得到的结果长度为0,而直接取下标为0的字段导致越界crash。

String source = "<br/>";

String[] infos = source.split("<br/>");

String poiName = infos[0];

5.1.3 推荐方案
在使用 infos之前,先对infos的长度作检查,修改如下:

String source = "<br/>";

String[] infos = source.split("<br/>");

if(0 < infos.length){

   String poiName = infos[0];

}

6. 【判断】添加Fragment前未判断是否IsAdded隐患
6.1.1 摘要

问题:当使用FragmentTransaction调用add函数添加某个fragment时,如果该fragment已经被添加到activity,再进行添加操作会抛出Fragment already added异常。

解决方案:添加fragment前,先调用fragment.isAdded函数判断该fragment是否已经添加。

6.1.2 示例

在下面代码中,用户如果快速点击或者函数被重复执行时,如果myFragment已经被添加再进行添加操作会抛出Fragment already added异常。

if (!ret) {
         try {
           myFragment.setArguments(pageArgs);
           FragmentTransaction ftr = getSupportFragmentManager().beginTransaction();
           ftr.add(R.id.fragment_container, myFragment, ((Object) myFragment).getClass().getName() + myFragment.getPageTag());

}  

6.1.3 推荐方案

在进行执行add函数前,先调用isAdded判断myFragment是否已经被添加,修改如下:

if (!ret && !myFragment.isAdded()) {
         try {
           myFragment.setArguments(pageArgs);
           FragmentTransaction ftr = getSupportFragmentManager().beginTransaction();
           ftr.add(R.id.fragment_container, myFragment, ((Object) myFragment).getClass().getName() + myFragment.getPageTag());

}

7. 【异常】使用除法或求余没有判断分母长度隐患
7.1.1 摘要

问题:使用除法或者求余运算时,如果分母是通过调用函数返回的int,未对返回值进行判断,当返回值为0时,会出现java.lang.ArithmeticException: / by zero异常。

解决方案:调用函数前,对函数的返回值的长度进行判断。

7.1.2 示例

在下面代码中,程使用了求余运算,但调用mBoardTextList.size()前没有判断mBoardTextList的长度,如果mBoardTextList为0时就抛出了java.lang.ArithmeticException: / by zero异常而导致app crash。

text = mBoardTextList.get(mBoardIndex % mBoardTextList.size());

 

mBoardIndex++;

7.1.3 推荐方案

在进行求余运算前,先判断mBoardTextList是否为0,再进行求余运算,修改如下:

int boardListSize =mBoardTextList.size();

 

if (boardListSize > 0) {

     text = mBoardTextList.get(mBoardIndex % boardListSize);

     mBoardIndex++;

}

        

8. 【越界】使用String.substring前未判断长度隐患
8.1.1 摘要

问题:在使用String.substring时,未对字符串的长度进行检查,截取字符串时可能会发生越界而导致Crash。

解决方案:在使用 substring 前,对字符串的长度进行判断。

8.1.2 示例

在下面代码中,虽然sb不为空但是长度为0,而直接进行字符串截取导致越界crash。

String sb = new String();

String value = sb.substring(0,sb.length()-1);

 

8.1.3 推荐方案

在使用sb之前,先对sb的长度作检查,修改如下:

String sb = new String();

if( sb.length() > 0){

  String value = sb.substring(0,sb.length()-1);

}

9. 【判空】通过HashMap获取对象使用未判空隐患
9.1.1 摘要

问题:在Java代码实现时,通过Hashmap的get方法获取对象,并且不是使用Hashmap的Iterator获取,如果key不存在时获取的对象为null,在使用此对象可能出现java.lang.NullPointerException的异常,app出现Crash。

解决方案:在使用Hashmap获取的对象前,判断该对象是否为null,并进行异常处理。

9.1.2 示例
在下面代码中,程序调用mCacheStatus.get(bmmf.mId_1)方法返回的为null,因此在使用status.path时抛出了java.lang.NullPointerException异常而导致app crash。

private HashMap<Long, OfflineCacheStatus> mCacheStatus;

……

synchronized (mLatestDatas) {

       for (TestMp3MusicFile bmmf : mLatestDatas) {

              if(bmmf == nullcontinue;//add this line,question?

              status = mCacheStatus.get(bmmf.mId_1);

              // status为null,使用status.path报空指针异常

              if (!StringUtils.isEmpty(status.path)) {

                     bmmf.mPath = status.path;

              }

       }

}

9.1.3 推荐方案
在对象使用前,先进行判空操作,并进行异常处理,修改如下:

private HashMap<Long, OfflineCacheStatus> mCacheStatus;

……

synchronized (mLatestDatas) {

       for (TestMp3MusicFile bmmf : mLatestDatas) {

              if(bmmf == nullcontinue;//add this line,question?

              status = mCacheStatus.get(bmmf.mId_1);

              // status为null,使用status.path报空指针异常

if (status != null) {

                     if (!StringUtils.isEmpty(status.path)) {

                            bmmf.mPath = status.path;

                     }

}

       }

}

10. 【异常】ArrayList使用get方法获取元素未判断下标有效性的隐患
10.1.1 摘要

问题:ArrayList通过get方法使用下标获取元素,如果使用的下标不在ArrayList大小范围内,将产生java.lang.IndexOutOfBoundsException的异常,导致app出现Crash。

解决方案:在使用ArrayList的get方法获取元素时,需要判断使用的下标的有效性。

10.1.2 示例
在下面代码中,程序调用mRepliesData.get(selectedPosition)方法获取元素,因selectedPosition超出了mRepliesData.size()的范围,抛出了java.lang.IndexOutOfBoundsException异常导致app crash。

private ArrayList<Reply> mRepliesData;

public boolean onContextItemSelected(int selectedPosition) {

mRepliesAdapter = new NoteReplyAdapter(thismRepliesData);

Reply reply = mRepliesData.get(selectedPosition);

……

return super.onContextItemSelected(item);

}

10.1.3 推荐方案
在调用mRepliesData.get(selectedPosition)方法前,先判断selectedPosition是否小于mRepliesData.size()再进行方法调用,修改如下:

private ArrayList<Reply> mRepliesData;

public boolean onContextItemSelected(int selectedPosition) {

mRepliesAdapter = new NoteReplyAdapter(thismRepliesData);

if (selectedPosition < mRepliesData.size()) {

Reply reply = mRepliesData.get(selectedPosition);

}

……

return super.onContextItemSelected(item);

}

11. 【异常】使用动态载入界面的元素未判断是否属于此界面的隐患
11.1.1 摘要

问题:通过inflater.inflate(R.layout.frag_name_search,null)方法动态载入界面,然后通过findViewById获取界面元素,如果这个元素不存在此界面,再使用此元素对象的方法时将产生java.lang.NullPointerException的异常,导致app出现Crash。

解决方案:在使用元素对象时先判断元素是否为null。

11.1.2 示例
在下面代码中,程序调用inflater.inflate(R.layout.frag_name_search, null)方法动态加载界面,然后通过view.findViewById(R.id.navi_logo)获取界面元素,因R.id.navi_logo不存在于该view,抛出了java.lang. NullPointerException异常导致app crash。

View view = inflater.inflate(R.layout.frag_name_searchnull);

mHistoryLV = (ListView) view.findViewById(R.id.navi_logo);  

mHistoryLV.addHeaderView(headView);

11.1.3 推荐方案
在调用mHistoryLV.addHeaderView(headView);方法前,先判断mHistoryLV是否为null,再进行方法调用,修改如下:

View view = inflater.inflate(R.layout.frag_name_searchnull);

mHistoryLV = (ListView) view.findViewById(R.id.navi_logo);  

if(mHistoryLV != null){

mHistoryLV.addHeaderView(headView);

}

12. 【OOM】使用IO流后没有关闭导致OOM隐患
12.1.1 摘要

问题:在使用IO流进行相关操作后没关闭导致一直占用IO资源,大量流操作后没有关闭可能导致系统内存不足从而使系统抛出OOM异常。

解决方案:在使用相关IO流操作后将其关闭,如果在try-catch作用域内应在finally中关闭。

12.1.2 示例

在下面代码中,使用IO流相关操作后没有关闭导致资源占用,从而导致系统内存不足而引发OOM异常。

InputStream inputStream = httpResponse.getEntity().getContent();

inputStream.read();

  ……

 

12.1.3 推荐方案

对IO流进行操作完毕后关闭相关流,修改如下:

InputStream inputStream = null;

try {

  inputStream = httpResponse.getEntity().getContent();

   ……

} finally {

try {

if (inputStream==null) {

inputStream.close();

}

} catch (IOException e) {

e.printStackTrace();

}

13. 【异常】数据库操作异常未捕获处理隐患
13.1.1 摘要

问题:在Java程序中,调用数据库操作时,可能存在数据库连接已关闭情况(由于多线程实现不好,导致状态被改变,尽管开始可能已经进行了状态判断),导致抛出java.lang.IllegalStateException异常,此时,必须要在某个位置进行异常处理,否则该异常会层层上传,直到有代码捕获和处理该异常,可能会导致app出现crash。

解决方案:对于可能抛出异常的代码,增加try{}catch{},捕获和处理能处理的异常,对于不能处理的异常重新封装并抛给上层。(若仅仅捕获所有异常而不处理,则crash率会下降,但会掩盖程序运行错误问题)。

13.1.2 示例
在下面代码中,程序调用query方法时抛出了java.lang.IllegalStateException异常而导致app crash。

public static boolean isTableExists(String tableName) {

       Cursor cursor = database.query("sqlite_master", new String[]{"[sql]"},

              "[type] = 'table' and name = ?"new String[]{tableName}, nullnullnull);

       return cursor.getCount() == 1;

}

13.1.3 推荐方案
在可能抛出异常的方法,增加try{}catch{}捕获和处理能处理的异常,不能完整处理的重新封装异常抛给上层,修改如下:

public static boolean isTableExists(String tableName) {

try{

                     Cursor cursor = database.query("sqlite_master", new String[]{"[sql]"},

                            "[type] = 'table' and name = ?"new String[]{tableName}, nullnullnull);

}catch(Exception e){

// 处理能处理的异常,不能完整处理,重新封装异常抛给上层

}

return cursor.getCount() == 1;

}

14. 【异常】主动抛出异常未捕获处理隐患
14.1.1 摘要

问题:在Java程序中,使用throw new Exception主动抛出异常而不对异常进行捕获,会导致app出现Crash。

解决方案:对于抛出异常的代码,增加try{}catch{},捕获和处理能处理的异常,对于不能处理的异常重新封装并抛给上层。(若仅仅捕获所有异常而不处理,则crash率会下降,但会掩盖程序运行错误问题)

14.1.2 示例
在下面代码中,throw new IllegalArgumentException没有加上try catch导致app crash。

public static int compare(String version1, String version2) {

               if (version1 == 0||version2 == 0)

        throw new IllegalArgumentException("Invalid parameter!");

}

14.1.3 推荐方案
抛出异常时,需要增加try{}catch{}用于补充和处理能处理的异常,对于不能处理的异常重新封装抛给上层处理,修改如下:

public static int compare(String version1, String version2) {

   if (version1 == 0||version2 == 0){

      try{

         throw new IllegalArgumentException("Invalid parameter!");

      }catch(Exception e){

// 处理能处理的异常,不能完整处理,重新封装异常抛给上层

      }

   }

}

15. 【异常】dismiss()方法调用前isShowing未判断的隐患
15.1.1 摘要

问题:在调用系统的dismiss()方法前,没有对状态进行判断,导致抛出NullPointerException异常。

解决方案:在调用系统的dismiss()方法时,需要对状态先进行判断。

15.1.2 示例
在下面代码中,popupWindow.dismiss()调用时出现了NullPointerException。

if (mContext != null &&!((Activity)mContext).isFinishing())

{

   popupWindow.dismiss();

   setFocusable(false);

              }

15.1.3 推荐方案
在调用系统的dismiss()方法前先进行isShowing的判断,修改如下:

if (mContext != null &&!((Activity)mContext).isFinishing() && isShowing())

{

   popupWindow.dismiss();

   setFocusable(false);

              }

16. 【判空】方法中存在return null返回对象直接进行方法调用隐患
16.1.1 摘要

问题:方法中存在return null,在特定条件下触发返回return null,而对该方法的返回对象直接进方法调用将产生java.lang.NullPointerException的异常,导致app出现Crash。

解决方案:对方法中含有return null的返回对象进行直接方法调用时需要先进行判断。

16.1.2 示例
在下面代码中,程序调用getRouteNodeData().get(0)前没有判断getRouteNodeData()的返回存在null的情况,抛出了java.lang. NullPointerException的异常而导致app crash。

public ArrayList<RouteListItem> getRouteNodeData() {

           if (mRouteList.size() == 0) {

                  return null;

else {

                  return mRouteList;

          }

}

public void clearItem(){

     RouteResultManager mgr = RouteResultManager.instance(mContext);

mFocusItemIndex = mgr.getRouteNodeData().get(0);

}

16.1.3 推荐方案
在调用getRouteNodeData()方法前,先判断getRouteNodeData()是否为null,再进行方法调用,修改如下:

public ArrayList<RouteListItem> getRouteNodeData() {

           if (mRouteList.size() == 0) {

                  return null;

else {

                  return mRouteList;

          }

}

public void clearItem(){

     RouteResultManager mgr = RouteResultManager.instance(mContext);

if(mgr.getRouteNodeData() != null ){

mFocusItemIndex = mgr.getRouteNodeData().get(0);

}

}

17. 【OOM】查询数据库没有关闭游标导致OOM的隐患
17.1.1 摘要

问题:在使用Cursor对数据库进行操作后没有关闭Cursor,在常时间大量操作情况下出现OOM的问题,异常导致app crash。

解决方案:在使用Cursor对数据库进行操作完毕后关闭Cursor。

17.1.2 示例
在下面代码中,使用Cursor对数据库进行操作后没有关闭Cursor,在常时间大量操作情况下出现OOM的问题异常导致app crash。

Cursor cursor = getContentResolver().query(uri);

if (cursor.moveToNext()) {

  ……

}

17.1.3 推荐方案
对数据库进行操作完毕后关闭Cursor,修改如下:

Cursor cursor = null;

try {

  cursor = getContentResolver().query(uri);

    ……

} finally {

  if (cursor != null) {

  try { 

      cursor.close();

  } catch (Exception e) {

  }

  }

18. 【状态】销毁Dialog前是否isShowing未判断隐患
18.1.1 摘要

问题:调用Android.app.Dialog.cancel()方法前,如果这个dialog不处于showing状态时,会抛出java.lang.IllegalArgumentException的异常,导致app出现Crash。

解决方案:调用Android.app.dialog.cancel()方法前,先判断Android.app.dialog.isShowing(),为true时才进行cancel()操作。

18.1.2 示例
在下面代码中,程序调用mProgressDialog.cancel()前没有判断mProgressDialog.isShowing()抛出了java.lang.IllegalArgumentException异常而导致app crash。

public void hideProgressDialog(){

           if(mProgressDialog != null){

                  mProgressDialog.cancel();

                  mProgressDialog = null;

          }

}

18.1.3 推荐方案
在调用cancel()方法前,先判断dialog是否处于showing状态,再进行方法调用,修改如下:

public void hideProgressDialog(){

           if(mProgressDialog != null && mProgressDialog.isShowing()){

                  mProgressDialog.cancel();

                  mProgressDialog = null;

          }

}

19. 【异常】复写生命周期函数没有调用父类的super函数隐患
19.1.1 摘要

问题:继承自Activity或Fragment的类当复写相关的生命周期函数时,需要调用父类的super函数,该点在Android开发者官网有明确说明。

解决方案:复写Activity或Fragment的生命周期函数时,需调用其父类的super函数。

19.1.2 示例

在下面代码中,复写Fragment的生命周期函数没有调用其父类的super函数,导致SuperNotCalledException。

@Override

public void onDestroyView() {

// TODO Auto-generated method stub

myLinsenter.close();

...

}

 

19.1.3 推荐方案

对生命周期函数添加super函数,修改如下:

@Override

public void onDestroyView() {

// TODO Auto-generated method stub

super.onDestroyView();

myLinsenter.close();

...

}

20. 【越界】数组下标越界隐患
20.1.1 摘要

问题:采用下标的方式获取数组元素时,如果下标越界,将产生java.lang.ArrayIndexOutOfBoundsException的异常,导致app出现Crash。

解决方案:在使用下标的方式获取数组元素时,需判断下标的有效性。

20.1.2 示例

在下面代码中,程序调用getIndex()方法获取索引值,存在idx超出strArr的有效范围导致app crash的隐患。

public void func(){

String[] strArr = {"e1","e2"};

int idx = getIndex();

System.out.println(strArr[idx]); 
}

 

20.1.3 推荐方案

在调用System.out.println(strArr[idx])方法前,先判断idx 是否在有效范围内,再进行方法调用,修改如下:

public void func(){

String[] strArr = {"e1","e2"};

int idx = getIndex();

if(idx >=0 && idx < strArr.length) {

System.out.println(strArr[idx]);

}
}

 

21. 【判空】使用在intent中获取的数据前未判空隐患
21.1.1 摘要

问题:在Intent中通过诸如“getBundleExtra、getStringExtra……”获取数据时,得到的对象有可能为null,若直接使用则有可能导致app出现Crash。

解决方案:在使用此类对象前,应做判空处理。

21.1.2 示例

在下面代码中,程序调用getStringExtra("info")方法获取对象,若获取到的对象为null,则存在导致app crash的隐患。

public void func(){
    String str = intent.getStringExtra("info");

    String value = str.substring(str.indexOf(','));       
    textview.setText(value);

}

21.1.3 推荐方案

在使用该对象前,先做判空处理,修改如下:

public void func(){  

    String str = intent.getStringExtra("info");

    if(str != null && str.contains(",")){
            value str.substring(str.indexOf(','));
    }else {
            value "null";
    }
 

    String value = str.substring(str.indexOf(','));      

    textview.setText(value);

}

22. 【注册】Activity未在AndroidManifest.xml中注册隐患
22.1.1 摘要

问题:使用未在AndroidManifest.xml中注册的Activity会导致app出现Crash。

解决方案:所有用到的Activity都在AndroidManifest.xml中进行注册。

22.1.2 示例

在下面代码中,程序使用了SecondActivity,但其未在AndroidManifest.xml中注册,程序执行到此逻辑时会报android.content.ActivityNotFoundException, 导致app crash。

public void func(){
        Intent intent = new Intent();
        intent.putExtra("intentkey", "the message from main activity");
        intent.setClass(MainActivity.this, SecondActivity.class);

        MainActivity.this.startActivity(intent);

}

22.1.3 推荐方案

在AndroidManifest.xml中注册SecondActivity,如下:

     <application

        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity

            android:name=".SecondActivity"

            android:label="@string/app_name" >
        </activity>
    </application>

23. 【判空】使用Bundle与使用从Bundle获取到的数据未判空隐患
23.1.1 摘要

问题:在使用Bundle对象时,因其可能为null,若直接使用诸如“get(String key)、getString(String key)、getByte(String key)...”函数获取Bundle对象所含数据时,有可能导致app出现Crash; 使用从Bundle获取到的数据,因其可能为null,若直接使用,可能会导致app出现crash。

解决方案:使用前,应做判空检查。

23.1.2 示例

在下面代码中,程序直接调用getString("myKey")方法获取对象,若myBundle对象为null,则存在导致app crash的隐患;使用获取的value调用split函数,若value为null, 则导致app 出现crash。

Bundle myBundle = intent.getBundleExtra("myBundle");

value = myBundle.getString("myKey");

String str[]  = value.split(",");

23.1.3 推荐方案

在使用该对象前,先做判空处理和检查获取到的数据是否为空,修改如下:

 Bundle myBundle = intent.getBundleExtra("myBundle"); 

if(myBundle != null ){

       value = myBundle.getString("myKey");

}else{

      //... 

}


if(value != null){

    String str[]  = value.split(",");

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值