Этот класс обработчика должен быть статическим, иначе могут возникнуть утечки (com.test.test3.ui.MainActivity.1)

Я новичок в Android, и я пытаюсь разработать систему, но когда я заканчиваю код, обработчик показывает это предупреждение

ниже показывает код после того, как я отредактировал, обработчик в событии ontounch показывает, что обработчик предупреждений не может быть разрешен. Я пытаюсь положить //, чтобы игнорировать обработчик при попытке запустить приложение и его результат принудительно закрывается.

public class MainActivity extends Activity {



protected static final int STOP = 100;
ImageView iv;
private ProgressBar pb;
LinearLayout ll;
private AnimationDrawable anim;
ScrollView sv;
private SQLiteDatabase db;
private boolean flagscanning = false;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ll = new LinearLayout(this);
    new HandlerClass(this);

            db = SQLiteDatabase.openDatabase(Environment.getExternalStorageDirectory()+"/antivirus.sqlite", null, SQLiteDatabase.OPEN_READONLY);  
            iv = (ImageView) this.findViewById(R.id.imageView1);
                    //扫描病毒进度条
            pb = (ProgressBar) this.findViewById(R.id.progressBar1);
            ll = (LinearLayout) this.findViewById(R.id.ll);
                    //设置ImageView背景资源为动画文件
            iv.setBackgroundResource(R.drawable.bg);
                    //sv用来显示病毒的扫描结果
            sv = (ScrollView) this.findViewById(R.id.scrollView1);
            anim = (AnimationDrawable) iv.getBackground();
}

private static class HandlerClass extends Handler{
    private final WeakReference<MainActivity> mTarget;
    public HandlerClass(MainActivity context){
        mTarget = new WeakReference<MainActivity>((MainActivity) context);
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        MainActivity target = mTarget.get();
         if(msg.what==STOP){
             target.ll.removeAllViews();
             //anim.stop();

             }
         String str = (String) msg.obj; 
         TextView tv = new TextView(target);
         tv.setText(str);
         target.ll.setOrientation(LinearLayout.VERTICAL);
         target.ll.addView(tv);
         //sv.scrollBy(0, 20);

        System.out.println(str);

    }
};


@Override
public boolean onTouchEvent(MotionEvent event) {
    //如果程序正在杀毒过程中,拒绝再次启动杀毒线程
    if(flagscanning){
        return false;
    }

    //如果用户触摸屏幕,则开启杀毒线程  
    if (event.getAction() == MotionEvent.ACTION_UP) {
        flagscanning= true;
        anim.start();
        new Thread() {
            public void run() {
                // 获取每一个应用程序的签名,签名须与数据库的签名想比较
                List<PackageInfo> infos = getPackageManager()
                        .getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_SIGNATURES);
                //设置进度条的扫描范围
                pb.setMax(infos.size());
                int total = 0;
                int virustotal = 0;//设置初始病毒数为0
                for (PackageInfo info : infos) {
                    total++;
                    try {
                        sleep(20);//只为便于观察扫描效果和进度,无实质作用
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Message msg = Message.obtain();
                    msg.obj = "正在扫描" + info.packageName;
                    _handler.sendMessage(msg);_
                    Signature[] signs = info.signatures;
                    String str = signs[0].toCharsString();

                    String md5 = MD5Encoder.encode(str);
                    //将应用程序签名与数据库中保存的签名进行比较,如果相一致,则使病毒数加1,并通过handler在界面显示病毒包名
                    Cursor cursor = db.rawQuery("select desc from datable where md5=?",new String[] { md5 });
                    if (cursor.moveToFirst()) {
                        String desc = cursor.getString(0);
                        msg = Message.obtain();
                        msg.obj = info.packageName + ": " + desc;
                        _handler.sendMessage(msg);_
                        virustotal++;
                    }
                    cursor.close();
                    pb.setProgress(total);

                }
                Message msg = Message.obtain();
                msg.what = STOP;
                msg.obj = "扫描完毕 ,共发现" + virustotal + "个病毒";
                _handler.sendMessage(msg);_
                flagscanning = false;
                pb.setProgress(0);
            };
        }.start();
    }
    return super.onTouchEvent(event);
}

@Override
protected void onDestroy() {
    if (db.isOpen())
        db.close();
    super.onDestroy();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}
}

2 ответа

Решение

Сделайте ваш обработчик статическим классом.

Предупреждение - это предупреждение. Вы можете отключить предупреждение, но это полезная информация

Вот список Lint Check

http://tools.android.com/tips/lint-checks

Цитирование из источника @

http://android-developers.blogspot.in/2009/01/avoiding-memory-leaks.html

Избегайте нестатических внутренних классов в деятельности, если вы не контролируете их жизненный цикл, используете статический внутренний класс и даете слабую ссылку на внутреннюю деятельность.

Решением этой проблемы является использование статического внутреннего класса с WeakReference к внешнему классу, как сделано в ViewRoot и его внутренний класс W, например.

Также проверьте это обсуждение на группе разработчиков Android. Проверьте решение от Romain Guy

https://groups.google.com/forum/

Пример решения Ромена Гая по ссылке выше

 class OuterClass { 
 class InnerClass { 
  private final WeakReference<OuterClass> mTarget; 

   InnerClass(OuterClass target) { 
    mTarget = new WeakReference<OuterClass>(target); 
  } 

  void doSomething() { 
  OuterClass target = mTarget.get(); 
  if (target != null) target.do(); 
   }

Редактировать:

Пример:

public class MainActivity extends Activity {

      LinearLayout ll;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ll = new LinearLayout(this);
        new HandlerClass(this);
    }
       private static class HandlerClass extends Handler{
           private final WeakReference<MainActivity> mTarget; 
        public HandlerClass(MainActivity context)
        {
             mTarget = new WeakReference<MainActivity>((MainActivity) context);

        }

            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                MainActivity target = mTarget.get(); 
                if (target != null) 
                 if(msg.what==1){
                     target.ll.removeAllViews();
                    // anim.stop();

                     }
                 String str = (String) msg.obj;
                 TextView tv = new TextView(target);
                 tv.setText(str);
                 target.ll.setOrientation(LinearLayout.VERTICAL);
                 target.ll.addView(tv);
                 //sv.scrollBy(0, 20);

                System.out.println(str);

            }

        };
}

Поправьте меня, если вышеприведенное неверно или имеет некоторые проблемы.

Вы также можете проверить этот блог Алекс Локвуд

http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html

Когда вы определяете анонимный внутренний класс таким образом, сам класс переопределяется для каждого экземпляра MainActivity, По всей видимости, Android SDK помечает, что имеет потенциал утечки этих определений классов. Самое простое решение - сделать его статическим внутренним классом, который принимает ссылку на MainActivity в конструкторе:

public class MainActivity extends Activity {
    //Fields and methods of MainActivity...
    private static final class MainHandler extends Handler {
        private final MainActivity caller;
        private MainHandler(final MainActivity caller) { this.caller = caller; }
        @Override public void handleMessage(Message msg) { //Your existing logic }
    }
}
Другие вопросы по тегам