代写辅导接单-A. Random Cards-Room

欢迎使用51辅导,51作业君孵化低价透明的学长辅导平台,服务保持优质,平均费用压低50%以上! 51fudao.top

A.RandomCards-Room

database

A.0WhatisaRoomdatabase?

Adatabaseisanorganizedcollectionofstructuredinformation,ordata,

typicallystoredelectronicallyinacomputersystem.Adatabaseisusually

controlledbyadatabasemanagementsystem(DBMS).[oracle.com]Android

usesSQLiteasadatabasemanagementsystem.

FormoredetailscheckthecontentprovidedunderWeek7>LectureMaterial>

DatabaseandSQL

BEFOREYOUBEGIN:Downloadthefollowingapplicationprojectasastarterapplication.

RandomCardsDatabase_Start.zip

AboveappisoutputofWeek6LabTask>C.GsontosaveArrayListtoSharedPreferences.Wewill

replaceSharedPreferencesstorelocationofthisapplicationprojectwithRoomDatabase.

A.1Importdependencies

RoomdatabaselibraryisavailablefromtheAndroidXpackage,toimportthemnavigate

toapp>GradleScripts>build.gradle.kts(Module:app)

Underthedependenciessectionaddtheselines:

//importRoomdatabasecommonandruntimepackages

implementation("androidx.room:room-common:2.6.1")

implementation("androidx.room:room-runtime:2.6.1")

//toparseannotationseg@Database,@Entity,@DAO,etc

annotationProcessor("androidx.room:room-compiler:2.6.1")

Onceaddedclickon"SyncNow"whichappearsatthetoponcechangesaredetectedinthefile.

A.2AddnewDatabaseClass

BeforeaddingthenewDatabaseclasslet'scontaineverythinginsideasubfoldertohaveseparationofconcern

andalldatabase-relatedfileswillbecontainedinsideonefolder.

Right-clickonthepackagefolder(com.fit2081.recyclerviewcards)andaddapackagecalled"provider".

Seemoredetailshere...

NowgoaheadandcreateanewJavaclassinsidethisnewpackage,named

"CardDatabase"andcarefullyreplacetheclassimplementationwiththeprovidedcode.

packagecom.fit2081.recyclerviewcards.provider;

importandroid.content.Context;

importandroidx.room.Database;

importandroidx.room.Room;

importandroidx.room.RoomDatabase;

importjava.util.concurrent.ExecutorService;

importjava.util.concurrent.Executors;

@Database(entities={},version=1)

publicabstractclassCardDatabaseextendsRoomDatabase{

//databasename,thisisimportantasdataiscontainedinsideafilenamed

"card_database"

publicstaticfinalStringCARD_DATABASE="card_database";

//markingtheinstanceasvolatiletoensureatomicaccesstothevariable

privatestaticvolatileCardDatabaseINSTANCE;

privatestaticfinalintNUMBER_OF_THREADS=4;

//ExecutorServiceisaJDKAPIthatsimplifiesrunningtasksinasynchronous

mode.

//Generallyspeaking,ExecutorServiceautomaticallyprovidesapoolofthreads

andanAPI

//forassigningtaskstoit.

staticfinalExecutorServicedatabaseWriteExecutor=

Executors.newFixedThreadPool(NUMBER_OF_THREADS);

}

Thisway,wecommunicatewithruntimeandprocessortonotreorderanyinstructions

involvingthevolatilevariable.Also,processorsunderstandthattheyshouldimmediately

makeanyupdatestothesevariables.

Nowbecausethisisanabstractclass,weneedaddadatabasereferenceforan

implementation.

staticfinalExecutorServicedatabaseWriteExecutor=

Executors.newFixedThreadPool(NUMBER_OF_THREADS);

/**

*Sincethisclassisanabsractclass,togetthedatabasereferencewewould

need

*toimplementawaytogetreferencetothedatabase.

*

*@paramcontextApplicationofActivityContext

*@returnareferencetothedatabaseforreadandwriteoperation

*/

staticCardDatabasegetDatabase(finalContextcontext){

if(INSTANCE==null){

synchronized(CardDatabase.class){

if(INSTANCE==null){

INSTANCE=

Room.databaseBuilder(context.getApplicationContext(),

CardDatabase.class,CARD_DATABASE)

.build();

}

}

}

returnINSTANCE;

}

