Android實(shí)現(xiàn)簡(jiǎn)單圖庫(kù)輔助器
寫(xiě)在前面
實(shí)際開(kāi)發(fā)經(jīng)常會(huì)遇到讀取相冊(cè)或者拍照功能,網(wǎng)上也很非常多圖庫(kù)框架,都各有風(fēng)格,也因此與自己的項(xiàng)目格格不入。再者,框架API太多,需要的配置太多,還要吃力研究。所以,本人摸索大多圖庫(kù)框架,提煉核心,寫(xiě)一個(gè)只提供核心的輔助類,剩下的就可以自行玩耍。
實(shí)現(xiàn)步驟
第一步,創(chuàng)建輔助類,使用弱引用持有Activity,防止內(nèi)存溢出。
public class GalleryHelper{ private Activity mActivity; public GalleryHelper(Activity activity) { mActivity = new WeakReference<>(activity).get(); } }
第二步,創(chuàng)建文件夾實(shí)體類,代表文件夾數(shù)據(jù)。paths集合是文件夾下的所有路徑。
public final class FolderEntity { private int num; private String name; private List<String> paths = new ArrayList<>(); public int getNum() { return paths.size(); } public List<String> getPaths() { return paths; } public void setName(String name) { this.name = name; } }
第三步,首先獲取手機(jī)所有的圖片,在Activity里有g(shù)etLoaderManager方法獲取一個(gè)LoaderManager實(shí)例,該類用于異步加載手機(jī)內(nèi)數(shù)據(jù)監(jiān)測(cè),這里不做多分析。我們調(diào)用它的initLoader方法,前兩個(gè)參數(shù)這里不需要,只要實(shí)現(xiàn)LoaderCallbacks接口,并且指定Cursor類型。LoaderCallbacks接口有三個(gè)覆蓋方法,我們需要用到的是onCreateLoader方法和onLoadFinished方法,前者是初始化Loader,后者是加載完成后的回調(diào)。
mActivity.getLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks<Cursor>() { @Override public Loader<Cursor> onCreateLoader(int i, Bundle bundle) { } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { } @Override public void onLoaderReset(Loader<Cursor> loader) { } });
在onCreateLoader方法里,初始化CursorLoader,參數(shù)跟Cursor類下的query一樣,第一個(gè)參數(shù)指定外部村粗多媒體URI;第二個(gè)參數(shù)是查找結(jié)果字段,這里只要了路徑;第三個(gè)參數(shù)和第四個(gè)參數(shù)是搜索條件,條件為搜索jpeg格式和png格式,最后一個(gè)是按時(shí)間倒序搜索。
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) { return new CursorLoader(mActivity, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Images.Media.DATA}, MediaStore.Images.Media.MIME_TYPE + "=? or " + MediaStore.Images.Media.MIME_TYPE + "=?", new String[]{"image/jpeg", "image/png"}, MediaStore.Images.Media.DATE_ADDED + " DESC"); }
CursorLoader初始化完成之后,搜索的結(jié)果會(huì)回調(diào)在onLoadFinished方法。這時(shí)就可以處理搜索出來(lái)的圖片路徑。因?yàn)閳D片路徑是沒(méi)有分類,這里采用HashMap分類,以文件夾路徑為key,具體文件夾FolderEntity類為value,如果當(dāng)前圖片路徑的文件夾不存在則創(chuàng)建FolderEntity并且放入HashMap,存在則獲取FolderEntity。
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { HashMap<String, FolderEntity> folderEntityHashMap = new HashMap<String, FolderEntity>(); if (cursor != null) { while (cursor.moveToNext()) { //圖片路徑 String path = cursor.getString( cursor.getColumnIndex(MediaStore.Images.Media.DATA)); // 路徑不存在或者文件不存在就跳過(guò) File file = new File(path); if (TextUtils.isEmpty(path) || !file.exists()) { continue; } String folerPath = file.getParent(); FolderEntity folderEntity; if (folderEntityHashMap.containsKey(folerPath)) { folderEntity = folderEntityHashMap.get(folerPath); } else { folderEntity = new FolderEntity(); folderEntityHashMap.put(file.getParentFile().getName(), folderEntity); } folderEntity.getPaths().add(path); } cursor.close(); } }
但是數(shù)據(jù)是要提供給外部的,HashMap就顯得很麻煩,所以要轉(zhuǎn)換ArrayList,并且按數(shù)量大小進(jìn)行順序。
private ArrayList<FolderEntity> map2List(HashMap<String, FolderEntity> mediaBeanMap) { Iterator<FolderEntity> iterator = mediaBeanMap.values().iterator(); ArrayList<FolderEntity> list = new ArrayList<FolderEntity>(); while (iterator.hasNext()) { list.add(iterator.next()); } Collections.sort(list, new Comparator<FolderEntity>() { @Override public int compare(FolderEntity lhs, FolderEntity rhs) { return lhs.getNum() > rhs.getNum() ? 1 : -1; } }); return list; }
使用接口將數(shù)據(jù)提供給外部。
public interface GalleryCallback { void complete(List<FolderEntity> list); } callback.complete(map2List(folderEntityHashMap));
第四步是實(shí)現(xiàn)拍照功能,這里實(shí)現(xiàn)是創(chuàng)建文件再啟動(dòng)拍照功能。
File imageStoreDir = new File(Environment.getExternalStorageDirectory(), "/DCIM/" + mActivity.getResources().getString(R.string.app_name)); if (!imageStoreDir.exists()) { imageStoreDir.mkdir(); } Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (captureIntent.resolveActivity(mActivity.getPackageManager()) != null) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA); String filename = String.format("IMG%s", dateFormat.format(new Date())); imagePath = new File(imageStoreDir, filename).getAbsolutePath(); captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(imagePath))); mActivity.startActivityForResult(new Intent( MediaStore.ACTION_IMAGE_CAPTURE), REQUEST_CODE); }
定義回調(diào)接口,接收Activit的onActivityResult方法,表示回調(diào)成功把上面創(chuàng)建好的文件路徑提供外部。
public interface CameraCallback { void complete(String path); } public void onActivityResult(int requestCode, int resultCode) { if (Activity.RESULT_OK == resultCode && REQUEST_CODE == requestCode) { if (cameraCallback != null) { cameraCallback.complete(imagePath); } } }
外部調(diào)用
galleryHelper = new GalleryHelper(this); galleryHelper.loadImages(new GalleryHelper.GalleryCallback() { @Override public void complete(List<FolderEntity> list) { //加載本地圖片返回結(jié)果 } }); findViewById(R.id.btn_camera).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { galleryHelper.openCamera(new GalleryHelper.CameraCallback() { @Override public void complete(String path) { //拍照返回結(jié)果 } }); } }); @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); //使用拍照,必須接收Activity的onActivityResult方法 galleryHelper.onActivityResult(requestCode, resultCode); }
別忘了加權(quán)限,這里為了簡(jiǎn)單實(shí)現(xiàn),我把targetSdkVersion設(shè)置23以下,23和23以上的需要自行加上動(dòng)態(tài)權(quán)限。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
整體就完成了,使用非常方便,有了這圖庫(kù)輔助器就可以自定義風(fēng)格,再也不用受約束。網(wǎng)上大多開(kāi)源圖片選擇器的搜索圖片都是如此,但這例子難免有bug,不足之處望指教。
github地址:https://github.com/tanxinye/GalleryHelper
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android實(shí)現(xiàn)SQLite添加、更新及刪除行的方法
這篇文章主要介紹了Android實(shí)現(xiàn)SQLite添加、更新及刪除行的方法,涉及Android基于SQLiteDatabase類操作SQLite數(shù)據(jù)庫(kù)的基本技巧,需要的朋友可以參考下2016-08-08老生常談Android HapticFeedback(震動(dòng)反饋)
下面小編就為大家?guī)?lái)一篇老生常談Android HapticFeedback(震動(dòng)反饋)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04Android實(shí)現(xiàn)倒計(jì)時(shí)結(jié)束后跳轉(zhuǎn)頁(yè)面功能
最近在工作中遇到一個(gè)需求,需要在倒計(jì)時(shí)一段時(shí)間后進(jìn)行跳轉(zhuǎn)頁(yè)面,通過(guò)查找相關(guān)資料發(fā)現(xiàn)其中涉及的知識(shí)還不少,所以分享出來(lái),下面這篇文章主要給大家介紹了關(guān)于Android實(shí)現(xiàn)倒計(jì)時(shí)結(jié)束后跳轉(zhuǎn)頁(yè)面功能的相關(guān)資料,需要的朋友可以參考下。2017-11-11HandlerThread的使用場(chǎng)景和用法詳解
這篇文章主要介紹了HandlerThread的使用場(chǎng)景和用法詳解,HandlerThread是Android中的一個(gè)線程類,它是Thread的子類,并且內(nèi)部封裝了Looper和Handler,提供了更方便的消息處理和線程操作,需要的朋友可以參考下2023-07-07Kotlin RadioGroup與ViewPager實(shí)現(xiàn)底層分頁(yè)按鈕方法
安卓的控件是挺多的,沒(méi)有辦法一個(gè)一個(gè)的來(lái)說(shuō)明,我們挑出了一些重點(diǎn)的控件,組成一些常見(jiàn)的布局,這樣以后在遇到相同功能的界面時(shí),就會(huì)有自己的思路,或者進(jìn)行復(fù)用2022-12-12Android studio 解決logcat無(wú)過(guò)濾工具欄的操作
這篇文章主要介紹了Android studio 解決logcat無(wú)過(guò)濾工具欄的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-04-04Android Activity打開(kāi)后被應(yīng)用快照遮住的問(wèn)題
這篇文章主要介紹了Android Activity打開(kāi)后被應(yīng)用快照遮住的問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01