Android - Activity 泄露了 IntentReceiver

Posted

技术标签:

【中文标题】Android - Activity 泄露了 IntentReceiver【英文标题】:Android - Activity has leaked IntentReceiver 【发布时间】:2012-05-22 22:19:02 【问题描述】:

我正在编写非常简单的应用程序。它工作正常,但是当我按下后退键时它崩溃(Activity 泄露了最初在此处注册的 IntentReceiver)。这个应用程序应该在后台运行。怎么做才合适?

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ProgressBar;
import android.widget.RadioButton;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;

public class Bateria extends Activity implements OnClickListener, OnSeekBarChangeListener 

    ProgressBar pbBatteryLevel;
    TextView tvBatteryLevel;
    TextView tvLeft;
    RadioButton rbPercent;
    RadioButton rbTime;
    SeekBar sbSetLeft;
    boolean percent; // true - percent, false - time
    boolean informed;
    int progress;
    int MAX_TIME;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 

        PowerManager pM = (PowerManager) getSystemService(Context.POWER_SERVICE);
        WakeLock wL = pM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "whatever");
        long HOURS24 = 86400000;

        super.onCreate(savedInstanceState);

        wL.acquire(HOURS24);

        setContentView(R.layout.main);

        initialize();
    

    @Override
    protected void onResume() 
        // TODO Auto-generated method stub
        super.onResume();
        registerReceiver(batteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
    

    private void initialize() 
        // TODO Auto-generated method stub
        SharedPreferences preferences = getSharedPreferences("SP_BATTERY", 0);
        percent = preferences.getBoolean("percent", true);
        progress = preferences.getInt("progress", 0);
        informed = false;

        MAX_TIME = 72*60;

        pbBatteryLevel = (ProgressBar) findViewById(R.id.pbBatteryLevel);
        tvBatteryLevel = (TextView) findViewById(R.id.tvBatteryLevel);
        tvBatteryLevel.setTextSize(20);
        tvLeft = (TextView) findViewById(R.id.tvLeft);
        if(percent)
            tvLeft.setText(String.valueOf(progress) + " %");
        else
            int minutes = MAX_TIME*progress/100;
            int hours = minutes / 60;
            minutes -= hours*60;
            tvLeft.setText(String.valueOf(hours) + "h " + String.valueOf(minutes) + "min");
        
        rbPercent = (RadioButton) findViewById(R.id.rbPercent);
        rbPercent.setOnClickListener(this);
        rbPercent.setChecked(percent);
        rbTime = (RadioButton) findViewById(R.id.rbTime);
        rbTime.setOnClickListener(this);
        rbTime.setChecked(!percent);

        sbSetLeft = (SeekBar) findViewById(R.id.sbSetPercent);
        sbSetLeft.setOnSeekBarChangeListener(this);
        sbSetLeft.setProgress(progress);

        registerReceiver(batteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
    

    private BroadcastReceiver batteryInfoReceiver = new BroadcastReceiver() 

        @Override
        public void onReceive(Context c, Intent i) 
            int level = i.getIntExtra("level", 0);
            int voltage = i.getIntExtra("voltage", 0);
            int temperature = i.getIntExtra("temperature", 0);
            pbBatteryLevel.setProgress(level);
            tvBatteryLevel.setText("Battery Level: " + Integer.toString(level)
                    + "%" + "\n" + voltage + " mV " + temperature + " C");
            if(level < progress && !informed)
                //////////
                Toast.makeText(getApplicationContext(), "BATTERY", Toast.LENGTH_LONG).show();
                MediaPlayer mp = MediaPlayer.create(Bateria.this, R.raw.explosion);
                mp.start();
                //////////
                informed = true;
            
            else if(level >= progress)
                informed = false;
            
        
    ;

    public void onClick(View v) 
        // TODO Auto-generated method stub
        switch(v.getId())
        case(R.id.rbPercent):
            percent = true;
            tvLeft.setText(String.valueOf(progress) + " %");
            break;
        case(R.id.rbTime):
            percent = false;
            int minutes = MAX_TIME*progress/100;
            int hours = minutes / 60;
            minutes -= hours*60;
            tvLeft.setText(String.valueOf(hours) + "h " + String.valueOf(minutes) + "min");
            break;
        

        SharedPreferences preferences = getSharedPreferences("SP_BATTERY", 0);
        SharedPreferences.Editor editor = preferences.edit();
        editor.putBoolean("percent", percent);
        editor.commit();
    

    public void onProgressChanged(SeekBar seekBar, int progress,
            boolean fromUser) 
        // TODO Auto-generated method stub
        if(percent)
            tvLeft.setText(String.valueOf(progress) + " %");
        else
            int minutes = MAX_TIME*progress/100;
            int hours = minutes / 60;
            minutes -= hours*60;
            tvLeft.setText(String.valueOf(hours) + "h " + String.valueOf(minutes) + "min");
        

        this.progress = progress;
        SharedPreferences preferences = getSharedPreferences("SP_BATTERY", 0);
        SharedPreferences.Editor editor = preferences.edit();
        editor.putInt("progress", progress);
        editor.commit();
        informed = false;
    

    public void onStartTrackingTouch(SeekBar seekBar) 
        // TODO Auto-generated method stub

    

    public void onStopTrackingTouch(SeekBar seekBar) 
        // TODO Auto-generated method stub

    

    @Override
    public boolean onCreateOptionsMenu(Menu menu) 
        // TODO Auto-generated method stub
        super.onCreateOptionsMenu(menu);
        MenuInflater blowUp = getMenuInflater();
        blowUp.inflate(R.menu.menu, menu);
        return true;
    

    @Override
    public boolean onOptionsItemSelected(MenuItem item) 
        // TODO Auto-generated method stub
        System.exit(0);
        return false;
    

【问题讨论】:

【参考方案1】:

首先,您需要根据需要取消注册已注册的 BroadcastReceiver。更多信息请看这里:http://developer.android.com/reference/android/content/BroadcastReceiver.html

更重要的是,你不能仅仅通过开发一个 Activity 来开发一个在后台运行的应用程序。您需要为此开发服务。检查此链接以获取有关如何执行此操作的说明以及 API 文档:http://developer.android.com/reference/android/app/Service.html

【讨论】:

以上是关于Android - Activity 泄露了 IntentReceiver的主要内容,如果未能解决你的问题,请参考以下文章

Activity 泄露了原本绑定在这里的 ServiceConnection com.google.android.youtube.player

Activity 泄露了原本绑定在这里的 ServiceConnection com.google.android.youtube.player

Activity 已泄露窗口 - Android

Activity 泄露了 IntentReceiver - LollipopBrowserAccessibilityManager

Android内存泄露

Android中使用Handler造成内存泄露的分析和解决