E/RecyclerView: No adapter attached; skipping layout in my fragment - java

I can run this and I also got data appear but I got this warning on my Run terminal
"E/RecyclerView: No adapter attached; skipping layout
No adapter attached; skipping layout"
How can I solve this
class SpacedFragment : Fragment() {
private lateinit var kanjiViewModel : KanjiViewModel
private lateinit var spacedRecyclerAdapter : SpacedRecyclerAdapter
private lateinit var day1Adapter: SpacedRecyclerAdapter
private var _binding : FragmentSpacedBinding? = null
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View {
_binding = FragmentSpacedBinding.inflate(inflater,container,false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initUI()
}
private fun initUI() {
val dao = KanjiDatabase.getInstance(requireContext()).dao()
val repository = KanjiRepository(dao)
val factory = KanjiViewModelFactory(repository)
kanjiViewModel = ViewModelProvider(this,factory)[KanjiViewModel::class.java]
//adapter
spacedRecyclerAdapter = SpacedRecyclerAdapter()
day1Adapter = SpacedRecyclerAdapter()
//layoutManager
binding.spacedRecyclerview.layoutManager = GridLayoutManager(context,5)
binding.spacedRecyclerviewDay1.layoutManager = GridLayoutManager(context,5)
getData()
}
private fun getData() {
kanjiViewModel.kanjiList.observe(viewLifecycleOwner, { data ->
spacedRecyclerAdapter.submitList(data.filter { it.spacedstatus == 0 })
binding.spacedRecyclerview.adapter = spacedRecyclerAdapter
day1Adapter.submitList(data.filter { it.Japanese_Language_Proficiency_Test == 4 })
binding.spacedRecyclerviewDay1.adapter = day1Adapter
})
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

There is a sorting error in the relevant lines.
day1Adapter.submitList(data.filter { it.Japanese_Language_Proficiency_Test == 4 })
binding.spacedRecyclerviewDay1.adapter = day1Adapter
You should use submitlist after assigning adapter

set your adapter inside initUI function
private fun initUI() {
...code
spacedRecyclerAdapter = SpacedRecyclerAdapter()
binding.spacedRecyclerview.adapter = spacedRecyclerAdapter
day1Adapter = SpacedRecyclerAdapter()
binding.spacedRecyclerviewDay1.adapter = day1Adapter
...code
getData()
}
private fun getData() {
kanjiViewModel.kanjiList.observe(viewLifecycleOwner, { data ->
spacedRecyclerAdapter.submitList(data.filter { it.spacedstatus == 0 })
day1Adapter.submitList(data.filter { it.Japanese_Language_Proficiency_Test == 4 })
})
}

Related

Incorrect data in recycleview

I am using RecycleView in android studio. When data is coming from Firebase it is correct at first. Later, when I add 1 sms to the list of type List(), I get wrong data as a result.
For example:
If List is {1,2,3,4,5},
Add 6 to the list on the screen
The elements of List {1,2,3,4,5,6} should appear in this order.
In this case,
After the chase
List {1,2,3,4,5,1,2,3,4,5,6} is like this. After 1 update it works fine.
class ChatAdapter(var list:MutableList<Sms>,var context: Context):RecyclerView.Adapter<RecyclerView.ViewHolder>(){
companion object {
private const val ITEM_RECEIVE = 1
private const val ITEM_SENT = 2
}
private val shared by lazy {
SharedPref(context)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == 1) {
val view = LayoutInflater.from(context).inflate(R.layout.item_he_sms, parent, false)
ReceiveVewHolder(view)
}else{
val view = LayoutInflater.from(context).inflate(R.layout.item_my_sms, parent, false)
SentViewHolder(view)
}
}
override fun getItemViewType(position: Int): Int {
val currentMessage = list[position]
return if (currentMessage.emailAddress==shared.getEmail()){
ITEM_SENT
}else{
ITEM_RECEIVE
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (shared.getEmail()==list[position].emailAddress){
holder as SentViewHolder
holder.textView.text = list[position].smsText
}else{
holder as ReceiveVewHolder
holder.textView.text = list[position].smsText
if (list[position].gender=="Male"){
holder.imagePerson.setImageResource(R.drawable.male_avatar)
}else{
holder.imagePerson.setImageResource(R.drawable.female_avatar)
}
}
}
override fun getItemCount(): Int =list.size
inner class SentViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView = view.findViewById(R.id.my_message)
}
inner class ReceiveVewHolder(view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView = view.findViewById(R.id.he_message)
val imagePerson:CircleImageView=view.findViewById(R.id.imagePerson)
}
}
Create this methode inside your Adapter :
fun updateList(list: List<Sms>){
this.list.clear()
this.list.addAll(list)
notifyDataSetChanged()
}
then call it from inside your observer method, it should resolve your problem.
Xato Firebase'dan getAllSms da, sendSms() usuli ishlayotganda, {1,2,3,4,5,1,2,3,4,5,6} ro'yxat sifatida qaytariladi. result.invoke ni bajarishdan oldin onDataChange-da list.clear ni bajarishingiz kerak.
override fun getAllSms(result: (UiState<ArrayList<Sms>>) -> Unit) {
CoroutineScope(Dispatchers.IO).launch {
val list = ArrayList<Sms>()
myRef.getReference("global")
.addValueEventListener(object :ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
list.clear()
snapshot.children.forEach {
val sms:Sms=it.getValue(Sms::class.java)!!
list.add(sms)
}
list.forEach {
Log.d("LLIISSTT", it.smsText)
}
result.invoke(UiState.Success(list))
}
override fun onCancelled(error: DatabaseError) {
result.invoke(UiState.Failure(error.message))
}
})
}
}

