如何在Android应用

时间:2015-07-06 20:41:47

标签: java android android-fragments memory-leaks firebase

我正在使用Firebase开发一个Android类型的图库应用程序,所以我将有大量的图像。我知道我需要小心内存管理。

当我在Android应用中搜索如何查找内存泄漏时,我遇到了LeakCanary。它看起来真的很棒,所以我在我的应用程序中使用。

基本上我的应用程序有3个片段,分别是Drawer,ProductGrid和ProductDetail。有时LeakCanary说我在ProductGrid中有内存泄漏,但我找不到它!通常,由于Context对象,适配器或静态方法或侦听器可能会导致内存泄漏,但我的知识不足以说'因为在这里'是的'

以下是课程。泄漏在哪里?(如果你建议我改进我的代码或方法,我将不胜感激!)

由于身体角色限制,我将link泄漏金丝雀日志文件。

我怀疑是否存在内存泄漏

首先,LeakCanary会显示一个对话框并记录转储。第二件事是,当我点击抽屉中的项目,在网格中并且在细节上分别15次(分别)时,内存使用量会增加。它以18M开始,在显示3张图像(正常)后增加22M-23M。然后在点击15次后达到29M-30M。如果你点击大约30-40,内存使用量增加34M-35M

编辑:我刚想通了,如果我打开和关闭抽屉,每次内存使用量增加0.05M,所以一次打开和关闭抽屉的成本为0.1M!我错过了什么?

Main.java

public class Main extends ActionBarActivity implements DrawerListener {

  private Toolbar mToolbar;

  private Drawer drawerFragment;
  private HomePage homeFragment;

  private FragmentHelper fh = new FragmentHelper();

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

    if (homeFragment == null)
      homeFragment = new HomePage();

    if (savedInstanceState == null) {
      mToolbar = (Toolbar) findViewById(R.id.toolbar);
      setSupportActionBar(mToolbar);
      getSupportActionBar().setDisplayShowHomeEnabled(true);

      drawerFragment = (Drawer)
            getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
      drawerFragment.setUp(R.id.navigation_drawer,
            (DrawerLayout) findViewById(R.id.drawer_layout), mToolbar);
      drawerFragment.setDrawerListener(this);
      drawerFragment.setRetainInstance(true);

      displayView(null);
    }
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();

    if (id == R.id.action_home) {
      getSupportActionBar().setTitle(getString(R.string.app_name));

      fh.replace(getSupportFragmentManager(), homeFragment, R.id.container_body);
      return true;
    }

    if (id == R.id.action_settings) {
      return true;
    }

    if (id == R.id.action_search) {
      Toast.makeText(getApplicationContext(), "Search action is selected!", Toast.LENGTH_SHORT).show();
      return true;
    }

    return super.onOptionsItemSelected(item);
  }

  @Override
  public void onDrawerItemSelected(View view, int position, Category category) {
    displayView(category);
  }

  private void displayView(Category category) {
    if (category != null) {
      getSupportActionBar().setTitle(category.getName());

      ProductGrid gridFragment = new ProductGrid();
      Bundle args = new Bundle();
      args.putString(Product.CATEGORY_ID, category.getId());
      gridFragment.setArguments(args);

      fh.replace(getSupportFragmentManager(), gridFragment, R.id.container_body);
    } else {
      getSupportActionBar().setTitle(getString(R.string.app_name));

      fh.replace(getSupportFragmentManager(), homeFragment, R.id.container_body);
    }
  }
}

Drawer.java

public class Drawer extends Fragment {

  private Firebase mFirebase;
  private Alert alert;

  private RecyclerView recyclerView;
  private View containerView;
  private DrawerLayout mDrawerLayout;
  private ActionBarDrawerToggle mDrawerToggle;
  private DrawerListener drawerListener;

  private DrawerAdapter mAdapter;

  private List<Category> mCategories;

  public Drawer() {
  }

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    alert = new Alert(getActivity().getApplicationContext());
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View layout = inflater.inflate(R.layout.drawer, container, false);

    mCategories = new ArrayList<>();

    mAdapter = new DrawerAdapter(mCategories);

    recyclerView = (RecyclerView) layout.findViewById(R.id.drawer_list);
    recyclerView.setLayoutManager(new LinearLayoutManager(getActivity().getApplicationContext()));
    recyclerView.setItemAnimator(new SlideInOutLeftItemAnimator(recyclerView));
    recyclerView.setAdapter(mAdapter);

    mFirebase = new Firebase(getActivity().getResources().getString(R.string.firebase_ref))
          .child(FirebaseRoots.CATEGORY);

    Query query = mFirebase.orderByChild(Category.PRIO);

