Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

razrjay/AndroidCommonBug

Open more actions menu
 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
6 Commits
 
 
 
 
 
 
 
 

Repository files navigation

android常见bug及解决方案总结

空指针

解决方案
  • 不确定对象在使用前先做是否为空判断
  • 特别注意:fragment getActivity为null处理

数组越界

解决方案
  • 使用索引值获取对象值时,需判断索引值是否小于数据源大小 example:
if (mData != null && mData.size() !=0 && i < mData.size()){
  Obj obj = mData.get(i);
}

ListView或RecycleView 更新数据源命令不同步

解决方案
  • 保证设置数据源和执行adapter.notifyDataSetChanged在同一个线程并且在Ui线程 example:
adapter.setData(mData);
adapter.notifyDataSetChanged();

Windows无页面附加(Unable to add window.....is your activity running?)

解决方案
  • 执行windows窗体Dialog或PopupWindow时,先判断当前页面是否销毁,若页面还在则可以执行窗体显示操作,可以通过全局变量或activity自定义堆栈管理判断当前页面是否销毁,在onDestory里面做关闭窗体操作并置空 example:
@Override
protected void onDestroy() {    
if (mDialog != null && mDialog.isShowing()){        
mDialog.dismiss();        
mDialog = null;    
}    
super.onDestroy();
}

sqlite问题(数据库缺字段或执行过程异常)

解决方案

升级sqlite方法里面添加字段处理,此时记得加入try catch处理方式,防止出现崩溃现象。 example:

FinalDb.DaoConfig daoConfig = new FinalDb.DaoConfig();
daoConfig.setContext(this);
daoConfig.setDbName(ChatDao.DATABASE_NAME);
daoConfig.setDebug(true);
daoConfig.setDbVersion(ChatDao.DATABASE_VERSION_CODE);
daoConfig.setDbUpdateListener(new FinalDb.DbUpdateListener() {
			@Override
			public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
				// 当之前版本的数据升级到新版版本的数据,我们需要给对应表增加新的字段
				try {
					// 添加字段has_appraised字段
					db.execSQL(ChatDao.VERSION_3_SQL_ADD_COLUMN_HAS_PRAISED);
				}
				catch (Exception e){
					e.printStackTrace();
				}

				try {
					// 添加字段receiveDate字段
					db.execSQL(ChatDao.VERSION_4_SQL_ADD_CLUMN_RECEIVE_DATE);
				}
				catch (Exception e){
					e.printStackTrace();
				}
			}
		});
FinalDb.create(daoConfig);

OOM(内存溢出)

情况一

处理bitmap资源不得当造成(压缩或者变换得到新bitmap)

解决方案

采用try catch处理方式,若出现异常再做压缩,期间采用弱引用方式处理。 example:

        WeakReference<Bitmap> bitmapWeakReference;
    	// First decode with inJustDecodeBounds=true to check dimensions
		final BitmapFactory.Options options = new BitmapFactory.Options();
		try {
			options.inJustDecodeBounds = true;
			BitmapFactory.decodeFileDescriptor(fd, null, options);

			// Calculate inSampleSize
			options.inSampleSize = calculateInSampleSize(options, reqWidth,
					reqHeight);

			// Decode bitmap with inSampleSize set
			options.inJustDecodeBounds = false;
			// 弱引用处理图片 add leibing 2016/12/8
			bitmapWeakReference
					= new WeakReference<Bitmap>(BitmapFactory.decodeFileDescriptor(fd, null, options));
			if (bitmapWeakReference != null && bitmapWeakReference.get() != null)
				return bitmapWeakReference.get();
		}catch (OutOfMemoryError ex){
			// 压缩图片指定值 add by leibing 2016/12/8
			options.inSampleSize = options.inSampleSize + 4;
			options.inJustDecodeBounds = false;
			// 弱引用处理图片 add leibing 2016/12/8
			bitmapWeakReference
					= new WeakReference<Bitmap>(BitmapFactory.decodeFileDescriptor(fd, null, options));
			if (bitmapWeakReference != null && bitmapWeakReference.get() != null)
				return bitmapWeakReference.get();
		}

情况二

各种内存泄漏问题造成,主要有以下:

单例造成的内存泄露
解决方案

