本地音乐Android10.0适配

This commit is contained in:
DESKTOP-ICQKP58\H1
2023-04-19 19:15:53 +08:00
parent 58a5556fc0
commit 34b061996f
12 changed files with 232 additions and 111 deletions

View File

@@ -91,6 +91,7 @@
android:icon="@mipmap/app_logo"
android:label="@string/app_name"
android:largeHeap="true"
android:requestLegacyExternalStorage="true"
android:resizeableActivity="true"
android:supportsRtl="true"
android:theme="@style/MyMaterialTheme"

View File

@@ -4,6 +4,7 @@ import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.BaseViewHolder
import com.nnbc123.app.R
@@ -21,8 +22,7 @@ import com.opensource.svgaplayer.SVGAImageView
import java.util.*
class RoomNewFriendsAdapter :
BaseQuickAdapter<UserInfo, BaseViewHolder>(R.layout.item_room_new_friends) {
class RoomNewFriendsAdapter : BaseQuickAdapter<UserInfo, BaseViewHolder>(R.layout.item_room_new_friends) {
override fun convert(helper: BaseViewHolder, item: UserInfo) {
@@ -75,16 +75,22 @@ class RoomNewFriendsAdapter :
VipHelper.loadVipIcon(helper.getView(R.id.iv_vip_icon), item.userVipInfoVO)
}
override fun onViewRecycled(holder: BaseViewHolder) {
super.onViewRecycled(holder)
val svgaLiving = holder.getView<SVGAImageView>(R.id.svga_living)
svgaLiving.stopAnimation()
}
override fun onViewAttachedToWindow(holder: BaseViewHolder) {
super.onViewAttachedToWindow(holder)
val svgaLiving = holder.getView<SVGAImageView>(R.id.svga_living)
svgaLiving.loadFromAssets("svga/home_living.svga")
val svgaLives = holder.getView<SVGAImageView>(R.id.svga_living)
svgaLives.startAnimation()
}
override fun onViewDetachedFromWindow(holder: BaseViewHolder) {
super.onViewDetachedFromWindow(holder)
val svgaLives = holder.getView<SVGAImageView>(R.id.svga_living)
svgaLives.stopAnimation(false)
}
}

View File

@@ -113,7 +113,6 @@ class MeFragment : BaseFragment(), View.OnClickListener {
onGetRelationShipEvent(e)
}
)
meViewModel.refreshData()
meViewModel.bannerLiveData.observe(viewLifecycleOwner) {
@@ -240,7 +239,10 @@ class MeFragment : BaseFragment(), View.OnClickListener {
override fun onResume() {
super.onResume()
setUserData()
requestUpdateUserInfo()
if(mUserInfo!=null && mUserInfo!!.isReview){
requestUpdateUserInfo()
}
}
@SuppressLint("SetTextI18n")

View File

@@ -554,6 +554,8 @@ class UserInfoModifyActivity : BaseViewBindingActivity<ActivityUserInfoModifyBin
StatusBarUtil.StatusBarLightMode(this)
}
override fun onDestroy() {
super.onDestroy()
dialogManager.dismissDialog()

View File

@@ -16,8 +16,10 @@ import com.netease.nim.uikit.StatusBarUtil
import com.nnbc123.app.R
import com.nnbc123.app.application.XChatApplication
import com.nnbc123.app.base.TitleBar
import com.nnbc123.app.common.permission.PermissionActivity
import com.nnbc123.app.common.util.BitmapUtil
import com.nnbc123.app.takephoto.app.TakePhotoActivity
import com.nnbc123.app.takephoto.compress.CompressConfig
import com.nnbc123.app.ui.user.UserModifyPhotosAdapter.PhotoItemClickListener
import com.nnbc123.app.ui.widget.dialog.CommonTipDialog
import com.nnbc123.core.file.FileModel
@@ -30,6 +32,7 @@ import com.nnbc123.library.common.photo.PhotoProviderNew
import com.nnbc123.library.common.util.PhotoCompressCallback
import com.nnbc123.library.common.util.PhotoCompressUtil
import com.nnbc123.library.easypermisssion.EasyPermissions
import com.nnbc123.library.utils.file.JXFileUtils
import com.orhanobut.logger.Logger
import com.trello.rxlifecycle3.android.ActivityEvent
import com.yalantis.ucrop.UCrop
@@ -55,7 +58,7 @@ class UserModifyPhotosActivity : TakePhotoActivity(), PhotoItemClickListener,
companion object {
const val FLAG_CHANGE = "isChanged"
private const val TAG = "UserModifyPhotosActivit"
private const val TAG = "UserModifyPhotosActivity"
fun startForResult(activity: Activity, userId: Long, requestCode: Int) {
val intent = Intent(activity, UserModifyPhotosActivity::class.java)
intent.putExtra("userId", userId)
@@ -84,7 +87,7 @@ class UserModifyPhotosActivity : TakePhotoActivity(), PhotoItemClickListener,
userInfo = UserModel.get().cacheLoginUserInfo
adapter = UserModifyPhotosAdapter(
this,
ArrayList(),
ArrayList<UserPhoto>(),
this
)
photoGridView!!.adapter = adapter
@@ -121,6 +124,26 @@ class UserModifyPhotosActivity : TakePhotoActivity(), PhotoItemClickListener,
isEditMode = !isEditMode
adapter!!.notifyDataSetChanged()
}
private fun takePhoto(){
val cameraOutFile = JXFileUtils.getTempFile(this, "picture_" + System.currentTimeMillis() + ".jpg");
if (!cameraOutFile.parentFile.exists()){
cameraOutFile.parentFile.mkdir();
}
val uri = Uri.fromFile(cameraOutFile)
val compressConfig = CompressConfig.Builder().create()
compressConfig.maxPixel = 500*1024
takePhoto.onEnableCompress(compressConfig,false)
takePhoto.onPickFromCapture(uri)
}
override fun checkPermission(
listener: PermissionActivity.CheckPermListener?,
resString: Int,
vararg mPerms: String?
) {
super.checkPermission(listener, resString, *mPerms)
takePhoto()
}
override fun onPhotoDeleteClick(position: Int) {
dialogManager.showProgressDialog(this, "请稍后")

View File

@@ -44,7 +44,7 @@ import butterknife.BindView;
import butterknife.ButterKnife;
@CreatePresenter(AddLocalMusicListPresenter.class)
public class AddLocalMusicListActivity extends BaseMvpActivity<IAddLocalMusicListView, AddLocalMusicListPresenter>
public class AddLocalMusicListActivity extends BaseMvpActivity<IAddLocalMusicListView,AddLocalMusicListPresenter>
implements IAddLocalMusicListView, View.OnClickListener {
@BindView(R.id.recycler_view)

View File

@@ -1,96 +0,0 @@
package com.nnbc123.app.music.presenter;
import com.nnbc123.app.base.BaseMvpPresenter;
import com.nnbc123.core.music.db.bean.LocalMusicBean;
import com.nnbc123.core.music.db.model.LocalMusicDbModel;
import com.nnbc123.core.music.view.IAddLocalMusicListView;
import com.nnbc123.core.utils.net.RxHelper;
import com.nnbc123.library.base.PresenterEvent;
import java.util.List;
import io.reactivex.disposables.Disposable;
public class AddLocalMusicListPresenter extends BaseMvpPresenter<IAddLocalMusicListView> {
private boolean isScanning = false;
private Disposable scanningDisposable;
private Disposable addAllDisposable;
public boolean isScanning() {
return isScanning;
}
public void scanningMusicInLocal() {
LocalMusicDbModel.getInstance().scanLocalMusic();
}
public void stopScanLocalMusic() {
isScanning = false;
if (scanningDisposable != null) {
if (!scanningDisposable.isDisposed()) {
scanningDisposable.dispose();
}
}
}
public void getLocalMusicBeans() {
LocalMusicDbModel.getInstance().getLocalMusicInfoList();
}
public void getLocalMusicBeanList(int page) {
}
public void scanningLocalMusicBeans() {
if (isScanning) {
return;
}
isScanning = true;
scanningDisposable = LocalMusicDbModel.getInstance().scanLocalMusicBeans()
.compose(bindUntilEvent(PresenterEvent.DESTROY))
.compose(RxHelper.handleException())
.compose(RxHelper.handleSchedulers())
.subscribe((localMusicBeans, throwable) -> {
isScanning = false;
if (getMvpView() == null) {
return;
}
getMvpView().onScanningComplete();
if (throwable == null) {
getMvpView().onScanningLocalMusicSuccess(localMusicBeans);
} else {
getMvpView().onScanningLocalMusicFail(throwable);
}
});
}
public void batchAddToPlayerList(List<LocalMusicBean> needAddList) {
//
addAllDisposable = LocalMusicDbModel.getInstance().batchAddToDB(needAddList)
.compose(bindUntilEvent(PresenterEvent.DESTROY))
.compose(RxHelper.handleSchedulers())
.subscribe((ids, throwable) -> {
if (getMvpView() == null) {
return;
}
if (throwable == null) {
getMvpView().addAllSuccess(ids);
} else {
getMvpView().addAllFail(throwable);
}
});
}
@Override
public void onDestroyPresenter() {
stopScanLocalMusic();
if (addAllDisposable != null && !addAllDisposable.isDisposed()) {
addAllDisposable.dispose();
}
super.onDestroyPresenter();
}
}

View File

@@ -0,0 +1,130 @@
package com.nnbc123.app.music.presenter
import android.net.Uri
import android.os.Build
import android.os.Environment
import com.nnbc123.app.base.BaseMvpPresenter
import com.nnbc123.core.music.db.bean.LocalMusicBean
import com.nnbc123.core.music.db.model.LocalMusicDbModel
import com.nnbc123.core.music.view.IAddLocalMusicListView
import com.nnbc123.core.utils.net.RxHelper
import com.nnbc123.library.base.PresenterEvent
import com.nnbc123.library.common.file.FileHelper
import com.nnbc123.library.common.util.Logger
import io.reactivex.disposables.Disposable
import kotlinx.coroutines.*
import java.io.File
class AddLocalMusicListPresenter : BaseMvpPresenter<IAddLocalMusicListView?>() {
var isScanning = false
private set
private var scanningDisposable: Disposable? = null
private var addAllDisposable: Disposable? = null
private var mCopyJob: Job? = null
companion object{
private const val TAG = "AddLocalMusicListPresenter"
}
fun scanningMusicInLocal() {
LocalMusicDbModel.getInstance().scanLocalMusic()
}
fun stopScanLocalMusic() {
isScanning = false
if (scanningDisposable?.isDisposed == false) {
scanningDisposable?.dispose()
}
}
val localMusicBeans: Unit
get() {
LocalMusicDbModel.getInstance().localMusicInfoList
}
fun getLocalMusicBeanList(page: Int) {}
fun scanningLocalMusicBeans() {
if (isScanning) {
return
}
isScanning = true
scanningDisposable = LocalMusicDbModel.getInstance().scanLocalMusicBeans()
.compose(bindUntilEvent(PresenterEvent.DESTROY))
.compose(RxHelper.handleException())
.compose(RxHelper.handleSchedulers())
.subscribe { localMusicBeans: List<LocalMusicBean>?, throwable: Throwable? ->
isScanning = false
if (mvpView == null) {
return@subscribe
}
mvpView?.onScanningComplete()
if (throwable == null) {
mvpView?.onScanningLocalMusicSuccess(localMusicBeans)
} else {
mvpView?.onScanningLocalMusicFail(throwable)
}
}
}
fun batchAddToPlayerList(needAddList: List<LocalMusicBean>) {
//APP 本地数据库里的数据
mCopyJob = MainScope().launch {
withContext(Dispatchers.IO){
if (needAddList.isNotEmpty()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
//localMusicList 手机外置存储的歌曲,android Q+ 需要插入到app 数据库的
needAddList.forEach { music ->
val newPath = copyFileToCache(music)
if (newPath != null){
music.localUri = newPath
}
}
}
addAllDisposable = LocalMusicDbModel.getInstance().batchAddToDB(needAddList)
.compose(bindUntilEvent(PresenterEvent.DESTROY))
.compose(RxHelper.handleSchedulers())
.subscribe { ids: List<Long>?, throwable: Throwable? ->
if (mvpView == null) {
return@subscribe
}
if (throwable == null) {
mvpView?.addAllSuccess(ids)
} else {
mvpView?.addAllFail(throwable)
}
}
}
}
}
}
/**
* 音乐文件缓存目录
*/
private fun getCacheMusicDir():String{
return "${FileHelper.getRootFilesDir(Environment.DIRECTORY_MUSIC).absolutePath}${File.separator}"
}
private fun copyFileToCache(music: LocalMusicBean): String? {
val path = "${getCacheMusicDir()}${music.songName}"
return if (FileHelper.copyFileFromUri(Uri.parse(music.uri), path, false)) {
Logger.debug(TAG, "copy success, path: $path ")
path
} else {
null
}
}
override fun onDestroyPresenter() {
stopScanLocalMusic()
if (mCopyJob?.isActive == true){
mCopyJob?.cancel()
}
if (addAllDisposable?.isDisposed == false) {
addAllDisposable?.dispose()
}
super.onDestroyPresenter()
}
}

View File

@@ -1,6 +1,7 @@
package com.nnbc123.core.utils;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.media.MediaScannerConnection;
@@ -292,6 +293,12 @@ public class AsyncTaskScanMusicFile extends AsyncTask<Context, AsyncTaskScanMusi
song.setLocalUri(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA)));
song.setLocalId(cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media._ID)));
song.setSongId(SongUtils.generateThirdPartyId());
//数据库升级
int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));// 歌曲的id
Uri uri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id);
song.setUri(uri.toString());
return song;
}