    query.addChildEventListener(new ChildEventListener() {
      @Override
      public void onChildAdded(DataSnapshot dataSnapshot, String s) {
        Category model = dataSnapshot.getValue(Category.class);
        model.setId(dataSnapshot.getKey());
        mCategories.add(model);

        recyclerView.scrollToPosition(mCategories.size() - 1);
        mAdapter.notifyItemInserted(mCategories.size() - 1);
      }

      @Override
      public void onChildChanged(DataSnapshot dataSnapshot, String s) {
        Category model = dataSnapshot.getValue(Category.class);
        model.setId(dataSnapshot.getKey());

        int index = -1;
        for (int i = 0; i < mCategories.size(); i++) {
          if (mCategories.get(i).getId().equals(model.getId())) {
            index = i;
            break;
          }
        }
        mCategories.set(index, model);

        recyclerView.scrollToPosition(0);
        mAdapter.notifyItemChanged(index);
      }

      @Override
      public void onChildRemoved(DataSnapshot dataSnapshot) {
        Category model = dataSnapshot.getValue(Category.class);
        model.setId(dataSnapshot.getKey());

        int index = -1;
        for (int i = 0; i < mCategories.size(); i++) {
          if (mCategories.get(i).getId().equals(model.getId())) {
            index = i;
            break;
          }
        }
        mCategories.remove(index);

        recyclerView.scrollToPosition(0);
        mAdapter.notifyItemRemoved(index);
      }

      @Override
      public void onChildMoved(DataSnapshot dataSnapshot, String s) {

      }

      @Override
      public void onCancelled(FirebaseError firebaseError) {
        alert.show(firebaseError.toString());
      }
    });

    recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity().getApplicationContext(),
          recyclerView, new ClickListener() {
      @Override
      public void onClick(View view, int position) {
        Category category = mCategories.get(position);
        drawerListener.onDrawerItemSelected(view, position, category);
        mDrawerLayout.closeDrawer(containerView);
      }

      @Override
      public void onLongClick(View view, int position) {

      }
    }));

    return layout;
  }

  public void setUp(int fragmentId, DrawerLayout drawerLayout, final Toolbar toolbar) {
    containerView = getActivity().findViewById(fragmentId);
    mDrawerLayout = drawerLayout;
    mDrawerToggle = new ActionBarDrawerToggle(getActivity(), drawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close) {
      @Override
      public void onDrawerOpened(View drawerView) {
        super.onDrawerOpened(drawerView);
        getActivity().invalidateOptionsMenu();
      }

      @Override
      public void onDrawerClosed(View drawerView) {
        super.onDrawerClosed(drawerView);
        getActivity().invalidateOptionsMenu();
      }

      @Override
      public void onDrawerSlide(View drawerView, float slideOffset) {
        super.onDrawerSlide(drawerView, slideOffset);
        toolbar.setAlpha(1 - slideOffset / 2);
      }
    };

    mDrawerLayout.setDrawerListener(mDrawerToggle);
    mDrawerLayout.post(new Runnable() {
      @Override
      public void run() {
        mDrawerToggle.syncState();
      }
    });
  }

  public void setDrawerListener(DrawerListener listener) {
    this.drawerListener = listener;
  }

}

ProductGrid.java

public class ProductGrid extends Fragment implements ChildEventListener{

  private Firebase mFirebaseRef;
  private Alert alert;

  private RecyclerView recyclerView;
  private GridAdapter mAdapter;

  private String categoryId;
  private ArrayList<Product> mProducts;

  private FileSystem fs;

  public ProductGrid() {
  }

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    this.categoryId = getArguments().getString(Product.CATEGORY_ID);

    this.alert = new Alert(getActivity().getApplicationContext());
    this.fs = new FileSystem(getActivity().getApplicationContext());
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View layout = inflater.inflate(R.layout.grid, container, false);
    fieldInitialize(layout);

    mProducts = new ArrayList<>();
    mAdapter = new GridAdapter(mProducts, getActivity().getApplicationContext());

