Activity 已泄露窗口,Dialog

Posted

技术标签:

【中文标题】Activity 已泄露窗口,Dialog【英文标题】:Activity has leaked window, Dialog 【发布时间】:2016-06-26 20:00:14 【问题描述】:

我有一个包含设备列表的活动A,当我单击此列表中的某个项目时,另一个活动称为(活动B)。

activityB是一个tabActivity,使用viewPager来展示不同的fragment。 Activity 有一个 MenuItem 来检查设备。单击 MenuItem 时会出现一个对话框。但是我创建了另一个类来显示对话框,因为我希望这个对话框显示在不同的片段中。

问题是,Dialog 出现了,但是 Activity 泄漏了,然后结束了。

怎么办?

活动B:

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.tab_activity);

    toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    equipment = (Equipment) getIntent().getExtras().getSerializable("equipment");

    viewPager = (ViewPager) findViewById(R.id.viewpager);
    viewPager.addOnPageChangeListener(this);
    setupViewPager(viewPager);


    tabLayout = (TabLayout) findViewById(R.id.tabs);
    tabLayout.setupWithViewPager(viewPager);

    tag = "FragA";



private void setupViewPager(ViewPager viewPager) 
    Bundle bundle = new Bundle();
    bundle.putSerializable("equipment", equipment);

    FragmentA fragmentA = new FragmentA();
    fragmentA.setArguments(bundle);

    FragmentB fragmentB = new FragmentB();
    fragmentB.setArguments(bundle);

    FragmentC fragmentC = new FragmentC();
    fragmentC.setArguments(bundle);

    adapter = new ViewPagerAdapter(getSupportFragmentManager());
    adapter.addFragment(fragmentA, "FragA");
    adapter.addFragment(fragmentB, "FragB");
    adapter.addFragment(fragmentC, "FragC");
    viewPager.setAdapter(adapter);



class ViewPagerAdapter extends FragmentPagerAdapter 
    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager manager) 
        super(manager);
    

    @Override
    public Fragment getItem(int position) 
        return mFragmentList.get(position);
    

    @Override
    public int getCount() 
        return mFragmentList.size();
    

    public void addFragment(Fragment fragment, String title) 
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    

    @Override
    public CharSequence getPageTitle(int position) 
        return mFragmentTitleList.get(position);
    


@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) 



@Override
public void onPageSelected(int position) 
    index = viewPager.getCurrentItem();
    if (index == 0) 
        tag = "FragA";
     else if (index == 1) 
        tag = "FragB";
     else 
        tag = "FragC";
    
    invalidateOptionsMenu();


@Override
public void onPageScrollStateChanged(int state) 



public void onBackPressed() 
    finish();


@Override
public void finishCheckEquipment(Boolean success) 
    Intent intent = new Intent(this, MainActivity.class);
    startActivity(intent);


@Override
public boolean onQueryTextSubmit(String query) 
    return false;


@Override
public boolean onQueryTextChange(String newText) 
    switch (index) 
        case 0:
            FragmentA fragmentA = new FragmentA() adapter.getItem(index);
            if (fragmentA != null) 
                fragmentA.refreshFragmentA(newText);
                return false;
            
        case 1:
            FragmentB fragmentB = new FragmentB() adapter.getItem(index);
            if (fragmentB != null) 
                fragmentB.refreshFragmentB(newText);
                return false;
 
    
    return false;


@Override
public boolean onCreateOptionsMenu(Menu menu) 
    getMenuInflater().inflate(R.menu.alarm, menu);
    mCheckedItem = menu.findItem(R.id.action_check_equipment_final);
    mBackupSettings = menu.findItem(R.id.enable_backup_final);
    MenuItem searchItem = menu.findItem(R.id.menu_item_search_alarm);
    mSearchItem = searchItem;
    mSearchView = (SearchView) MenuItemCompat.getActionView(mSearchItem);
    mSearchView.setOnQueryTextListener(this);
    FragmentC fragmentC = (FragmentC) adapter.getItem(2);
    if (fragmentC != null && fragmentC.isVisible() && index == 2) 
        String backup = equipmentInfoFragment.verifyBackup();
        switch (backup) 
            case "enable":
                mBackupSettings.setTitle(getResources().getString(R.string.disable_backup));
                break;
            case "disable":
                mBackupSettings.setTitle(getResources().getString(R.string.enable_backup));
                break;
            case "null":
                break;
        
    

    switch (index) 
        case 0:
            mSearchItem.setVisible(true);
            mCheckedItem.setVisible(true);
            mBackupSettings.setVisible(false);
            return true;
        case 1:
            mSearchItem.setVisible(true);
            mCheckedItem.setVisible(true);
            mBackupSettings.setVisible(false);
            return true;
        case 2:
            mSearchItem.setVisible(false);
            mCheckedItem.setVisible(true);
            mBackupSettings.setVisible(true);
            return true;
        default:
            return super.onCreateOptionsMenu(menu);
    


@Override
public boolean onOptionsItemSelected(MenuItem item) 
    switch (item.getItemId()) 
        case R.id.action_check_equipment_final:
            CheckEquipment checkEquipment = new CheckEquipment(this);
            checkEquipment.StarCheckEquipment(TabActivity.this, equipment);
        case android.R.id.home:
            finish();
            return true;
        case R.id.enable_backup_final:
            EquipmentInfoFragment equipmentInfoFragment = (EquipmentInfoFragment) adapter.getItem(2);
            equipmentInfoFragment.startEnableBackup();

    
    return super.onOptionsItemSelected(item);


具有对话框的类:

public class CheckEquipment extends FragmentActivity

private OnCheckEquipmentListener listener;
private Equipment mEquipment;
private Context mContext;
private Boolean success;
private SharedPreferences sessionUserSettings = null;
Bundle bundle = new Bundle();

