java - 将原始资源设置为所选绘图中的壁纸

标签 java android gridview wallpaper android-wallpaper

我有一个 gridview,其中包含可绘制文件夹中的图像数组。我现在已经解决了将可绘制对象发送到另一个 Activity ,在该 Activity 中用户将在将原始文件夹中的图片设置为壁纸之前查看图像。由于压缩,我无法使用可绘制资源,并且合适的图像会因内存不足而导致崩溃。

我的 MainActivity 文件与 gridview:

GridView androidGridView;

private Integer asset1 = R.drawable.asset1;
private Integer asset2 = R.drawable.asset2;
private Integer asset3 = R.drawable.asset1;
private Integer asset4 = R.drawable.asset2;
private Integer asset5 = R.drawable.asset1;
private Integer asset6 = R.drawable.asset2;
private Integer[] images = {
        asset1, asset2, asset3,
        asset4, asset5, asset6
};

Integer[] imagesIDs = {
        R.raw.asset1, R.raw.asset2, R.drawable.asset1,
        R.drawable.asset1, R.drawable.asset1, R.drawable.asset1,
};

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

    androidGridView = findViewById(R.id.gridview_android_example);
    androidGridView.setAdapter(new ImageAdapterGridView(this));

    androidGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent,
                                View v, int position, long id) {
            int imageRes = images[position];

            Intent intent = new Intent(MainActivity.this, ViewActivity.class);
            intent.putExtra("IMAGE_RES", imageRes);
            startActivity(intent);
        }
    });

}

public class ImageAdapterGridView extends BaseAdapter {
    private Context mContext;

    public ImageAdapterGridView(Context c) {
        mContext = c;
    }

    public int getCount() {
        return images.length;
    }

    public Object getItem(int position) {
        return null;
    }

    public long getItemId(int position) {
        return 0;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ImageView mImageView;

        if (convertView == null) {
            mImageView = new ImageView(mContext);
            mImageView.setLayoutParams(new GridView.LayoutParams(525, 350));
            mImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
            mImageView.setPadding(16, 16, 16, 16);
        } else {
            mImageView = (ImageView) convertView;
        }
        mImageView.setImageResource(images[position]);
        return mImageView;
    }

我的 ViewActivity 文件,用户在将其设置为壁纸之前将在其中预览图像:

private Integer asset1 = R.raw.asset1;
private Integer asset2 = R.raw.asset2;
private Integer asset3 = R.raw.asset1;
private Integer asset4 = R.raw.asset2;
private Integer asset5 = R.raw.asset1;
private Integer asset6 = R.raw.asset2;
private Integer[] images = {
        asset1, asset2, asset3,
        asset4, asset5, asset6
};

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

    Bundle extras = getIntent().getExtras();
    int imageRes = extras.getInt("IMAGE_RES");

    ImageView preview = findViewById(R.id.preview);
    preview.setImageResource(imageRes);
    preview.setScaleType(ImageView.ScaleType.CENTER_CROP);

    Button set = findViewById(R.id.setButton);
    set.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

        }
    });
}

我不确定我是否走在正确的道路上,但如果有人能指出我正确的方向,那就太好了!

最佳答案

关于在 Android 应用程序中处理位图和图像时出现内存不足错误,已经写了很多文章:here , herehere , 例如。

对于在设备上设置壁纸的特殊目的,您可以尝试这种方法。我不保证您这样做总能避免 OOM 错误,但它应该可以防止大多数错误。

它通过在将资源解码为位图时尝试保留在应用程序当前的可用内存中来实现这一点。它还在最后回收位图。

一个优点是您不必提出输出位图所需的宽度和高度。它会根据可用内存为您执行此操作。 (这也是一个缺点 - 您不能自由选择您想要的任何位图尺寸。它们可能太大并导致崩溃。)

解码可能需要一些时间,这就是它在后台线程上完成的原因。

无论如何,这对我有用:

将ExecutorService和方法decodeBitmapWithinFreeMemory添加到您的ViewActivity中:

private ExecutorService executor = Executors.newSingleThreadExecutor();

...

// adapted from https://developer.android.com/topic/performance/graphics/load-bitmap.html
private Bitmap decodeResourceWithinFreeMemory(Resources resources, int resourceId, float requiredAspectRatio) {

    // get just the size of the resource image
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(resources, resourceId, options);

    // estimate number of pixels we can work with in current free memory   
    long freeMem = Runtime.getRuntime().freeMemory();
    long spaceForARGV8888Px = freeMem / 4; // est. number of ARGV_8888 pixels that can be stored

    // calculate the sides of a rectangle with approximately that number of pixels
    long squareRootLowerBound = (long) Math.floor(Math.pow(spaceForARGV8888Px, 0.5));
    int requestedWidth = (int) Math.floor(squareRootLowerBound * requiredAspectRatio);
    int requestedHeight = (int) Math.floor(squareRootLowerBound / requiredAspectRatio);

    // find the right sample size by aggressively increasing sampleSize var: require only that
    // _one_ of the output dimensions be greater than the corresponding requested dimension
    int sampleSize = 1;
    while ((options.outHeight / (2 * sampleSize) ) >= requestedHeight
            || (options.outWidth / (2 * sampleSize) ) >= requestedWidth) {
        sampleSize *= 2;
    }

    // output the bitmap by sampling the input resource at the calculated sampleSize
    options.inSampleSize = sampleSize;
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(resources, resourceId, options);
}

在按钮的onClick方法中调用decodeBitmapWithinFreeMemory,为其提供设备的屏幕宽高比:

DisplayMetrics metrics = getResources().getDisplayMetrics();
final float screenAspectRatio = (float)metrics.widthPixels/(float)metrics.heightPixels;
executor.submit(new Runnable() {
    @Override
    public void run() {
        try {
            Bitmap drawableAsBitmap = decodeResourceWithinFreeMemory(getResources(),
                    R.raw.asset1, screenAspectRatio);
            WallpaperManager.getInstance(MainActivity.this).setBitmap(drawableAsBitmap);
            drawableAsBitmap.recycle();
        } catch (IOException ioe) {
            Log.e(TAG, "Could not set wallpaper to bitmap", ioe);
        }
    }
});

另请注意,您可以选择将 BroadcastReceiver 添加到您的 Activity 中,以收到壁纸已设置的通知。 (请参阅 setBitmap. 的文档)

关于java - 将原始资源设置为所选绘图中的壁纸,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44935973/

相关文章:

java - 如何使用ArrayList HashMap将listview onItemClick数据发送到另一个 Activity

Android 应用向后兼容版本的 google play services API

c# - 在 ASP.NET 中使用超链接编辑 gridview 中的行

gridview - Yii GridView 小部件 - 居中对齐分页

java - 如何使用简单的 json 在请求正文下传递 json 数组

java - 使用 SAX 解析器解析 XML 文件后将数据存储到 MySQL 的最佳方法是什么?

javascript - 如何将 Javascript 日期转换为 Spring @RequestParam 的 LocalDate?

android - 服务是否有 onBackPressed() 替代方案?

Android Studio - 无法下载 sdk-common.jar

android - 带有日期分隔符的 GridView