赞
踩
利用ContentProvider和contentResolver可实现在不同应用程序之间的数据共享,并保证被访问数据的安全性。ContentProvider用于暴露数据,contentResolver用于操作数据。
通过Context的getContentResolver()方法获取实例,通过Uri对指定应用的表进行增删改查
Uri由content://authority/path/(id)组成,其中authority用于区分不用程序,path用于区分程序中不同的表,id用于指定表中的数据
列如:content://com.example.demo0.provider/table1/1 意为访问com.example.demo0应用table1中id为1的数据
Tips:
通过Uri.parse()方法可将字符串解析为Uri对象:
Uri uri=Uri.parse("content://com.example.demo0.provider/table1");
第一个参数为uri,第二个参数为要插入的ContentValues,返回新纪录的Uri:
ContentValues values=new ContentValues();
values.put("column1","text1");
values.put("column2","text2");
getContentResolver().insert(uri,values);
第一个参数为uri,第二三个参数为约束条件,返回被删除的行数:
getContentResolver().delete(uri,"column2=?",new String[]{"text2"});
第一个参数为uri,第二个参数为要修改的ContentValues,第三四个参数为约束条件,返回影响行数:
ContentValues values=new ContentValues();
values.put("column1","");
getContentResolver().update(uri,values,"colum1=? and colum2=?",new String[]{"text",1});
第一个参数为uri,第二个参数为列名,第三四个参数为约束条件,第五个参数为对结果的排序方式,返回cursor:
Cursor cursor=getContentResolver().query(uri,null,null,null,null);
if(cursor!=null){
while(cursor.moveToNext()){
String column1=cursor.getString(cursor.getColumnIndex("column1"));
String column2=cursor.getString(cursor.getColumnIndex("column2"));
}
cursor.close();
}
除了系统自带应用的ContentProvider,还可以通过继承ContentProvider,内部维护UriMatcher匹配Uri,重写以下方法实现自定义ContentProvider:
Tips:
新建MyDatabaseHelper:
public class MyDatabaseHelper extends SQLiteOpenHelper { public static final String CREATE_BOOK = "create table Book(" + "id integer primary key autoincrement," + "author text," + "price real," + "pages integer," + "name text)"; private Context mContext; public MyDatabaseHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); mContext = context; } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_BOOK); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
选择包new→Ohter→ContentProvider,输入name=MyContentProvider和authorities=com.example.database.provider,重写相关方法:
public class MyContentProvider extends ContentProvider { public static final int BOOK_DIR = 0; public static final int BOOK_ITEM = 1; public static final String AUTHORITY = "com.example.database.provider"; private static UriMatcher uriMatcher; private MyDatabaseHelper databaseHelper; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR); uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM); } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { SQLiteDatabase writableDatabase = databaseHelper.getWritableDatabase(); int deleteRows = 0; switch (uriMatcher.match(uri)) { case BOOK_DIR: deleteRows = writableDatabase.delete("Book",selection,selectionArgs); break; case BOOK_ITEM: String bookId = uri.getPathSegments().get(1); deleteRows = writableDatabase.delete("Book", "id=?", new String[]{bookId}); break; default: break; } return deleteRows; } @Override public String getType(Uri uri) { switch (uriMatcher.match(uri)) { case BOOK_DIR: return "vnd.android.cursor.dir/vnd.com.example.database.provider.book"; case BOOK_ITEM: return "vnd.android.cursor.item/vnd.com.example.database.provider.book"; } return null; } @Override public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase writableDatabase = databaseHelper.getWritableDatabase(); Uri UriReturn = null; switch (uriMatcher.match(uri)) { case BOOK_DIR: case BOOK_ITEM: long newBookId = writableDatabase.insert("Book", null, values); UriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId); break; } getContext().getContentResolver().notifyChange(UriReturn,null); return UriReturn; } @Override public boolean onCreate() { databaseHelper = new MyDatabaseHelper(getContext(), "Book.db", null, 1); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase writableDatabase = databaseHelper.getWritableDatabase(); Cursor cursor = null; switch (uriMatcher.match(uri)) { case BOOK_DIR: cursor = writableDatabase.query("Book", projection, selection, selectionArgs, null, null, sortOrder); break; case BOOK_ITEM: String bookId = uri.getPathSegments().get(1); cursor = writableDatabase.query("Book", projection, "id=?", new String[]{bookId}, null, null, sortOrder); break; default: break; } return cursor; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase writableDatabase = databaseHelper.getWritableDatabase(); int updateRows = 0; switch (uriMatcher.match(uri)) { case BOOK_DIR: updateRows = writableDatabase.update("Book",values,selection,selectionArgs); break; case BOOK_ITEM: String bookId = uri.getPathSegments().get(1); updateRows = writableDatabase.update("Book", values, "id=?", new String[]{bookId}); break; default: break; } return updateRows; } }
修改activity_main.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:orientation="vertical" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/add" android:layout_height="wrap_content" android:text="add" android:layout_width="match_parent"/> <Button android:id="@+id/query" android:layout_height="wrap_content" android:text="query" android:layout_width="match_parent"/> <Button android:id="@+id/update" android:layout_height="wrap_content" android:text="update" android:layout_width="match_parent"/> <Button android:id="@+id/delete" android:layout_height="wrap_content" android:text="delete" android:layout_width="match_parent"/> </LinearLayout>
修改MainActivity:
public class MainActivity extends AppCompatActivity { private String newId; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getContentResolver().registerContentObserver(Uri.parse("content://com.example.database.provider/book"), true, new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange) { super.onChange(selfChange); } }); Button add = findViewById(R.id.add); add.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Uri uri = Uri.parse("content://com.example.database.provider/book"); ContentValues values = new ContentValues(); values.put("name", "Tom"); values.put("author", "john"); values.put("pages", 100); values.put("price", 10); Uri newUri = getContentResolver().insert(uri, values); newId = newUri.getPathSegments().get(1); } }); Button query = findViewById(R.id.query); query.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Uri uri = Uri.parse("content://com.example.database.provider/book"); Cursor cursor = getContentResolver().query(uri, null, null, null, null); if (cursor != null) { while (cursor.moveToNext()) { String name = cursor.getString(cursor.getColumnIndex("name")); String author = cursor.getString(cursor.getColumnIndex("author")); String pages = cursor.getString(cursor.getColumnIndex("pages")); String price = cursor.getString(cursor.getColumnIndex("price")); Log.d("MainActivity", name + author + pages + price); } cursor.close(); } } }); Button update = findViewById(R.id.update); update.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Uri uri = Uri.parse("content://com.example.database.provider/book/" + newId); ContentValues values = new ContentValues(); values.put("price", 20); getContentResolver().update(uri, values, null, null); } }); Button delete = findViewById(R.id.delete); delete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Uri uri = Uri.parse("content://com.example.database.provider/book/" + newId); getContentResolver().delete(uri, null, null); } }); } }
activitiy_main.xml布局文件只有一个按钮
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/insertEvent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="添加日历事件" />
</RelativeLayout>
AndroidManifest.xml添加权限
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
MainActivity动态申请权限
public class MainActivity extends AppCompatActivity { private static final String TAG = "song"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); checkCalendarPermission(); //query(); Button insertBtn = findViewById(R.id.insertEvent); insertBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Calendar beginTime = Calendar.getInstance(); // 分别为年-月(从0开始)-日-时-分 beginTime.set(2022, 0, 30, 0, 0); long beginMillis = beginTime.getTimeInMillis(); Calendar endTime = Calendar.getInstance(); endTime.set(2022, 0, 30, 23, 59); long endMillis = endTime.getTimeInMillis(); String timeZoneID = TimeZone.getDefault().getID(); //插入需要设置开始/结束时间、时区、日历id,其他的如标题描述自行添加 Uri eventUri = CalendarContract.Events.CONTENT_URI; ContentResolver contentResolver = getContentResolver(); ContentValues eventValues = new ContentValues(); eventValues.put(CalendarContract.Events.DTSTART, beginMillis); eventValues.put(CalendarContract.Events.DTEND, endMillis); eventValues.put(CalendarContract.Events.CALENDAR_ID, 1); eventValues.put(CalendarContract.Events.EVENT_TIMEZONE, timeZoneID); eventValues.put(CalendarContract.Events.TITLE, "日历提醒"); eventValues.put(CalendarContract.Events.DESCRIPTION, "这里是日历事件描述"); eventValues.put(CalendarContract.Events.EVENT_LOCATION, "深圳"); Uri resultUri = contentResolver.insert(eventUri, eventValues); Log.d(TAG, "resultUri=" + resultUri); //插入事件和提醒是不同的表 String eventID = resultUri.getLastPathSegment(); Log.d(TAG, "eventID=" + eventID); ContentValues reminderValues = new ContentValues(); reminderValues.put(CalendarContract.Reminders.EVENT_ID, Long.parseLong(eventID)); reminderValues.put(CalendarContract.Reminders.MINUTES, 15); reminderValues.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALARM); Uri reminderUri = CalendarContract.Reminders.CONTENT_URI; contentResolver.insert(reminderUri, reminderValues); } }); } private void checkCalendarPermission() { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { int readPermission = checkSelfPermission(Manifest.permission.READ_CALENDAR); int writePermission = checkSelfPermission(Manifest.permission.WRITE_CALENDAR); if (readPermission == PackageManager.PERMISSION_GRANTED && writePermission == PackageManager.PERMISSION_GRANTED) { } else { requestPermissions(new String[]{Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR}, 1); } } } private void query() { ContentResolver contentResolver = getContentResolver(); //Uri uri = Uri.parse("content://" + "com.android.calendar/" + "calendars"); Uri uri = CalendarContract.Calendars.CONTENT_URI; Cursor cursor = contentResolver.query(uri, null, null, null, null); String[] columnNames = cursor.getColumnNames(); while (cursor.moveToNext()) { for (String columnName : columnNames) { Log.d(TAG, columnName + " == " + cursor.getString(cursor.getColumnIndex(columnName))); } } cursor.close(); } }
MainActivity如下,需要动态申请权限READ_CONTACTS,data1为列名
public class MainActivity extends AppCompatActivity { private static final String TAG = "song"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); checkCalendarPermission(); getUserInfo(); } private void getUserInfo() { ContentResolver contentResolver = getContentResolver(); Uri contactsUri = Uri.parse("content://com.android.contacts/raw_contacts"); Cursor contactsCursor = contentResolver.query(contactsUri, new String[]{"contact_id", "display_name"}, null, null, null); String[] columnNames = contactsCursor.getColumnNames(); List<UseInfo> useInfos = new ArrayList<>(); while (contactsCursor.moveToNext()) { UseInfo useInfo = new UseInfo(); useInfo.setId(contactsCursor.getString(contactsCursor.getColumnIndex("contact_id"))); useInfo.setDisplayName(contactsCursor.getString(contactsCursor.getColumnIndex("display_name"))); /*for (String columnName : columnNames) { Log.d(TAG, columnName + " = " + contactsCursor.getString(contactsCursor.getColumnIndex(columnName))); }*/ useInfos.add(useInfo); } contactsCursor.close(); Uri phoneUri = Uri.parse("content://com.android.contacts/data/phones"); for (UseInfo useInfo : useInfos) { Cursor phoneCursor = contentResolver.query(phoneUri, new String[]{"data1"}, "raw_contact_id=?", new String[]{useInfo.getId()}, null); if (phoneCursor.moveToNext()) { useInfo.setPhoneNum(phoneCursor.getString(0)); } phoneCursor.close(); Log.d(TAG, "getUserInfo: userInfo = " + useInfo); } } private void checkCalendarPermission() { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { int readPermission = checkSelfPermission(Manifest.permission.READ_CONTACTS); int writePermission = checkSelfPermission(Manifest.permission.WRITE_CONTACTS); if (readPermission == PackageManager.PERMISSION_GRANTED && writePermission == PackageManager.PERMISSION_GRANTED) { } else { requestPermissions(new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS}, 1); } } } }
用到的javabean如下
public class UseInfo { private String id; private String displayName; private String phoneNum; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getDisplayName() { return displayName; } public void setDisplayName(String displayName) { this.displayName = displayName; } public String getPhoneNum() { return phoneNum; } public void setPhoneNum(String phoneNum) { this.phoneNum = phoneNum; } @Override public String toString() { return "UseInfo{" + "id='" + id + '\'' + ", displayName='" + displayName + '\'' + ", phoneNum='" + phoneNum + '\'' + '}'; } }
需要申请READ_SMS权限,通过监听事件获取短信内容,正则表达式提取验证码
public class MainActivity extends AppCompatActivity { private static final String TAG = "song"; private Uri mSmsUri = Uri.parse("content://sms/"); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); checkPermission(); //getSms(); getVerifyCode(); } private static UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); static { sUriMatcher.addURI("sms", "#", 1); } private void getVerifyCode() { getContentResolver().registerContentObserver(mSmsUri, true, new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange, @Nullable Uri uri) { Log.d(TAG, "onChange: "); if (sUriMatcher.match(uri) == 1) { Log.d(TAG, "onChange: uri=" + uri); Cursor query = getContentResolver().query(mSmsUri, new String[]{"body"}, null, null, null); if (query.moveToNext()) { String body = query.getString(0); Log.d(TAG, "onChange: body=" + body); if (!TextUtils.isEmpty(body)) { Pattern pattern = Pattern.compile("(?<![0-9])([0-9]{4})(?![0-9])"); Matcher matcher = pattern.matcher(body); boolean b = matcher.find(); if (b) { Log.d(TAG, "onChange: code=" + matcher.group()); } } } } } }); } private void getSms() { ContentResolver contentResolver = getContentResolver(); Cursor smsCursor = contentResolver.query(mSmsUri, null, null, null, null); String[] columnNames = smsCursor.getColumnNames(); while (smsCursor.moveToNext()) { for (String columnName : columnNames) { Log.d(TAG, columnName + " = " + smsCursor.getString(smsCursor.getColumnIndex(columnName))); } } smsCursor.close(); } private void checkPermission() { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { int readPermission = checkSelfPermission(Manifest.permission.READ_SMS); if (readPermission != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.READ_SMS}, 1); } } } }
通过模拟器发送短信,即可在log中捕获
javabean类,存储照片在sd卡的路径、名称、和添加日期
public class ImageItem { private String path; private String title; private long date; public ImageItem(String path, String title, long date) { this.path = path; this.title = title; this.date = date; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public long getDate() { return date; } public void setDate(long date) { this.date = date; } }
获取屏幕宽度,从而计算平分每张照片所占宽度
public class SizeUtils {
public static Point getScreenSize(Context context) {
Point point = new Point();
((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getSize(point);
return point;
}
}
MainActivity适配布局,放置一个跳转Button和所选择照片返回显示的RecycleView
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/get_pic" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="获取图片" /> <androidx.recyclerview.widget.RecyclerView android:layout_below="@id/get_pic" android:id="@+id/result_image_list" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>
public class MainActivity extends AppCompatActivity implements PickerConfig.OnImageSelectedFinishedListener { private static final int MAX_SELECTED_COUNT = 9; private Button mGetPicBtn; private RecyclerView mResultImageRv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); checkPermission(); initView(); initEvent(); initPickerConfig(); } private void checkPermission() { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { int readPermission = checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE); if (readPermission != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1); } } } private void initView() { mGetPicBtn = findViewById(R.id.get_pic); mResultImageRv = findViewById(R.id.result_image_list); } private void initEvent() { mGetPicBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(MainActivity.this, PickerActivity.class)); } }); } private void initPickerConfig() { PickerConfig pickerConfig = PickerConfig.getInstance(); pickerConfig.setMaxSelectedCount(MAX_SELECTED_COUNT); pickerConfig.setOnImageSelectedFinishedListener(this); } @Override public void onSelectedFinished(List<ImageItem> result) { int col = Math.min(result.size(), 3); ResultImageAdapter resultImageAdapter = new ResultImageAdapter(); resultImageAdapter.setData(result, col); mResultImageRv.setAdapter(resultImageAdapter); mResultImageRv.setLayoutManager(new GridLayoutManager(this, col)); } }
为适配布局,有一个显示图片ImageVIew、选中后的背景颜色覆盖View和CheckBox选择框
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/image_container" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/image_iv" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" /> <View android:id="@+id/image_cover" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#77000000" android:visibility="gone" /> <CheckBox android:id="@+id/image_chek_box" android:clickable="false" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:checked="false" /> </RelativeLayout>
为返回结果的适配器
public class ResultImageAdapter extends RecyclerView.Adapter<ResultImageAdapter.innerHolder> { private List<ImageItem> mImageItems = new ArrayList<>(); private int mCol = 1; @NonNull @Override public innerHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_image, parent, false); itemView.findViewById(R.id.image_chek_box).setVisibility(View.GONE); return new innerHolder(itemView); } @Override public void onBindViewHolder(@NonNull ResultImageAdapter.innerHolder holder, int position) { View itemView = holder.itemView; Point screenSize = SizeUtils.getScreenSize(itemView.getContext()); RecyclerView.LayoutParams layoutParams = new RecyclerView.LayoutParams(screenSize.x / mCol, screenSize.x / mCol); itemView.setLayoutParams(layoutParams); ImageView imageView = itemView.findViewById(R.id.image_iv); ImageItem imageItem = mImageItems.get(position); Glide.with(imageView.getContext()).load(imageItem.getPath()).into(imageView); } @Override public int getItemCount() { return mImageItems.size(); } public void setData(List<ImageItem> result, int horizontalCount) { this.mCol = horizontalCount; mImageItems.clear(); mImageItems.addAll(result); notifyDataSetChanged(); } public class innerHolder extends RecyclerView.ViewHolder { public innerHolder(@NonNull View itemView) { super(itemView); } } }
为主页面和选择页面的单例桥梁,持有最大选择数量和数据回调
public class PickerConfig { private int maxSelectedCount = 1; private OnImageSelectedFinishedListener mImageSelectedFinishedListener = null; private PickerConfig() { } private static PickerConfig sPickerConfig; public static PickerConfig getInstance() { if (sPickerConfig == null) { sPickerConfig = new PickerConfig(); } return sPickerConfig; } public int getMaxSelectedCount() { return maxSelectedCount; } public void setMaxSelectedCount(int maxSelectedCount) { this.maxSelectedCount = maxSelectedCount; } public OnImageSelectedFinishedListener getImageSelectedFinishedListener() { return mImageSelectedFinishedListener; } public void setOnImageSelectedFinishedListener(OnImageSelectedFinishedListener listener) { this.mImageSelectedFinishedListener = listener; } public interface OnImageSelectedFinishedListener { void onSelectedFinished(List<ImageItem> result); } }
选择界面布局,由上方的标题栏(返回,选择数量提示和完成)及下面的RecycleView组成
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".PickerActivity"> <RelativeLayout android:id="@+id/title" android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:id="@+id/back" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:text="返回" /> <TextView android:id="@+id/selectedCount" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toLeftOf="@id/finished" android:layout_centerVertical="true" android:layout_marginRight="10dp" android:text="已选择(0/9)" android:textSize="20sp" /> <Button android:id="@+id/finished" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="10dp" android:text="完成" android:textSize="20sp" /> </RelativeLayout> <androidx.recyclerview.widget.RecyclerView android:id="@+id/image_selector" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/title" /> </RelativeLayout>
public class PickerActivity extends AppCompatActivity implements ImageSectorAdapter.OnItemSelectedChangeListener { private static final String TAG = "song"; private static final int LOADER_ID = 1; private List<ImageItem> mImageItems = new ArrayList<>(); private ImageSectorAdapter mImageSectorAdapter; private TextView mSelectedCount; private Button mFinishedBtn; private PickerConfig mPickerConfig; private RecyclerView mImageSectorRv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_picker); //query(); initLoaderManager(); initView(); initEvent(); initConfig(); } private void initConfig() { mPickerConfig = PickerConfig.getInstance(); int maxSelectedCount = mPickerConfig.getMaxSelectedCount(); mImageSectorAdapter.setMaxSelectedCount(maxSelectedCount); } private void initView() { mImageSectorRv = findViewById(R.id.image_selector); mSelectedCount = findViewById(R.id.selectedCount); mFinishedBtn = findViewById(R.id.finished); } private void initEvent() { mImageSectorAdapter = new ImageSectorAdapter(); mImageSectorAdapter.setOnItemSelectedChangeListener(this); mImageSectorRv.setAdapter(mImageSectorAdapter); mImageSectorRv.setLayoutManager(new GridLayoutManager(this, 3)); mFinishedBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { List<ImageItem> result = new ArrayList<>(mImageSectorAdapter.getSelectedList()); if (result.size() != 0) { mImageSectorAdapter.release(); PickerConfig.OnImageSelectedFinishedListener imageSelectedFinishedListener = mPickerConfig.getImageSelectedFinishedListener(); if (imageSelectedFinishedListener != null) { imageSelectedFinishedListener.onSelectedFinished(result); } } finish(); } }); findViewById(R.id.back).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); } private void initLoaderManager() { mImageItems.clear(); LoaderManager loaderManager = LoaderManager.getInstance(this); loaderManager.initLoader(LOADER_ID, null, new LoaderManager.LoaderCallbacks<Cursor>() { @NonNull @Override public Loader<Cursor> onCreateLoader(int id, @Nullable Bundle args) { if (id == LOADER_ID) { return new CursorLoader(PickerActivity.this, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{"_data", "_display_name", "date_added"}, null, null, "date_added DESC"); } return null; } @Override public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor cursor) { if (cursor != null) { while (cursor.moveToNext()) { String path = cursor.getString(0); String title = cursor.getString(1); long date = cursor.getLong(2); ImageItem imageItem = new ImageItem(path, title, date); mImageItems.add(imageItem); } cursor.close(); mImageSectorAdapter.setData(mImageItems); } } @Override public void onLoaderReset(@NonNull Loader<Cursor> loader) { } }); } private void query() { ContentResolver contentResolver = getContentResolver(); Uri imageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; Cursor query = contentResolver.query(imageUri, null, null, null, null); String[] columnNames = query.getColumnNames(); while (query.moveToNext()) { for (String columnName : columnNames) { Log.d(TAG, columnName + " = " + query.getString(query.getColumnIndex(columnName))); } } query.close(); } @Override public void OnItemSelectedChange(List<ImageItem> selectedList) { mSelectedCount.setText("已选择(" + selectedList.size() + "/" + mImageSectorAdapter.getMaxSelectedCount() + ")"); } }
选择界面的适配器
public class ImageSectorAdapter extends RecyclerView.Adapter<ImageSectorAdapter.innerHolder> { private List<ImageItem> mImageItems = new ArrayList<>(); private List<ImageItem> mSelectedList = new ArrayList<>(); private OnItemSelectedChangeListener mOnItemSelectedChangeListener; private int maxSelectedCount; public int getMaxSelectedCount() { return maxSelectedCount; } public void setMaxSelectedCount(int maxSelectedCount) { this.maxSelectedCount = maxSelectedCount; } public List<ImageItem> getSelectedList() { return mSelectedList; } public void setSelectedList(List<ImageItem> selectedList) { mSelectedList = selectedList; } @NonNull @Override public innerHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_image, parent, false); Point point = SizeUtils.getScreenSize(itemView.getContext()); RecyclerView.LayoutParams layoutParams = new RecyclerView.LayoutParams(point.x / 3, point.x / 3); itemView.setLayoutParams(layoutParams); return new innerHolder(itemView); } @Override public void onBindViewHolder(@NonNull ImageSectorAdapter.innerHolder holder, int position) { View itemView = holder.itemView; View imageContainer = itemView.findViewById(R.id.image_container); ImageView imageView = itemView.findViewById(R.id.image_iv); CheckBox check = itemView.findViewById(R.id.image_chek_box); View imageCover = itemView.findViewById(R.id.image_cover); ImageItem imageItem = mImageItems.get(position); Glide.with(imageView.getContext()).load(imageItem.getPath()).into(imageView); if (mSelectedList.contains(imageItem)) { check.setChecked(true); imageCover.setVisibility(View.VISIBLE); } else { check.setChecked(false); imageCover.setVisibility(View.GONE); } imageContainer.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //已选中则取消选择 if (mSelectedList.contains(imageItem)) { mSelectedList.remove(imageItem); check.setChecked(false); imageCover.setVisibility(View.GONE); } else { //未选中则选择 if (mSelectedList.size() >= maxSelectedCount) { Toast.makeText(check.getContext(), "最多只能选" + maxSelectedCount + "张图片", Toast.LENGTH_SHORT).show(); return; } mSelectedList.add(imageItem); check.setChecked(true); imageCover.setVisibility(View.VISIBLE); } if (mOnItemSelectedChangeListener != null) { mOnItemSelectedChangeListener.OnItemSelectedChange(mSelectedList); } } }); } public void release() { mSelectedList.clear(); } public interface OnItemSelectedChangeListener { void OnItemSelectedChange(List<ImageItem> selectedList); } public void setOnItemSelectedChangeListener(OnItemSelectedChangeListener listener) { this.mOnItemSelectedChangeListener = listener; } @Override public int getItemCount() { return mImageItems.size(); } public void setData(List<ImageItem> imageItems) { mImageItems.clear(); mImageItems.addAll(imageItems); notifyDataSetChanged(); } public class innerHolder extends RecyclerView.ViewHolder { public innerHolder(@NonNull View itemView) { super(itemView); } } }
点击获取照片进入选择界面,选择完成后根据照片数量显示
下面是选择界面
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。