Pleasenotethesynchronizedkeywordabove.

Synchronizedblocksormethodspreventsthreadinterferenceandmakesure

thatdataisconsistent.Atanypointoftime,onlyonethreadcanaccessa

synchronizedblockormethod(criticalsection)byacquiringalock.Other

thread(s)willwaitforreleaseoflocktoaccesscriticalsection.Methodsare

synchronizedwhenyouadd

synchronized

tomethoddefinitionordeclaration.

Youcanalsosynchronizeaparticularblockofcodewith-inamethod.

Itmeansthatonlyonethreadcanaccesscriticalsectionbyacquiringalock.

Unlessthisthreadreleasethislock,allotherthread(s)willhavetowaitto

acquirealock.Theydon'thaveaccesstoentercriticalsectionwithout

acquiringlock.It'sprogrammerresponsibilitytoidentifycriticalsection(s)in

applicationandguarditaccordingly.Javaprovidesaframeworktoguardyour

application,butwhichsectionstobeguardedistheresponsibilityof

programmer.Source

A.3Transformthe"Item"classtoRoomEntity

OpenItem.javaandimplementthefollowing

A.3.1Entityannotation

Inthelinebefore"publicclassItem"add"@Entity"annotationthiswillidentifythisclass

asaRoomDatabaseentity.Anentityisequivalenttoadatabasetable.Youcangiveita

tableNamehereaswell(sowecanaccessitlaterusingthisname).

@Entity(tableName="items")

A.3.2Addnewcolumn"Id"

Toidentifyeachrecordinthetable,weaddthis"id"field,wewantthisfield'svaluetobe

auto-generatedonthesaveofanewrecord,thiswaywedonothavetoworryabout

implementingourcustomuniquenesslogic.

@PrimaryKey(autoGenerate=true)

@ColumnInfo(name="id")

privateintid;

Ifyouopttocopyandpastetheabovecode,don'tforgettoresolvedependencies.

A.3.3Annotateotherclassattributesusingthe"ColumnInfo"annotation

ColumnInfoannotationhelpsusmarkclassattributesasdatabasecolumnsandspecify

theattribute'scolumnnameinthesameline.

@ColumnInfo(name="suit")

privateStringsuit;

@ColumnInfo(name="card")

privateStringcard;

A.3.4AddGetter&Settermethodfor"Id"column

Right-clickwithinItem.javaclass>Generate>GetterandSetter>Selectonlythe"id"

columnasothercolumnsalreadyhavetheirgettermethod&setisdoneusingthe

constructorclass.

HereisthecompletedcodeoftheItem.javaclass,noticethatlinenumber7specifies

thetablename"items"

packagecom.fit2081.recyclerviewcards;

importandroidx.room.ColumnInfo;

importandroidx.room.Entity;

importandroidx.room.PrimaryKey;

@Entity(tableName="items")

publicclassItem{

@PrimaryKey(autoGenerate=true)

@ColumnInfo(name="id")

privateintid;

@ColumnInfo(name="columnSuit")

privateStringsuit;

@ColumnInfo(name="columnCard")

privateStringcard;

publicItem(Stringsuit,Stringcard){

this.suit=suit;

this.card=card;

}

publicStringgetSuit(){

returnsuit;

}

publicStringgetCard(){

returncard;

}

publicintgetId(){

returnid;

}

publicvoidsetId(intid){

this.id=id;

}

}

Important:NowgobacktoCardDatabaseclassanddeclarethisentityclassasoneofthedatabase

tablesofCardDatabase.java,asshownbelow.YoucandothisabovethedeclarationofCardDatabse-

seebelow.

JAVA

@Database(entities={Item.class},version=1)

