4

I am new to android and i try to develop a system but when i finish code the handler show this warning

below show the code after I edit, the handler in event ontounch show the warning handler cannot be resolved. I try putting // to ignore the handler at i try run the application and its result in force close.

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;
}
}
Raghunandan
  • 132,755
  • 26
  • 225
  • 256
chu kokwann
  • 45
  • 1
  • 7
  • make your handler class static. http://stackoverflow.com/questions/3106912/why-does-android-prefer-static-classes – Raghunandan Jul 27 '13 at 15:19
  • Declare `HanderClass hc` as a class member. then in onCreate replace `new HandlerClass(this);` by `hc = new HandlerClass(this);`. And instead of `handler.sendMessage` use `hc.sendMessage`. – Raghunandan Jul 28 '13 at 11:09

2 Answers2

10

Make your handler a static class.

The warning is a lint warning. You can disable the warning but its a useful info

Here's a list of Lint Check

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

Quoting from the source @

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

Avoid non-static inner classes in an activity if you don't control their life cycle, use a static inner class and make a weak reference to the activity inside.

The solution to this issue is to use a static inner class with a WeakReference to the outer class, as done in ViewRoot and its W inner class for instance.

Also check this discussion on android developers group. Check the solution by Romain Guy

https://groups.google.com/forum/#!topic/android-developers/1aPZXZG6kWk

Example from Romain Guy's solution from the above link

 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(); 
   }

Edit:

Example:

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);

            }

        };
}

Correct me if the above is wrong or has some issues.

You can also check this blog by Alex Lockwood

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

Raghunandan
  • 132,755
  • 26
  • 225
  • 256
  • i try the Romain guy's solution from the link you given at the end of the line 'if(target !=null) target.do()' the do occur error message Syntax error on token "do", super expected
    howcome this is happening ??
    – chu kokwann Jul 28 '13 at 09:15
  • @chukokwann and what's wrong with that?. it should work. post your updated code. – Raghunandan Jul 28 '13 at 09:17
  • how come I can't comment in code format even i put 'code' ''public class MainActivity extends Activity { private Handler handler = new Handler() { private final WeakReference mTarget; Handler(MainActivity target) { mTarget = new WeakReference(target); } void doSomething(){ MainActivity target = mTarget.get(); if (target != null ) target.do(); } public void handleMessage(Message msg) { super.handleMessage(msg); if(msg.what==STOP){ ll.removeAllViews(); anim.stop(); } } }; '' – chu kokwann Jul 28 '13 at 09:23
  • @chukokwann try as the edited post. also check the last link posted in the answer. – Raghunandan Jul 28 '13 at 09:24
  • after I edit the code the handler warning disappear but the handler I use in my ontouch event pop out handler cannot be resolved warning – chu kokwann Jul 28 '13 at 09:59
  • erm how to add code in the comment ?? i try use 'code' but fail to post code like what you did – chu kokwann Jul 28 '13 at 10:46
  • don't post code in comment edit your question put it under edit section. – Raghunandan Jul 28 '13 at 10:48
  • sorry never think of it i first time post question here sorry for any inconvenience. I edit the code in my question already. – chu kokwann Jul 28 '13 at 10:55
  • @chukokwann Declare `HanderClass hc` as a class member. then in `onCreate` replace `new HandlerClass(this);` by `hc = new HandlerClass(this);`. And instead of `handler.sendMessage` use `hc.sendMessage`. – Raghunandan Jul 28 '13 at 11:05
  • thank you so much it works for it finally. been struggle for this problem for quite long. Really thanks a lot. – chu kokwann Jul 28 '13 at 11:37
1

When you define an anonymous inner class like that, the class itself is redefined for every instance of MainActivity. Apparently, the Android SDK flags that as having the potential to leak those class definitions. The simplest solution is to make it a static inner class that takes a reference to MainActivity in the constructor:

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 }
    }
}
Thorn G
  • 12,620
  • 2
  • 44
  • 56
  • after I edit the code it occur Illegal modifier for the local class MainHandler; only abstract or final is permitted at the mainhandler and Cannot make a static reference to the non-static field happen in the handlerMessage I try change to private static LinearLayout ll; but still cant fix it below show the code after edit – chu kokwann Jul 28 '13 at 06:05
  • `public class MainActivity extends Activity { private Handler handler = new Handler() { 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) { } ll.setOrientation(LinearLayout.VERTICAL); } } };` howcome I cnat comment code line like Tom G did even i already put ` code ` – chu kokwann Jul 28 '13 at 06:20
  • @Raghunandan I try the method tom G suggest and after that it pop up a illegal modifier for the local class mainhandler, only abstratc or final is permitted. and the value declare and use in the handleMessage have to change to static value – chu kokwann Jul 28 '13 at 08:57