1、将该属性的引用方式改为弱引用; 2、如果传入Context,使用ApplicationContext; example 泄漏代码片段

    // sington
    private static InstanceClass instance;
    // activity refer
    private Context mContext;
    
    /**
     * set activity refer
     * @author leibing
     * @createTime 2016/12/9
     * @lastModify 2016/12/9
     * @param mContext activity refer
     * @return
     */
    public void setRefer(Context mContext){
        this.mContext = mContext;
    }
    
    /**
     * constructor
     * @author leibing
     * @createTime 2016/12/9
     * @lastModify 2016/12/9
     * @param
     * @return
     */
    private InstanceClass(){
    }

    /**
     * sington
     * @author leibing
     * @createTime 2016/12/9
     * @lastModify 2016/12/9
     * @param
     * @return
     */
    public static InstanceClass getInstance(){
        if (instance == null){
            synchronized (InstanceClass.class){
                if (instance == null)
                    instance = new InstanceClass();
            }
        }

        return instance;
    }

Solution:使用WeakReference

    // sington
    private static InstanceClass instance;
    // activity refer
    private WeakReference<Context> mContextWeakRef;

    /**
     * set activity refer
     * @author leibing
     * @createTime 2016/12/9
     * @lastModify 2016/12/9
     * @param mContext activity refer
     * @return
     */
    public void setRefer(Context mContext){
        mContextWeakRef = new WeakReference<Context>(mContext);
    }
    
    /**
     * constructor
     * @author leibing
     * @createTime 2016/12/9
     * @lastModify 2016/12/9
     * @param
     * @return
     */
    private InstanceClass(){
    }

    /**
     * sington
     * @author leibing
     * @createTime 2016/12/9
     * @lastModify 2016/12/9
     * @param
     * @return
     */
    public static InstanceClass getInstance(){
        if (instance == null){
            synchronized (InstanceClass.class){
                if (instance == null)
                    instance = new InstanceClass();
            }
        }

        return instance;
    }
InnerClass匿名内部类
解决方案

1、将内部类变成静态内部类; 2、如果有强引用Activity中的属性,则将该属性的引用方式改为弱引用; 3、在业务允许的情况下,当Activity执行onDestory时,结束这些耗时任务; example 泄漏代码片段

public class InnerClassActivity extends Activity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // start a thread to work
        new InnerThread().start();
    }
    
    /**
     * @interfaceName: InnerThread
     * @interfaceDescription: custom thread
     * @author: leibing
     * @createTime: 2016/12/9
     */
    class InnerThread extends Thread{
        @Override
        public synchronized void start() {
            super.start();
        }

    }
}

Solution:使用WeakReference + static

public class InnerClassActivity extends Activity{
    // 图片资源
    private Drawable mDrawable;
    // inner thread
    private InnerThread mInnerThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // init drawable
        mDrawable = getResources().getDrawable(R.drawable.ic_launcher);
        // start a thread to work
        mInnerThread = new InnerThread(mDrawable);
        mInnerThread.start();
    }
    
    @Override
    protected void onDestroy() {
        if (mInnerThread != null)
            mInnerThread.setIsRun(false);
        super.onDestroy();
    }
    
    /**
     * @interfaceName: InnerThread
     * @interfaceDescription: custom thread
     * @author: leibing
     * @createTime: 2016/12/9
     */
    static class InnerThread extends Thread{
        // weak ref
        public WeakReference<Drawable> mDrawableWeakRef;
        // is run
        private boolean isRun = true;

        /**
         * constructor
         * @author leibing
         * @createTime 2016/12/9
         * @lastModify 2016/12/9
         * @param mDrawable 图片资源(存在对页面的引用风险)
         * @return
         */
        public InnerThread(Drawable mDrawable){
          mDrawableWeakRef = new WeakReference<Drawable>(mDrawable);
        }
        
        /**
         *  set is run
         * @author leibing
         * @createTime 2016/12/9
         * @lastModify 2016/12/9
         * @param isRun
         * @return
         */
        public void setIsRun(boolean isRun){
            this.isRun = isRun;
        }

        @Override
        public void run() {
            while (isRun){
                // do work
                try {
                    // sleep one second
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public synchronized void start() {
            super.start();
        }
    }
}

#####Activity Context 的不正确使用

解决方案

1、使用ApplicationContext代替ActivityContext,因为ApplicationContext会随着应用程序的存在而存在,而不依赖于activity的生命周期; 2、对Context的引用不要超过它本身的生命周期,慎重的对Context使用“static”关键字。Context里如果有线程,一定要在onDestroy()里及时停掉。 example 泄漏代码片段

public class DrawableActivity extends Activity{
    // static drawable 
    private static Drawable leakDrawable;
    
    @Override
    protected void onCreate(Bundle state) {
        super.onCreate(state);
        TextView label = new TextView(this);
        // init drawable
        if (leakDrawable == null) {
            leakDrawable = getResources().getDrawable(R.drawable.ic_launcher);
        }
        // view set drawable
        label.setBackgroundDrawable(leakDrawable);
        
        setContentView(label);
    }
}

Solution:

public class DrawableActivity extends Activity{
    // static drawable
    private static Drawable leakDrawable;

    @Override
    protected void onCreate(Bundle state) {
        super.onCreate(state);
        TextView label = new TextView(this);
        // init drawable
        if (leakDrawable == null) {
            leakDrawable = getApplicationContext().getResources().getDrawable(R.drawable.ic_launcher);
        }
        // view set drawable
        label.setBackgroundDrawable(leakDrawable);

        setContentView(label);
    }
}
Handler引起的内存泄漏
解决方案

1、可以把Handler类放在单独的类文件中,或者使用静态内部类便可以避免泄露; 2、如果想在Handler内部去调用所在的Activity,那么可以在handler内部使用弱引用的方式去指向所在Activity.使用Static + WeakReference的方式来达到断开Handler与Activity之间存在引用关系的目的。 example 泄漏代码片段

public class HandlerActivity extends Activity{
    // custom handler
    private CustomHandler mHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // init custom handler
        mHandler = new CustomHandler();
        // sendMsg
        Message msg = new Message();
        mHandler.sendMessage(msg);
    }
    
    /**
     * @interfaceName: CustomHandler
     * @interfaceDescription: custom handler
     * @author: leibing
     * @createTime: 2016/12/9
     */
    class CustomHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    }
}