publicabstractclassCardDatabaseextendsRoomDatabase{

A.4Adddataaccessobject-DAO

Addanewinterfacenamed"CardDAO",makesuretoselect"interface"beforeyouhit

enterafterspecifyingthename,seethestepsbelow.

1.Addannotation"@Dao"tothisinterface,whichstandsforDataAccessObject

2.Addtwokeymethods:

○Insertnewitemrecord(C-fromCRUD)

○Getallitemsfromthedatabase(R-fromCRUD)

HereisthecompletedcodeforDAO,whichusesaLiveDataholder(seelectureslides)

LiveDataisanobservabledataholderclass.Unlikearegularobservable,

LiveDataislifecycle-aware,meaningitrespectsthelifecycleofotherapp

components,suchasactivities,fragments,orservices.Thisawareness

ensuresLiveDataonlyupdatesappcomponentobserversthatareinanactive

lifecyclestate.Source

JAVA

packagecom.fit2081.recyclerviewcards.provider;

importandroidx.lifecycle.LiveData;

importandroidx.room.Dao;

importandroidx.room.Insert;

importandroidx.room.Query;

importcom.fit2081.recyclerviewcards.Item;

importjava.util.List;

//IndicatesthatthisinterfaceisaDataAccessObject(DAO),

//usedforinteractingwiththedatabase.

@Dao

publicinterfaceCardDAO{

////Specifiesadatabasequerytoretrieveallitemsfromthe"items"table.(referenced

A.3.4)

@Query("select*fromitems")

LiveData>getAllItems();//ReturnsaLiveDataobjectcontainingalistof

Itemobjects.

//Indicatesthatthismethodisusedtoinsertdataintothedatabase.

@Insert

voidaddItem(Itemitem);//MethodsignatureforinsertinganItemobjectintothe

database.

}

NoticetableNameattributewespecifiedinA.3.4isreferencedinline15above.

InitialisetheDAOvariableinsidetheCardDatabaseclassasshownbelow.

//referencetoDAO,hereRoomDatabaseparentclasswillimplementthisinterface

publicabstractCardDAOcardDAO();

A.5CreateRepositoryclass

CreateanewJavaclass"CardRepository"andreplacethecodespecifiedbelow,read

inlinecommentsformoredetails.

InAndroiddevelopmentwithRoom,arepositoryclasstypicallyinteractswith

theRoomdatabasethroughDAOs(DataAccessObjects)andprovides

methodsforaccessingandmanipulatingdata.Thishelpstokeepthedata

accesslogicseparatefromtheUIlogic,followingtheprinciplesofseparationof

concernsandsingleresponsibility.Thinkaboutit.Whenyouhavemultipledata

sources,inthatcase,therepositorywillactasasinglesourceoftruthhaving

dataavailablefromdifferentsourcesandservingthedatatotheViewModel

class.

packagecom.fit2081.recyclerviewcards.provider;

importandroid.app.Application;

importandroidx.lifecycle.LiveData;

importcom.fit2081.recyclerviewcards.Item;

importjava.util.List;

publicclassCardRepository{

//privateclassvariabletoholdreferencetoDAO

privateCardDAOcardDAO;

//privateclassvariabletotemporaryholdalltheitemsretrievedandpassoutsideof

thisclass

privateLiveData>allCardsLiveData;

//constructortoinitialisetherepositoryclass

CardRepository(Applicationapplication){

//getreference/instanceofthedatabase

CardDatabasedb=CardDatabase.getDatabase(application);

//getreferencetoDAO,toperformCRUDoperations

cardDAO=db.cardDAO();

//oncetheclassisinitialisedgetalltheitemsintheformofLiveData

allCardsLiveData=cardDAO.getAllItems();

}

/**

*Repositorymethodtogetallcards

*@returnLiveDataoftypeList

*/

LiveData>getAllCards(){

returnallCardsLiveData;

}

/**

*Repositorymethodtoinsertonesingleitem

*@paramcardobjectcontainingdetailsofnewItemtobeinserted

*/

voidinsert(Itemcard){

//Executesthedatabaseoperationtoinserttheiteminabackgroundthread.

CardDatabase.databaseWriteExecutor.execute(()->cardDAO.addItem(card));

}

}

Letstakeacloserlookatthiscode..

CardDatabase.databaseWriteExecutor.execute(()->cardDAO.addItem(card))

:

Thislineofcodeexecutesadatabaseoperationtoinserttheitem.It'susinganexecutor

(

databaseWriteExecutor

)torunthisoperationonabackgroundthreadtoavoid

blockingthemainUIthread.The

execute()

methodtakesalambdaexpression(

()->

cardDAO.addItem(card)

)asanargument,whichencapsulatesthedatabaseoperation

tobeexecuted.

A.6CreateViewModelclass

ViewModelclassisusedforpre-processingthedata,beforepassingittothecontrollers

(ActivityorFragments).ViewModelclassshouldnotholddirectreferencetothe