How to combine two Adapter from call response in Android Java?

Is there a way to combine two adapters that are inside a Callback from Model?
Like, I get data from two sources and I want to display both of them in the same recyclerView
I tried to load the method first then put both adapters on concatAdapter but I got a null from this concatAdapter and then my app crashed
here is my method in Java
private void fetchDataKabupaten(){
progressBar.setVisibility(View.VISIBLE);
token = getIntent().getStringExtra("token");
Call<KabupatenModel> kabupatenModelCall = RetrofitClient.getLoginInterface().getKabupatenData("Bearer "+token);
kabupatenModelCall.enqueue(new Callback<KabupatenModel>() {
#Override
public void onResponse(Call<KabupatenModel> call, Response<KabupatenModel> response) {
kabupatenList = response.body().getKabupaten();
adKabupaten = new KabupatenAdapter(MainActivity.this, kabupatenList);
progressBar.setVisibility(View.GONE);
}
}
private void fetchDataKecamatan(){
progressBar.setVisibility(View.VISIBLE);
token = getIntent().getStringExtra("token");
Call<KecamatanModel> kecamatanModelCall = RetrofitClient.getLoginInterface().getKecamatanData("Bearer " + token);
kecamatanModelCall.enqueue(new Callback<KecamatanModel>() {
#Override
public void onResponse(Call<KecamatanModel> call, Response<KecamatanModel> response) {
kecamatanList = response.body().getKecamatan();
adKecamatan = new KecamatanAdapter(MainActivity.this, kecamatanList);
progressBar.setVisibility(View.GONE);
}
}
I have tried to call both in MainActivity then setAdapter with concatAdapter like this:
fetchDataKabupaten();
fetchDataKecamatan();
concatAdapter = new ConcatAdapter(adKecamatan, adKabupaten);
rV.setAdapter(concatAdapter);
why is it null?
but, when I only set one Adapter inside the response method it works.
you can only use one adapter in recyclerview, but adapter can have multiple view.
for example I have adapter for chat, with right and left view
Adapter Chat Detail
class AdapterChatDetail(val datas: ArrayList<ChatMessage>) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private lateinit var ctx: Context
companion object {
const val LEFT = 0
const val RIGHT = 1
}
inner class ViewHolderLeft(val binding: AdapterMyChatLeftBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(data: ChatMessage) {
}
}
inner class ViewHolderRight(val binding: AdapterMyChatRightBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(data: ChatMessage) {
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
ctx = parent.context
return when (viewType) {
LEFT -> ViewHolderLeft(
AdapterMyChatLeftBinding.inflate(
LayoutInflater.from(ctx),
parent,
false
)
)
RIGHT -> ViewHolderRight(
AdapterMyChatRightBinding.inflate(
LayoutInflater.from(ctx),
parent,
false
)
)
else -> ViewHolderLeft(
AdapterMyChatLeftBinding.inflate(
LayoutInflater.from(ctx),
parent,
false
)
)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (getItemViewType(position)) {
LEFT -> (holder as ViewHolderLeft).bind(datas[position])
RIGHT -> (holder as ViewHolderRight).bind(datas[position])
}
}
override fun getItemCount() = datas.size
override fun getItemViewType(position: Int): Int {
val data = datas[position]
return if (data.position == "right") RIGHT else LEFT
}
}

Swipe detection and Touch listener not working inside fragment

App has bottom navigation menus and fragments. This is the fragment which requires swipe detection similar to Tinder:
class HomeFragment : Fragment() {
private lateinit var homeViewModel: HomeViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
homeViewModel =
ViewModelProvider(this).get(HomeViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_home, container, false)
val textView: TextView = root.findViewById(R.id.text_home)
homeViewModel.text.observe(viewLifecycleOwner, {
textView.text = it
})
root.setOnTouchListener(object : OnSwipeTouchListener(requireContext()) {
override fun onSwipeRight() {
Toast.makeText(requireContext(), "Swiped right!", Toast.LENGTH_SHORT).show()
}
override fun onSwipeLeft() {
Toast.makeText(requireContext(), "Swiped left!", Toast.LENGTH_SHORT).show()
}
})
return root
}
}
The app needs Swipe features like Tinder.
Following is the Listener class:
open class OnSwipeTouchListener(ctx: Context) : OnTouchListener {
val gestureDetector: GestureDetector
companion object {
private val SWIPE_THRESHOLD = 100
private val SWIPE_VELOCITY_THRESHOLD = 100
}
init {
gestureDetector = GestureDetector(ctx, GestureListener())
}
override fun onTouch(v: View, event: MotionEvent): Boolean {
var isTouch = false
if (gestureDetector != null && event != null) {
isTouch = gestureDetector.onTouchEvent(event)
} else {
isTouch = true
}
return isTouch
}
inner class GestureListener : SimpleOnGestureListener() {
override fun onDown(e: MotionEvent): Boolean {
return false
}
override fun onFling(e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean {
var result = false
try {
val diffY = e1?.y?.let { e2?.y?.minus(it) }
val diffX = e1?.x?.let { e2?.x?.minus(it) }
if (diffX != null && diffY != null) {
if (abs(diffX) > abs(diffY)) {
if (abs(diffX) > SWIPE_THRESHOLD && abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
onSwipeRight()
} else {
onSwipeLeft()
}
result = true
}
}
} else {
onSwipeRight()
result = true
}
} catch (exception: Exception) {
exception.printStackTrace()
}
return result
}
}
open fun onSwipeRight() {}
open fun onSwipeLeft() {}
open fun onSwipeTop() {}
open fun onSwipeBottom() {}
open fun onSwipeDown() {
}
}
The swipe feature or any sort of touch listeners are not working at all. Why is this happening? I'm new to Kotlin and mobile app development. So any help is very appreciated.
In Android, a gesture is defined as the beginning of ACTION_DOWN and ending with ACTION_UP. If you want your view to receive a gesture, you MUST return true for ACTION_DOWN, otherwise, you will got nothing.
Root cause
override fun onDown(e: MotionEvent): Boolean {
return false
}
Because in this callback, you return false, that means your view does not show interest to any gesture, it explains why all callback such as onFling(), onSwipeRight(), onSwipeLeft() is not called.
Solution
Return true for the ACTION_DOWN event.
override fun onDown(e: MotionEvent): Boolean {
return true
}
Here is a great article about the Android Touch System. Please take a look when you have time.

RecyclerView Adapter methods not getting called kotlin

In the Adapter method. i am able to print list elements in updateUsers(newUsers: List)
that means I am getting dataset in the Adapter, but none of the Adapter methods are getting called.
I have set the layout manager too.
I have breakpoints for All adapter methods onCreateViewHolder, onBindViewHolder. but control is not entering code block.
class MainActivity : AppCompatActivity() {
lateinit var viewModel: ListViewModel
private val usersAdapter = UserListAdapter(arrayListOf(),this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProviders.of(this).get(ListViewModel::class.java)
viewModel.refresh()
usersList.apply {
layoutManager = LinearLayoutManager(this.context)
adapter = usersAdapter
}
usersList.adapter = usersAdapter
observeViewModel()
}
fun observeViewModel() {
viewModel.users.observe(this, Observer {
it?.let {
it.forEach {
Log.d("Each Item", it.toString());
}
loading_view.visibility = View.VISIBLE
usersAdapter.updateUsers(it)
}
})
viewModel.userLoadError.observe(this, Observer {
it?.let {
list_error.visibility = if (it) View.VISIBLE else View.GONE
}
})
viewModel.loading.observe(this, Observer {
it?.let {
loading_view.visibility = if (it) View.VISIBLE else View.GONE
if (it) {
list_error.visibility = View.GONE
usersList.visibility = View.GONE
}
}
})
}
}
class UserListAdapter(private var users: ArrayList<User>, private val context : Context) : RecyclerView.Adapter<UserListAdapter.UserViewHolder>() {
fun updateUsers(newUsers: List<User>) {
newUsers.forEach() {
Log.d("updateUsers", it.firstName)
}
users.clear()
users.addAll(newUsers)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) : UserViewHolder{
val layoutInflator = LayoutInflater.from(parent.context)
val view = layoutInflator.inflate(R.layout.item_layout,parent,false)
return UserViewHolder(view)
}
override fun getItemCount():Int {
return users.size
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
holder.bind(users[position])
}
class UserViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private val imageView = view.imageView
private val userName = view.name
private val userEmail = view.email
fun bind(country: User) {
userName.text = country.firstName + " " + country.lastName
userEmail.text = country.email
imageView.loadImage(country.avatar)
}
}
}
I am not exactly sure why your code is not working, here I have implemented using your code and it's working.
MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: ListViewModel
private val usersAdapter = UserListAdapter(arrayListOf(), this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProviders.of(this).get(ListViewModel::class.java)
viewModel.refresh()
usersList.apply {
layoutManager = LinearLayoutManager(this.context,
RecyclerView.VERTICAL, false)
adapter = usersAdapter
}
// usersList.adapter = usersAdapter // Don't need, you already set the
// adapter above.
observeViewModel()
}
private fun observeViewModel() {
viewModel.users.observe(this, Observer {
it?.let {
it.forEach {
Log.d("Each Item", it.toString());
}
//loading_view.visibility = View.VISIBLE
usersAdapter.updateUsers(it)
}
})
// commented for simplicity
//viewModel.userLoadError.observe(this, Observer {
// it?.let {
//list_error.visibility = if (it) View.VISIBLE else View.GONE
// }
//})
// viewModel.loading.observe(this, Observer {
// it?.let {
// loading_view.visibility = if (it) View.VISIBLE else View.GONE
// if (it) {
// list_error.visibility = View.GONE
// usersList.visibility = View.GONE
// }
//
// }
// })
}
}
UserListAdapter
class UserListAdapter(private var users: ArrayList<User>, private val context : Context) : RecyclerView.Adapter<UserListAdapter.UserViewHolder>() {
fun updateUsers(newUsers: List<User>) {
newUsers.forEach() {
Log.d("updateUsers", it.firstName)
}
users.clear()
users.addAll(newUsers)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) : UserViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.item_layout,parent,false)
return UserViewHolder(view)
}
override fun getItemCount():Int {
return users.size
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
holder.bind(users[position])
}
class UserViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private val imageView = view.imageView
private val userName = view.name
private val userEmail = view.email
fun bind(country: User) {
userName.text = country.firstName + " " + country.lastName
userEmail.text = country.email
//imageView.loadImage(country.avatar)
}
}
}
ListViewModel
class ListViewModel: ViewModel() {
val users : MutableLiveData<List<User>> = MutableLiveData()
fun refresh() {
val userList = mutableListOf<User>()
userList.add(User(
"User1 First Name",
"User1 last Name",
"example#gmail.com"
))
userList.add(User(
"User2 First Name",
"User2 First Name",
"example#gmail.com"
))
userList.add(User(
"User3 First Name",
"User3 First Name",
"example#gmail.com"
))
userList.add(User(
"User4 First Name",
"User4 First Name",
"example#gmail.com"
))
userList.add(User(
"User5 First Name",
"User5 First Name",
"example#gmail.com"
))
userList.add(User(
"User6 First Name",
"User6 First Name",
"example#gmail.com"
))
users.value = userList
}
}
Hope this helps.