View File

@@ -1,8 +1,11 @@
package com.nnbc123.app.database;
import androidx.annotation.NonNull;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import com.nnbc123.xchat_android_constants.XChatConstants;
import com.nnbc123.core.music.db.bean.LocalMusicBean;
@@ -28,6 +31,16 @@ public abstract class AppDataBase extends RoomDatabase {
return mInstance;
}
private static final Migration migration_1_2 =new Migration(1,2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL(
"ALTER TABLE local_songs"
+ " ADD COLUMN uri TEXT"
);
}
};
public abstract LocalMusicDao localMusicDao();
public abstract SongDao songDao();

View File

@@ -29,6 +29,12 @@ public class LocalMusicBean {
private String year;
@ColumnInfo(name = "duration")
private long duration;
/**
* 新增uri适配安卓10.0
*/
@ColumnInfo(name = "uri")
private String uri;
/**
* 用于列表判断是否选中
*/
@@ -83,6 +89,10 @@ public class LocalMusicBean {
public long getDuration() {
return this.duration;
}
@SuppressWarnings("all")
public String getUri() {
return this.uri;
}
/**
* 用于列表判断是否选中
@@ -137,6 +147,11 @@ public class LocalMusicBean {
this.duration = duration;
}
@SuppressWarnings("all")
public void setUri(final String uri) {
this.uri = uri;
}
/**
* 用于列表判断是否选中
*/
@@ -155,6 +170,7 @@ public class LocalMusicBean {
if (this.getId() != other.getId()) return false;
if (this.getLocalId() != other.getLocalId()) return false;
if (this.getDuration() != other.getDuration()) return false;
if (this.getUri() != other.getUri()) return false;
if (this.isSelected() != other.isSelected()) return false;
final Object this$songId = this.getSongId();
final Object other$songId = other.getSongId();
@@ -204,6 +220,8 @@ public class LocalMusicBean {
result = result * PRIME + ($artistName == null ? 43 : $artistName.hashCode());
final Object $localUri = this.getLocalUri();
result = result * PRIME + ($localUri == null ? 43 : $localUri.hashCode());
final Object uri = this.getUri();
result = result * PRIME + (uri == null ? 43 : uri.hashCode());
final Object $year = this.getYear();
result = result * PRIME + ($year == null ? 43 : $year.hashCode());
return result;
@@ -212,7 +230,7 @@ public class LocalMusicBean {
@Override
@SuppressWarnings("all")
public String toString() {
return "LocalMusicBean(id=" + this.getId() + ", localId=" + this.getLocalId() + ", songId=" + this.getSongId() + ", songName=" + this.getSongName() + ", albumName=" + this.getAlbumName() + ", artistName=" + this.getArtistName() + ", localUri=" + this.getLocalUri() + ", year=" + this.getYear() + ", duration=" + this.getDuration() + ", selected=" + this.isSelected() + ")";
return "LocalMusicBean(id=" + this.getId() + ", localId=" + this.getLocalId() + ", songId=" + this.getSongId() + ", songName=" + this.getSongName() + ", albumName=" + this.getAlbumName() + ", artistName=" + this.getArtistName() + ", localUri=" + this.getLocalUri() + ", year=" + this.getYear() + ", duration=" + this.getDuration() +", uri=" + this.getUri() + ", selected=" + this.isSelected() + ")";
}
//</editor-fold>
}

View File

@@ -1,8 +1,10 @@
package com.nnbc123.core.music.db.model;
import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import androidx.annotation.Nullable;
@@ -34,13 +36,19 @@ import io.reactivex.schedulers.Schedulers;
public class LocalMusicDbModel extends BaseModel implements ILocalMusicDbModel {
public static final String SCHEME_FILE = "file://";
public static final long DURATION_MIN = 1000;
private Context context;
private AsyncTaskScanMusicFile scanMediaTask;
private volatile boolean isRefresh;
private List<LocalMusicBean> localMusicInfoList = new ArrayList<>();
private CompositeDisposable compositeDisposable = new CompositeDisposable();
private AtomicInteger page = new AtomicInteger(0);
private LocalMusicDbModel() {
@@ -311,6 +319,13 @@ public class LocalMusicDbModel extends BaseModel implements ILocalMusicDbModel {
song.setLocalUri(data);
song.setLocalId(cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media._ID)));
song.setSongId(SongUtils.generateThirdPartyId());
//本地音乐适配android10.0
int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));// 歌曲的id
Uri uri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id);
song.setUri(uri.toString());
return song;
} catch (Exception e) {
return null;