database.ViewModelclassreliesontherepositoryclass,hencethedatabaseis

accessedusingtheRepositoryclass.

CreateanewViewModelclasscallit"CardViewModel"andusetheprovidedcodeto

completeit,readinlinecommentsformoredetails.

packagecom.fit2081.recyclerviewcards.provider;

importandroid.app.Application;

importandroidx.annotation.NonNull;

importandroidx.lifecycle.AndroidViewModel;

importandroidx.lifecycle.LiveData;

importcom.fit2081.recyclerviewcards.Item;

importjava.util.List;

/**

*ViewModelclassisusedforpre-processingthedata,

*beforepassingittothecontrollers(ActivityorFragments).ViewModelclassshouldnot

hold

*directreferencetodatabase.ViewModelclassreliesonrepositoryclass,hencethe

databaseis

*accessedusingtheRepositoryclass.

*/

publicclassCardViewModelextendsAndroidViewModel{

//referencetoCardRepository

privateCardRepositoryrepository;

//privateclassvariabletotemporaryholdalltheitemsretrievedandpassoutsideof

thisclass

privateLiveData>allCardsLiveData;

publicCardViewModel(@NonNullApplicationapplication){

super(application);

//getreferencetotherepositoryclass

repository=newCardRepository(application);

//getallitemsbycallingmethoddefinedinrepositoryclass

allCardsLiveData=repository.getAllCards();

}

/**

*ViewModelmethodtogetallcards

*@returnLiveDataoftypeList

*/

publicLiveData>getAllCards(){

returnallCardsLiveData;

}

/**

*ViewModelmethodtoinsertonesingleitem,

*usuallycallinginsertmethoddefinedinrepositoryclass

*@paramcardobjectcontainingdetailsofnewItemtobeinserted

*/

publicvoidinsert(Itemcard){

repository.insert(card);

}

}

NowbothViewModel&Repositoryclassesaredefined,andanytimeMainActivityneeds

dataorneedstoinsertdataitwillgointhissequence.

MainActivity>ViewModel>Repository>DAO>Database.

Thisisabreakdownofourfiles(approximation):

A.7Insertarandomcard

GotoMainActivityanddeclareaclassvariabletoholdareferencetoCardViewModel.

privateCardViewModelcardViewModel;

insideonCreatemethodofMainActivityinitialiseViewModel.

//initialiseViewModel

cardViewModel=newViewModelProvider(this).get(CardViewModel.class);

UpdatetheaddItemmethodasperbelowbycallingCardViewModel'sinsertmethod.

publicvoidaddItem(){

Randomrandom=newRandom();

intrandCard=random.nextInt(cards.length);

intrandSuit=random.nextInt(suits.length);

Itemitem=newItem(suits[randSuit],cards[randCard]);

//insertnewrecordtodatabase

cardViewModel.insert(item);

//noneedofnotifyDataSetChangedhereasitwillbedonebyLiveDatasubscription

above

//data.add(item);

//adapter.notifyDataSetChanged();

//savethewholelisttoSharedPreferencesoneachaddItem

//saveArrayListAsText();

}

A.8Readallcards&displayusingRecyclerView

InsidetheonCreatemethodafterinitiatingtheCardViewModel,subscribetoLiveDataof

typeArrayList.Readingallitemsandsubscribingtoanyfurtherupdates.

//subscribetoLiveDataoftypeArrayList,

//anychangesdetectedinthedatabasewillbenotifiedtoMainActivity

cardViewModel.getAllCards().observe(this,newData->{

//castListtoArrayList

adapter.setData(newArrayList(newData));

adapter.notifyDataSetChanged();

});

OpentheAppInspectionwindowtoinspectthedatabasewithinAndroidStudio,even

thoughitisstoredinthevirtualandroiddevice.

Tips

●Tickthe"Liveupdates"boxashighlightedbelowseeredhighlight.

●ThetablenamewedefinedinItem.javaline7,isvisibleasoneoftheoptions

underthelistoftables,seethegreenhighlight.

●Similarly,thecolumnnamesarevisibleinthesnippetbelow,seetheblue

highlights.

Welldone!Thiswasamassiveeffort,youhavecompleteddatabaseimplementationin

anAndroidproject!

51作业君

Email:51zuoyejun

@gmail.com

添加客服微信: abby12468