How to make phone call using intent after getting contact name and number

I am a newbie on android.
I already made an activity that shows all my contact list and number inside Linear Layout. How can I make phone call using intent after I click the Linear Layout?
I don't know where to put the setOnclickListener in my code. So here I share all of the source-code.
XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/listContacts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:orientation="vertical">
<TextView
android:id="#+id/itemName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="Nama : "
style="#style/Base.TextAppearance.AppCompat.Headline"/>
<TextView
android:id="#+id/itemNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:text="Nomor HP : "
style="#style/Base.TextAppearance.AppCompat.Body2"/>
</LinearLayout>
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
showDetail.setOnClickListener {
var myDetailIntent = Intent(this, DetailActivity::class.java)
startActivity(myDetailIntent)
}
doAsync {
Thread.sleep(5000L)
uiThread {
showNotivy();
}
}
}
private fun showNotivy() {
val notfyDetailIntent = Intent(this#MainActivity,
DetailActivity::class.java)
val myPendingIntent = TaskStackBuilder.create(this)
.addParentStack(DetailActivity::class.java)
.addNextIntent(notfyDetailIntent)
.getPendingIntent(110, PendingIntent.FLAG_UPDATE_CURRENT)
val myNotfyManager = this.getSystemService(android.content.Context.NOTIFICATION_SERVICE) as NotificationManager
val myBuilder = NotificationCompat.Builder(this)
.setContentTitle("Show Detail Contact")
.setContentText("Click Me !")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(myPendingIntent)
.setAutoCancel(true)
myNotfyManager.notify(1101, myBuilder.build())
}
}
DetailActivity.kt
class DetailActivity : AppCompatActivity(), LoaderManager.LoaderCallbacks<Cursor> {
var DISPLAY_NAME = ContactsContract.Contacts.DISPLAY_NAME
var NUMBER = ContactsContract.CommonDataKinds.Phone.NUMBER
val myListContact : MutableList<myContact> = ArrayList();
override fun onCreateLoader(p0: Int, p1: Bundle?): Loader<Cursor> {
val MyContentUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI
val myProjection = arrayOf(DISPLAY_NAME, NUMBER)
return CursorLoader(this, MyContentUri, myProjection, null, null, DISPLAY_NAME+ " ASC")
}
override fun onLoadFinished(p0: Loader<Cursor>, p1: Cursor?) {
myListContact.clear()
if (p1!=null) {
p1.moveToFirst()
while(!p1.isAfterLast()) {
myListContact.add(myContact(nama = p1.getString(p1.getColumnIndex(DISPLAY_NAME)),nomorHp = p1.getString(p1.getColumnIndex(NUMBER))))
p1.moveToNext()
}
}
val contactAdapter = myAdapterRecyView(myListContact)
myRecyView.apply {
layoutManager = LinearLayoutManager(this#DetailActivity)
adapter = contactAdapter
}
}
override fun onLoaderReset(p0: Loader<Cursor>) {
val contactAdapter = myAdapterRecyView(myListContact)
myRecyView.apply {
layoutManager = LinearLayoutManager(this#DetailActivity)
adapter = contactAdapter
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detail)
LoaderManager.getInstance(this).initLoader(1, null, this)
}
}
myAdapterRecyView.kt
class myAdapterRecyView(private val contact : List<myContact>): RecyclerView.Adapter<myHolder>() {
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): myHolder {
return myHolder(LayoutInflater.from(p0.context)
.inflate(R.layout.layout_recy_view,p0,false))
}
override fun getItemCount(): Int = contact.size
override fun onBindViewHolder(p0: myHolder, p1: Int) {
p0.bindContact(contact[p1])
}
}
class myHolder(view: View):RecyclerView.ViewHolder(view) {
private val contactName = view.itemName
private val contactNumber = view.itemNumber
fun bindContact(tmp: myContact) {
contactName.text = "${contactName.text} ${tmp.nama}"
contactNumber.text = "${contactNumber.text} ${tmp.nomorHp}"
}
}
class myHolder(view: View):RecyclerView.ViewHolder(view) {
private val contactName = view.itemName
private val contactNumber = view.itemNumber
fun bindContact(tmp: myContact) {
contactName.text = "${contactName.text} ${tmp.nama}"
contactNumber.text = "${contactNumber.text} ${tmp.nomorHp}"
}
}
myContact.kt
class myContact (
val nama : String,
val nomorHp : String
)
You can put yout click action inside the onBind in recycler view adapter.
class myHolder(view: View):RecyclerView.ViewHolder(view) {
private val contactName = view.itemName
private val contactNumber = view.itemNumber
fun bindContact(tmp: myContact) {
contactName.text = "${contactName.text} ${tmp.nama}"
contactNumber.text = "${contactNumber.text} ${tmp.nomorHp}"
view.setOnClickListener {
// YOUR ACTION HERE.
}
}
}

Categories

Resources