2013-07-27 3 views
3

저는 Android를 처음 사용하기 때문에 시스템을 개발하려고하지만 코드를 완료하면 처리기가이 경고를 표시합니다.이 처리기 클래스는 정적이거나 누수가 발생할 수 있습니다 (com.test.test3.ui.MainActivity.1)

아래의

아래 코드를 편집하면 경고 핸들러를 확인할 수 없다는 이벤트 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; 
} 
} 
+0

이 핸들러 클래스는 정적 만들 알렉스 록우드에 의해이 블로그를 확인할 수 있습니다. http://stackoverflow.com/questions/3106912/why-does-android-prefer-static-classes – Raghunandan

+0

'HanderClass hc'을 클래스 멤버로 선언하십시오. onCreate는'new HandlerClass (this);를'hc = new HandlerClass (this); '로 대체한다. 그리고'handler.sendMessage' 대신'hc.sendMessage'를 사용하십시오. – Raghunandan

답변

10

이 핸들러 정적 클래스 확인 : 가장 간단한 해결책은 생성자에서 MainActivity에 대한 참조를 취하는 정적 내부 클래스 확인하는 것입니다.

경고는 보푸라기 경고입니다. 당신은 비 정적 내부 클래스를 피

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

@ 소스에서 인용 린트의 목록

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

을 확인있어 여기

경고하지만 유용한 정보를 해제 할 수 있습니다 라이프 사이클을 제어하지 않으면 정적 활동을 사용하고 정적 내부 클래스를 사용하고 내부 활동을 약하게 참조하십시오.

이 문제를 해결하려면 ViewRoot과 그 내부 클래스 인 예를 들어 외부 클래스에 WeakReference의 정적 내부 클래스를 사용하는 것이 좋습니다.

또한 android developers group에서이 토론을 확인하십시오.

예 : 다음 경우

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

      } 

     }; 
} 

저를 수정

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

편집 위의 링크에서 로맹 사람에 의해 로맹 가이의 솔루션에서

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

예 솔루션을 확인 위의 내용이 잘못되었거나 문제가 있습니다.

는 또한

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

+0

나는 당신이 줄의 끝에 주어진 링크에서 Romain 녀석의 해결책을 시도한다 'if (target! = null) target.do()'오류 메시지 발생 토큰 "do"에 대한 구문 오류, super expected
howcome this 이 일어나고있다 ?? –

+0

@ chukokwann 그리고 그게 뭐가 잘못 됐어?. 작동해야합니다. 업데이트 된 코드를 게시하십시오. 내가 코드 형식으로 말씀 드릴 수 없습니다 오는 방법 – Raghunandan

+0

심지어 내가 공용 클래스 MainActivity가 { \t \t \t \t 개인 처리기 처리기 = 새로운 핸들러() { \t \t 민간 최종 WeakReference를 <활동을 확장 '코드' ''넣어 MainActivity> mTarget; \t \t \t \t 처리기 (MainActivity 타겟) { \t \t \t mTarget = 새로운 WeakReference를 (표적); \t \t \t \t} \t \t 무효 해봐요() { \t \t \t MainActivity 타겟 mTarget.get =(); \t \t \t if (target! = null) target.해야 할 것(); \t \t \t \t} \t \t \t 공개 무효 handleMessage (메시지 MSG) { \t \t \t super.handleMessage (MSG); \t \t \t 경우 (msg.what == STOP) { \t \t \t ll.removeAllViews(); \t \t \t \t anim.stop(); \t \t \t \t \t \t \t \t} \t \t \t \t \t} \t \t \t }; '' –

1

, 클래스 자체는 MainActivity의 모든 인스턴스에 대해 다시 정의됩니다. Android SDK는 이러한 클래스 정의가 누출 될 가능성이 있음을 나타냅니다.

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 } 
    } 
} 
+0

코드를 편집 한 후 로컬 클래스의 잘못된 수정 자 MainHandler; 추상 또는 final 만 메인 핸들러에서 허용되며 handlerMessage에서 비 정적 필드에 대한 정적 참조를 만들 수 없습니다. private static LinearLayout으로 변경하려고합니다 .ll; 공용 클래스 MainActivity가 활동을 확장' –

+0

편집 후 여전히 캔트는 아래의 코드를 보여 수정 { \t \t 개인 처리기 처리기 = 새로운 핸들러() { \t 개인 정적 최종 클래스 MainHandler는 핸들러 { \t \t 민간 최종 MainActivity 발신자를 확장; \t \t 개인 MainHandler (최종 MainActivity 호출자) { \t \t \t this.caller = caller; \t \t \t \t} \t \t \t \t @Override 공개 무효 handleMessage (메시지 MSG) {} \t \t \t \t ll.setOrientation (LinearLayout.VERTICAL); \t \t \t \t \t} \t \t \t} \t \t}'나는 톰 G와 같은 주석 코드 라인이 뭐가 잘못 @chukokwann도 이미 넣어'코드' –

+0

했다 CNAT howcome? – Raghunandan