decodeSizedBitmap以避免outOfMemory不起作用

时间:2017-03-15 11:24:42

标签: java android

我有一个显示8个图像的活动,所以我不得不使用这个代码来避免在某些情况下工作正常的outOfMemory。

public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {
        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) >= reqHeight
                && (halfWidth / inSampleSize) >= reqWidth) {
            inSampleSize *= 2;
        }
    }

    return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
                                                     int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

这在此布局上运行良好

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:weightSum="1"
android:layout_width="match_parent"
android:padding="10dp"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.fahrul.pesantrenbahrululum.FotoPerdivisi"
android:orientation="vertical"
tools:showIn="@layout/app_bar_foto_perdivisi">
<ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_alignParentTop="true"
    android:layout_alignParentStart="true">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <LinearLayout
            android:id="@+id/kiriFotoPerdivisi"
            android:layout_width="150dp"
            android:layout_height="wrap_content"
            android:orientation="vertical">
        </LinearLayout>
        <LinearLayout
            android:id="@+id/kananFotoPerdivisi"
            android:layout_width="150dp"
            android:layout_height="wrap_content"
            android:orientation="vertical">
        </LinearLayout>
    </LinearLayout>
</ScrollView>
</LinearLayout>

这是java代码

public class FotoPerdivisi extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, ImageView.OnClickListener{
    LinearLayout kiriLay, kananLay;
    public int[] imageIds={
            R.drawable.foto_perdivisi1,R.drawable.foto_perdivisi2,R.drawable.foto_perdivisi3,R.drawable.foto_perdivisi4,
            R.drawable.foto_perdivisi5,R.drawable.foto_perdivisi6,R.drawable.foto_perdivisi7
    };
    public int[] Ids={
            R.id.img1,R.id.img2,R.id.img3,R.id.img4,R.id.img5,R.id.img6,R.id.img7
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_foto_perdivisi);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbarFotoPerdivisi);
        setSupportActionBar(toolbar);
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_foto_perdivisi);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.setDrawerListener(toggle);
        toggle.syncState();
        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_foto_perdivisi);
        navigationView.setNavigationItemSelectedListener(this);
        kiriLay = (LinearLayout)findViewById(R.id.kiriFotoPerdivisi);
        kananLay = (LinearLayout)findViewById(R.id.kananFotoPerdivisi);
//        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_foto_perdivisi);
//        navigationView.setNavigationItemSelectedListener(this);
//        RecyclerView recyclerView = (RecyclerView)findViewById(R.id.foto_perdivisiGrid);
//        recyclerView.setHasFixedSize(true);
//        RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getApplicationContext(),2);
//        recyclerView.setLayoutManager(layoutManager);
//        ArrayList<CreateList> createLists = prepareData();
//        MyAdapter adapter = new MyAdapter(getApplicationContext(),createLists);
//        recyclerView.setAdapter(adapter);
        prepareLayout();
    }
    public static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) >= reqHeight
                    && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }
    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
                                                         int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }

    public void prepareLayout(){
        for(int i = 0; i < imageIds.length;i++) {
            ImageView img = new ImageView(this);
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, (int) (150 * getResources().getDisplayMetrics().density));
            img.setLayoutParams(params);
            img.setScaleType(ImageView.ScaleType.CENTER_CROP);
            img.setOnClickListener(this);
            img.setImageBitmap(decodeSampledBitmapFromResource(getResources(),imageIds[i],params.width/2,params.height/2));
            img.setId(Ids[i]);
            if (i % 2==0) {
                kiriLay.addView(img);
            } else{
                kananLay.addView(img);
            }
        }
    }
    @Override
    public void onBackPressed() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_foto_perdivisi);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }

    @SuppressWarnings("StatementWithEmptyBody")
    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        int id = item.getItemId();

        if (id == R.id.nav_home) {
            Intent intent = new Intent(getApplicationContext(),MainActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(intent);
        } else if (id == R.id.nav_daftar) {
            Intent intent = new Intent(getApplicationContext(),DaftarIsiActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(intent);
        } else if (id == R.id.nav_foto) {
            Intent intent = new Intent(getApplicationContext(),Gallery.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(intent);
        } else if (id == R.id.nav_info) {
            Intent intent = new Intent(getApplicationContext(),InfoActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(intent);
        } else if (id == R.id.nav_exit) {
            System.exit(0);
        }

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_foto_perdivisi);
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }

    @Override
    public void onClick(View view) {
        Intent intent = new Intent(getApplicationContext(),ImageViewer.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        ImageView img = (ImageView)view;
        for(int i = 0; i < Ids.length; i++){
            if(img.getId() == Ids[i]) {
                intent.putExtra("position", i);
            }
        }
        intent.putExtra("curUse",1);
        startActivity(intent);
    }
}

但是如果我改变了线性布局参数 机器人:layout_width = “0dp” 机器人:layout_weight = “0.5” 代码没有用,我认为它是因为在layoutParams中宽度为0导致了算术错误。 如何避免outOfMemoryException并将布局参数保持为android:layout_width =“0dp” android:layout_weight =“0.5”? 感谢您的回复

2 个答案:

答案 0 :(得分:0)

  

我不得不使用这段代码来避免outOfMemory在某些方面运行良好   例。

我还遇到了很多关于图像缓存和加载的问题。还使用了decodeSampledBitmapFromResource。但相信我 Glide / Picasso 非常容易。您只需添加3行或4行,而不是使用复杂方法calculateInSampleSizedecodeSampledBitmapFromResource

GLIDE 添加到您的项目中:

首先在app gradle中添加依赖项:

dependencies {
  compile 'com.github.bumptech.glide:glide:3.7.0'
}

然后在您的prepareLayout()方法中,替换以下行

img.setImageBitmap(decodeSampledBitmapFromResource(getResources(),imageIds[i],params.width/2,params.height/2));
            img.setId(Ids[i]);

使用:

 Glide.with(this).load(R.id.img1).into(imageView);  //As example

使用GLIDE看here

希望这有帮助。

答案 1 :(得分:0)

您的问题是视图尚未布局,因此没有最终尺寸(getHeight()和getWidth()将返回0)。
decodeSampledBitmapFromResource需要这些维度来确定加载位图的大小。

解决方法是在解码图像之前等待布局传递:

    // place a runnable at the end of the message queue, after the layout pass.
    getWindow().getDecorView().post(new Runnable() {
        @Override
        public void run() {
            prepareLayout();
        }
    });

还要确保将实际尺寸实际传递给decodeSampledBitmapFromResource。例如,不是MATCH_PARENT常量,而是父级的实际高度。

相关问题