问题
I'm learning how to use Android Room from google-developer-training, where I found example of repository class
. I try to simplify my SportRepository
class. I wonder how to avoid repetition of inner class ...AsyncTask
in my code. Here is very sample example:
@Singleton
class SportRepository {
val LOG_TAG = SportRepository::class.java.name
@Inject
lateinit var sportDAO: SportDAO
var list: LiveData<List<Sport>>
init {
App.app().appComponent()?.inject(this)
list = sportDAO.getAll()
}
fun insert(sport: Sport) {
insertAsyncTask().execute(sport)
}
fun update(sport: Sport){
updateAsyncTask().execute(sport)
}
fun delete(sport: Sport) {
deleteAsyncTask().execute(sport)
}
@SuppressLint("StaticFieldLeak")
private inner class insertAsyncTask() : AsyncTask<Sport, Void, Void>() {
override fun doInBackground(vararg p0: Sport): Void? {
sportDAO.insert(p0.get(0))
return null
}
}
@SuppressLint("StaticFieldLeak")
private inner class updateAsyncTask() : AsyncTask<Sport, Void, Void>() {
override fun doInBackground(vararg p0: Sport): Void? {
sportDAO.update(p0[0])
return null
}
}
@SuppressLint("StaticFieldLeak")
private inner class deleteAsyncTask() : AsyncTask<Sport, Void, Void>() {
override fun doInBackground(vararg p0: Sport): Void? {
sportDAO.delete(p0[0])
return null
}
}
}
The AsyncTask
classes differ only in name and in kind of method invoke from sportDAO class.
Is there any way to avoid creating many almost the same AsyncTask
classes?
I've not found any example how to simplify that.
回答1:
Ok, I faced the same. There are 3 solutions that I use. 1. Use RX. Return a Flowable, and observe it on different thread. 2. Use LiveData. 3. Async Task. This is how I avoid multiple async tasks by using Generics. I hope this is what you are looking for.
This is the class that will perform your queries.
/**
*
* @param <T> type of result expected
*/
public abstract class DaoAsyncProcessor<T> {
public interface DaoProcessCallback<T>{
void onResult(T result);
}
private DaoProcessCallback daoProcessCallback;
public DaoAsyncProcessor(DaoProcessCallback daoProcessCallback) {
this.daoProcessCallback = daoProcessCallback;
}
protected abstract T doAsync();
public void start(){
new DaoProcessAsyncTask().execute();
}
private class DaoProcessAsyncTask extends AsyncTask<Void, Void, T>{
@Override
protected T doInBackground(Void... params) {
return doAsync();
}
@Override
protected void onPostExecute(T t) {
if(daoProcessCallback != null)
daoProcessCallback.onResult(t);
}
}
}
Now for querying
fun putAllUsersAsync(vararg users: User) {
object : DaoAsyncProcessor<Unit>(null) {
override fun doAsync(): Unit {
yourDao.insertAll(*users)
}
}.start()
}
Another example of fetching data.
fun getAllUsers(callback: DaoAsyncProcessor.DaoProcessCallback<List<User>>) {
object : DaoAsyncProcessor<List<User>>(callback) {
override fun doAsync(): List<User> {
return yourDao.getAll()
}
}.start()
You can call getAllUsers and pass a callback for getting the data.
As requested, this is the Kotlin equivalent
abstract class DaoAsyncProcessor<T>(val daoProcessCallback: DaoProcessCallback<T>?) {
interface DaoProcessCallback<T> {
fun onResult(result: T)
}
protected abstract fun doAsync(): T
fun start() {
DaoProcessAsyncTask().execute()
}
private inner class DaoProcessAsyncTask : AsyncTask<Void, Void, T>() {
override fun doInBackground(vararg params: Void): T {
return doAsync()
}
override fun onPostExecute(t: T) {
daoProcessCallback?.onResult(t)
}
}
}
回答2:
Using RX java you could replace AsyncTask with a Completable for your insert/update/delete commands.
fun insert(sport: Sport) : Completable = Completable.fromAction { sportDAO.insert(sport) }
fun update(sport: Sport) : Completable = Completable.fromAction { sportDAO.update(sport) }
fun delete(sport: Sport) : Completable = Completable.fromAction { sportDAO.delete(sport) }
回答3:
You could use the same AsyncTask for each task if you pass it the code segment that it needs to actually execute.
You could for example do the following, using lambda-with-receivers
(and without having to add Rx completables/singles or whatever):
@Singleton
class SportRepository @Inject constructor(val sportDAO: SportDao) {
companion object {
const val LOG_TAG = "SportRepository"
}
var list: LiveData<List<Sport>> = sportDAO.getAll() // is this necessary?
fun insert(sport: Sport) {
executeTask(sport) { insert(it) }
}
fun update(sport: Sport){
executeTask(sport) { update(it) }
}
fun delete(sport: Sport) {
executeTask(sport) { delete(it) }
}
private fun executeTask(sport: Sport, task: SportDao.(Sport) -> Unit) {
BackgroundTask(sport, task).execute()
}
@SuppressLint("StaticFieldLeak")
private inner class BackgroundTask(
private val sport: Sport,
private val task: SportDao.(Sport) -> Unit
) : AsyncTask<Void, Void, Void>() {
override fun doInBackground(vararg p0: Void): Void? {
task(sportDAO, sport)
return null
}
}
}
来源:https://stackoverflow.com/questions/49520123/how-to-avoid-occurring-many-asynctask-class-in-my-android-room-repository