概述
内容提供者 (获取媒体库图片显示出来)
- 呈现效果
- 设计步骤
- 注意问题
Android 10.0 适配问题都解决了
项目源码.
呈现效果
设计步骤
-
第一步:先定义两个Activity,一个获取数据并用来展示,一个展示媒体库图片并提供选择
MainActivity<Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="pickImages" android:text="获取图片" android:textSize="20dp" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/showPicM" android:layout_width="match_parent" android:layout_height="match_parent"/>
PackageImageActivity
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/image3" />
<TextView
android:id="@+id/finished_pic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:text="(0/9)完成"
android:textColor="#000000"
android:textSize="20dp"
android:onClick="finishedPic"
/>
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/showImages"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
-
第二步: Android6.0以后的动态申请权限。
private void checkReadPermission() { int readPermission = checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE); int writePermission = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE); if (readPermission != PackageManager.PERMISSION_GRANTED && writePermission != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, READ_PERMISSION_CORD); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == READ_PERMISSION_CORD) { if (grantResults.length == 2 && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) { Log.d(TAG, "拥有权限"); } } }
-
第三步 从MainActivity 跳转到 PackageImageActivity
public void pickImages(View view) { Intent intent = new Intent(MainActivity.this, PackageImage.class); startActivity(intent); }
4. 第四步 使用LoaderManager 异步获取数据
private void initLoaderManager() {
imageItemList.clear();
LoaderManager loaderManager = LoaderManager.getInstance(this);
loaderManager.initLoader(LOADER_ID, null, new LoaderManager.LoaderCallbacks<Cursor>() {
/**
* 因为图库图片可能较多,不能在主线程进行耗时操作
* 在子线程进行操作
* @param id
* @param args
* @return
一个CurSor 装载
*/
@NonNull
@Override
public Loader<Cursor> onCreateLoader(int id, @Nullable Bundle args) {
if (id == LOADER_ID) {
return new CursorLoader(PackageImage.this, MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Images.Media._ID}, null, null, MediaStore.Images.Media.DATE_ADDED+" DESC");
}
return null;
}
/**
* 装载完成后调用
* @param loader
一个对象
* @param cursor
光标,包含所有图片信息。
*/
@Override
public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor cursor) {
if (cursor != null) {
while (cursor.moveToNext()) {
String id = cursor.getString(0);
//
**因为Android 10.0 以后进行分区存储。我们即使申请权限,也不能访问SD卡的内容。
//
因此如果这里获取path 后面使用Glide 加载图片会报FileNoFOUND错误。所以我们通过ID获取Uri**
Uri uri = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,id);
imageItemList.add(uri);
adapter.setData(imageItemList);
}
}
}
/**
* 重新装载是调用
* @param loader
*/
@Override
public void onLoaderReset(@NonNull Loader<Cursor> loader) {
}
});
}
-
第五步 使用recyclerView 将获取的图片信息,展现出来
@NonNull @Override public InnerHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_image, parent, false); //使用该方法,获取屏幕长度,将每一个图片尺寸设置x/3 Point point = SizeUtils.getScreenSize(view.getContext()); RecyclerView.LayoutParams layoutParams = new RecyclerView.LayoutParams(point.x / 3, point.y / 3); view.setLayoutParams(layoutParams); return new InnerHolder(view); }
-
第六步 在Adapter 里面暴露一个接口,用于将数据传出来
public void setOnItemSelectedNum(onItemSelectedNum onItemSelectedNum){ this.mOnItemSelectedNum = onItemSelectedNum; } public interface onItemSelectedNum{ void onItemSelectedChange(List<Uri> list); }
-
第七步 设计事件,用于表示选中图片
@Override public void onBindViewHolder(@NonNull InnerHolder holder, int position) { View view = holder.itemView; ImageView imageView = view.findViewById(R.id.iv); final View visibility = view.findViewById(R.id.visibility); final CheckBox select = view.findViewById(R.id.select); final Uri uri = mimageItems.get(position); Glide.with(imageView.getContext()).load(uri).into(imageView); // 先根据状态来渲染,防止紊乱 if (mselect.contains(uri)) { select.setButtonDrawable(R.drawable.image1); visibility.setVisibility(View.VISIBLE); } else { select.setButtonDrawable(R.drawable.image2); visibility.setVisibility(View.INVISIBLE); } imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 如果已经没被选择,添加 if (!mselect.contains(uri)) { if(mselect.size()>=9){ Toast.makeText(select.getContext(),"最多选择"+MAX_SELECTED_PIC+"张图片",Toast.LENGTH_SHORT).show(); }else{ mselect.add(uri); select.setButtonDrawable(R.drawable.image1); visibility.setVisibility(View.VISIBLE); } } else { // 如果已经被选择,删除,更改可见度 mselect.remove(uri); select.setButtonDrawable(R.drawable.image2); visibility.setVisibility(View.INVISIBLE); } mOnItemSelectedNum.onItemSelectedChange(mselect); } }); }
-
第八步 选择完成,将图片传回。需要使前后数据一致。我们使用一个PickerConfig(单例模式) 来实现。 在两个Activity都初始化它
public class PickerConfig { //最大选择图片数量 private int max_selected_pic = 1; private OnItemSelectedFinished monItemSelectedFinished = null; public OnItemSelectedFinished getMonItemSelectedFinished() { return monItemSelectedFinished; } private PickerConfig(){} private static PickerConfig pickerConfig; public static PickerConfig getInstance(){ if(pickerConfig==null){ pickerConfig =new PickerConfig(); } return pickerConfig; } public void setOnItemSelectedFinished(OnItemSelectedFinished onItemSelectedFinished){ this.monItemSelectedFinished = onItemSelectedFinished; } public interface OnItemSelectedFinished{ void onItemSelectedFinished(List<Uri> list); } public int getMax_selected_pic() { return max_selected_pic; } public void setMax_selected_pic(int max_selected_pic) { this.max_selected_pic = max_selected_pic; } }
-
第九步, 两个Activity初始化上面方法。 选择完成 ,数据返回
public void finishedPic(View view){ //需要获取数据 List<Uri> list = adapter.getMselect(); //把数据通知给其他地方 PickerConfig.OnItemSelectedFinished monItemSelectedFinished = mpickerConfig.getMonItemSelectedFinished(); if(monItemSelectedFinished!=null){ monItemSelectedFinished.onItemSelectedFinished(list); } //结束 finish(); }
-
第十步,将获取的数据在MainActivity 使用recyclView实现。
可以如果返回图片少于3个,就按几列展示。大于三列的三列显示private void initConfig() { PickerConfig pickerConfig = PickerConfig.getInstance(); pickerConfig.setMax_selected_pic(MAX_SELECTED_PIC); pickerConfig.setOnItemSelectedFinished(new PickerConfig.OnItemSelectedFinished() { @Override public void onItemSelectedFinished(List<Uri> list) { int horNum =1; if(list.size()<3){ horNum =list.size(); }else{ horNum =3; } GridLayoutManager gridLayoutManager =new GridLayoutManager(MainActivity.this,horNum); recyclerView.setLayoutManager(gridLayoutManager); mainAdapter.setData(list,horNum); } }); }
注意问题
1. Android10.0 为了保存隐私,不允许访问SD卡的等内容。我们需要使用
MediaStore.Images.Media 得到uri 不能使用path路径
2. Glide4.x 以上版本需要
implementation ‘com.github.bumptech.glide:glide:4.11.0’
annotationProcessor ‘com.github.bumptech.glide:compiler:4.11.0’
并且创建
@GlideModule
public class MyAppGlideModule extends AppGlideModule {
}
4. 如果没有报错,但图片没有加载出来。可能是因为适配器的设置长宽参数不合适
最后
以上就是无聊狗为你收集整理的内容提供者 (获取媒体库图片显示出来)Android10.0 适配呈现效果的全部内容,希望文章能够帮你解决内容提供者 (获取媒体库图片显示出来)Android10.0 适配呈现效果所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复