public CheckEquipment (OnCheckEquipmentListener listener) 
    this.listener = listener;


public void StarCheckEquipment(Context context, Equipment equipment) 
    this.mEquipment = equipment;
    this.mContext = context;
    EquipmentDialogInner equipmentFragment = new EquipmentDialogInner(mContext);
    equipmentFragment.setCancelable(false);
    equipmentFragment.show();


private String generateAuthHeaderValue(String login, String password) 
    String authorizationString = "Basic "
            + Base64.encodeToString((login + ":"
            + password).getBytes(), Base64.DEFAULT);

    authorizationString = authorizationString.replaceAll("\\n", "");
    return authorizationString;


private class EquipmentDialogInner extends Dialog implements View.OnClickListener 

    private Button cancel, send;

    public EquipmentDialogInner(Context context) 
        super(context);
    

    @Override
public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.dialog_alert_message);
    cancel = (Button) findViewById(R.id.cancel_button);
    send = (Button) findViewById(R.id.send_button);
    cancel.setOnClickListener(this);
    send.setOnClickListener(this);
 

@Override
public void onClick(View view) 
    switch (view.getId())
        case R.id.cancel_button:
            this.dismiss();
            break;
        case R.id.send_button:
            if (!Utils.isNetworkAvailable(mContext))
                ActivityAction.showButtonToast(getOwnerActivity(), R.string.no_internet);
                return;
            
            try 
                new TaskSendEquipmentDetail().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
             catch (Exception e) 
                e.printStackTrace();
            
            this.dismiss();
            break;
        default:
    



private class TaskSendEquipmentDetail extends AsyncTask<Void, Void, Boolean> 

    List<Equipment> mEquipmentSelected = new ArrayList<>();

    @Override
    protected Boolean doInBackground(Void... params) 
        mEquipmentSelected.add(mEquipment);
        success = false;
        sessionUserSettings = mContext.getSharedPreferences(Constants.SHARED_PREFERENCE_USER, 0);
        String url = Constants.PROVIDER_DOMAIN_URL + Constants.REQUEST_EQUIPMENT;
        String login = sessionUserSettings.getString(Constants.SHARED_PREFERENCE_USER_LOGIN, "");
        String password = sessionUserSettings.getString(Constants.SHARED_PREFERENCE_USER_PWD, "");

        try
            DefaultHttpClient httpClient = new DefaultHttpClient();
            HttpPost httpPost = new HttpPost(url);

            final GsonBuilder builder = new GsonBuilder();
            builder.excludeFieldsWithoutExposeAnnotation();
            final Gson gson = builder.create();

            String json = gson.toJson(mEquipmentSelected);
            StringEntity enity = new StringEntity(json);
            httpPost.setEntity(enity);
            httpPost.setHeader("Content-type", "application/json");
            httpPost.addHeader("Authorization", generateAuthHeaderValue(login, password));
            HttpResponse httpResponse = httpClient.execute(httpPost);

            int responseCode = httpResponse.getStatusLine().getStatusCode();

            switch (responseCode) 
                case 200:
                    success = true;
                    break;
                default:
                    System.out.print("erro");
            
        catch (Exception ignored)
            System.out.print(ignored);
        

        return success;
    

    @Override
    protected void onPostExecute(Boolean aBoolean) 
        if (success) 
            if (listener != null)
                listener.finishCheckEquipment(success);
            
         else 
            Toast toast = Toast.makeText(mContext, "Não Foi Possível", Toast.LENGTH_SHORT);
            toast.show();
        

    


public interface OnCheckEquipmentListener 
    void finishCheckEquipment(Boolean success);



日志:

 03-11 10:37:16.809 29718-29718/com.company.provider E/WindowManager: android.view.WindowLeaked: Activity com.company.provider.controllers.equipmentDetail.TabActivity has leaked window com.android.internal.policy.PhoneWindow$DecorView7c1f044 V.E...... R.....I. 0,0-482,219 that was originally added here
                                                                       at android.view.ViewRootImpl.<init>(ViewRootImpl.java:368)
                                                                       at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:299)
                                                                       at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:86)
                                                                       at android.app.Dialog.show(Dialog.java:319)
                                                                       at com.company.provider.controllers.equipmentDetail.CheckEquipment.StarCheckEquipment(CheckEquipment.java:52)
                                                                       at com.company.provider.controllers.equipmentDetail.TabActivity.onOptionsItemSelected(TabActivity.java:224)

【问题讨论】:

我编辑了问题 【参考方案1】:

我认为您应该将EquipmentDialogInnerCheckEquipment 中取出并使其本身成为一个类(新文件等),而不是将其作为CheckEquipment 中的内部类。

然后您可以更改您的onOptionsItemSelected,如下所示:

switch (item.getItemId()) 
    case R.id.action_check_equipment_final:
        EquipmentDialogInner dialog = new EquipmentDialogInner(this);
        dialog.setCancelable(false);
        dialog.show();
     case android.R.id.home:
        finish();
        return true;
     case R.id.enable_backup_final:
        EquipmentInfoFragment equipmentInfoFragment = (EquipmentInfoFragment) adapter.getItem(2);
        equipmentInfoFragment.startEnableBackup();


【讨论】:

以上是关于Activity 已泄露窗口,Dialog的主要内容,如果未能解决你的问题,请参考以下文章

ProgressDialog.show() - Activity 已泄露窗口

“Activity 已经泄露了原本添加在这里的窗口”

android 活动已泄露窗口 com.android.internal.policy.impl.phonewindow$decorview 问题

Android - Activity 泄露了 IntentReceiver

android内存优化-Activity, Thread引起的内存泄露0

小部件。 Activity 泄露了 IntentReceiver