    recyclerView.addItemDecoration(new MarginDecoration(getActivity()));
    recyclerView.setHasFixedSize(true);
    recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 2));
    recyclerView.setAdapter(mAdapter);

    mFirebaseRef = new Firebase(getActivity().getResources().getString(R.string.firebase_ref))
          .child(FirebaseRoots.PRODUCT);

    Query query = mFirebaseRef.orderByChild(Product.CATEGORY_ID).equalTo(categoryId);
    query.addChildEventListener(this);

    recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), recyclerView, new ClickListener() {
      @Override
      public void onClick(View view, int position) {
        ProductDetail detailFragment = new ProductDetail();

        Bundle args = new Bundle();
        args.putSerializable("product", mProducts);
        args.putInt("position", position);
        detailFragment.setArguments(args);

        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        transaction.replace(R.id.container_body, detailFragment);
        transaction.addToBackStack(null);
        transaction.commit();
      }

      @Override
      public void onLongClick(View view, int position) {

      }
    }));

    return layout;
  }

  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);
  }

  @Override
  public void onDetach() {
    super.onDetach();
  }

  public void fieldInitialize(View layout) {
    recyclerView = (RecyclerView) layout.findViewById(R.id.product_grid_layout);
  }

  @Override
  public void onChildAdded(DataSnapshot dataSnapshot, String s) {
    Product model = dataSnapshot.getValue(Product.class);
    model.setId(dataSnapshot.getKey());
    mProducts.add(model);

    if (!fs.getFileNames().contains(model.getName() + FileExt.JPG.get())) {
      fs.writeImage(model.getName(), ImageUtil.base64ToBitmap(
            StringUtil.getBase64FromUrl(model.getImageData().getDataUrl())));
    }

    Collections.sort(mProducts);

    recyclerView.scrollToPosition(0);
    mAdapter.notifyItemInserted(mProducts.size() - 1);
  }

  @Override
  public void onChildChanged(DataSnapshot dataSnapshot, String s) {
    Product model = dataSnapshot.getValue(Product.class);
    model.setId(dataSnapshot.getKey());

    fs.writeImage(model.getName(), ImageUtil.base64ToBitmap(
          StringUtil.getBase64FromUrl(model.getImageData().getDataUrl())));

    int index = -1;
    for (int i = 0; i < mProducts.size(); i++) {
      if (mProducts.get(i).getId().equals(model.getId())) {
        index = i;
        break;
      }
    }
    mProducts.set(index, model);

    recyclerView.scrollToPosition(0);
    mAdapter.notifyItemChanged(index);
  }

  @Override
  public void onChildRemoved(DataSnapshot dataSnapshot) {
    Product model = dataSnapshot.getValue(Product.class);
    model.setId(dataSnapshot.getKey());

    fs.deleteImage(model.getName());

    int index = -1;
    for (int i = 0; i < mProducts.size(); i++) {
      if (mProducts.get(i).getId().equals(model.getId())) {
        index = i;
        break;
      }
    }
    mProducts.remove(index);

    recyclerView.scrollToPosition(0);
    mAdapter.notifyItemRemoved(index);
  }

  @Override
  public void onChildMoved(DataSnapshot dataSnapshot, String s) {
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    alert.show(firebaseError.toString());
  }

  @Override public void onDestroy() {
    super.onDestroy();
    RefWatcher refWatcher = AcarsanApp.getRefWatcher(getActivity());
    refWatcher.watch(this);
  }
}

ProductDetail.java

public class ProductDetail extends Fragment {

  private FullScreenImageAdapter adapter;
  private ViewPager viewPager;

  private ArrayList<Product> products;
  private int position;

  public ProductDetail() {
  }

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    products = (ArrayList<Product>) getArguments().getSerializable("product");
    position = getArguments().getInt("position");
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.product_detail, container, false);

    viewPager = (ViewPager) view.findViewById(R.id.product_gallery);
    adapter = new FullScreenImageAdapter(getActivity().getApplicationContext(), products);

    viewPager.setAdapter(adapter);
    viewPager.setCurrentItem(position);

    return view;
  }

  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);
  }

  @Override
  public void onDetach() {
    super.onDetach();
  }
}

文件系统

public class FileSystem {

  private Context mContext;

  public static final String PHOTOS_FOLDER = "photos";

  public FileSystem(Context mContext) {
    this.mContext = mContext;
  }

  public void writeImage(String name, Bitmap bitmap) {
    String filename = name + FileExt.JPG.get();

    File dir = mContext.getDir(PHOTOS_FOLDER, Context.MODE_PRIVATE);
    File fileWithinDir = new File(dir, filename);
    FileOutputStream outputStream;

    try {

      outputStream = new FileOutputStream(fileWithinDir);
      bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
      outputStream.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }


  public List<String> getFileNames() {
    List<String> fileNames = new ArrayList<>();

    File file = mContext.getDir(PHOTOS_FOLDER, Context.MODE_PRIVATE);
    File[] files = file.listFiles();
    for (File f : files) {
      fileNames.add(f.getName());
    }
    return fileNames;
  }

}

ImageUtil

public class ImageUtil {

  public static Bitmap base64ToBitmap(String encodedImage) {
    if (encodedImage == null)
      return null;

    byte[] decodedString = Base64.decode(encodedImage, Base64.DEFAULT);
    return BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
  }
}

0 个答案:

没有答案
相关问题