Solution(static + weakRef):

public class HandlerActivity extends Activity{
    // custom handler
    private CustomHandler mHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // init custom handler
        mHandler = new CustomHandler(this);
        // sendMsg
        Message msg = new Message();
        mHandler.sendMessage(msg);
    }

    /**
     * @interfaceName: CustomHandler
     * @interfaceDescription: custom handler
     * @author: leibing
     * @createTime: 2016/12/9
     */
    static class CustomHandler extends Handler{
        // weak ref
        private WeakReference<Context> mContextWeakRef;
        
        /**
         * constructor
         * @author leibing
         * @createTime 2016/12/9
         * @lastModify 2016/12/9
         * @param mContext activity ref
         * @return
         */
        public CustomHandler(Context mContext){
            mContextWeakRef = new WeakReference<Context>(mContext);    
        }
        
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (mContextWeakRef != null && mContextWeakRef.get() != null){
                // do work
            }
        }
    }
}
注册监听器的泄漏
解决方案

1、使用ApplicationContext代替ActivityContext; 2、在Activity执行onDestory时,调用反注册;

Cursor,Stream没有close,View没有recyle;
解决方案

资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。它们的缓冲不仅存在于 java虚拟机内,还存在于java虚拟机外。如果我们仅仅是把它的引用设置为null,而不关闭它们,往往会造成内存泄漏。因为有些资源性对象,比如SQLiteCursor(在析构函数finalize(),如果我们没有关闭它,它自己会调close()关闭),如果我们没有关闭它,系统在回收它时也会关闭它,但是这样的效率太低了。因此对于资源性对象在不使用的时候,应该调用它的close()函数,将其关闭掉,然后才置为null. 在我们的程序退出时一定要确保我们的资源性对象已经关闭。

集合中对象没清理造成的内存泄漏
解决方案

在Activity退出之前,将集合里的东西clear,然后置为null,再退出程序。

private List<String> mData;    
public void onDestory() {        
    if (mData!= null) {
        mData.clear();
        mData= null;
    }
}
WebView造成的泄露
解决方案

为webView开启另外一个进程,通过AIDL与主线程进行通信,WebView所在的进程可以根据业务的需要选择合适的时机进行销毁,从而达到内存的完整释放。

类型转换错误

解决方案

首先判断类型转换前数据是否符合转化后的数据再做处理。 example: 字符串转整型数字 首先判断字符串是否为数字字符串,然后再转换,此时最好加上try catch处理,防止崩溃。

以上是笔者在项目中遇到的常见bug以及解决方案,如有不足,请补充。

关于作者

About

android常见bug及解决方案总结

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published
Morty Proxy This is a proxified and sanitized view of the page, visit original site.