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】:我认为您应该将EquipmentDialogInner
从CheckEquipment
中取出并使其本身成为一个类(新文件等),而不是将其作为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 已泄露窗口
android 活动已泄露窗口 com.android.internal.policy.impl.phonewindow$decorview 问题
Android - Activity 泄露了 IntentReceiver