Android Navigation findNavController when NavHost is not in Activity - android

I have an activity which holds FragmentContainerView. In the FragmentContainerView I have a NavHostFragment. I want to setupActionBarWithNavController in the NavHostFragment.
class MenuNavHostFragment : Fragment() {
private lateinit var navController: NavController
fun setup(activity: MainActivity) {
navController = Navigation.findNavController(activity, R.id.fragment_menu_nav_host)
NavigationUI.setupActionBarWithNavController(activity, navController)
}
in MainActivity.kt
private lateinit var menuNavHostFragment: MenuNavHostFragment
private fun setupNavigation() {
menuNavHostFragment = MenuNavHostFragment()
menuNavHostFragment.setup(this)
}
in fragment_menu_nav_host:
...
tools:context=".View.MenuNavHostFragment">
<fragment
android:id="#+id/fragment_menu_nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
...
Which results in the following error message: ID does not reference a View inside this Activity
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.bla.bla/com.bla.bla.View.MainActivity}: java.lang.IllegalArgumentException: ID does not reference a View inside this Activity
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3122)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3261)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1977)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6923)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:870)
Caused by: java.lang.IllegalArgumentException: ID does not reference a View inside this Activity
at android.app.Activity.requireViewById(Activity.java:2686)
at androidx.core.app.ActivityCompat.requireViewById(ActivityCompat.java:363)
at androidx.navigation.Navigation.findNavController(Navigation.java:58)
at com.bla.bla.View.MenuNavHostFragment.setup(MenuNavHostFragment.kt:36)
at com.bla.bla.View.MainActivity.setupNavigation(MainActivity.kt:38)
How do I solve this?

The fragment in which navHostFragment is defined has to be created before calling the Navigation.findNavController() method to avoid this exception.

Related

Not navigate to fragment with #Inject constructor

I'm trying to create a simple news app, but when I used of #Inject constructor in my fragment, the navigation component not worked and show the below error... while, before used injection, it's worked without any problem
what I doing to fix this error?! thank you so much for your help
NewsActivity:
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.setupWithNavController
import com.example.simplenewsapp.R
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.android.synthetic.main.activity_news.*
#AndroidEntryPoint
class NewsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_news)
bottomNavigationView.setupWithNavController(newsNavHostFragment.findNavController())
}
}
BreakingNewsFragment:
class BreakingNewsFragment #Inject constructor(
val newsItemAdapter: NewsAdapter,
var viewModel: MainViewModel? = null
) : Fragment(R.layout.fragment_breaking_news) {
...
}
Error message:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.simplenewsapp, PID: 8558
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.simplenewsapp/com.example.simplenewsapp.ui.NewsActivity}: android.view.InflateException: Binary XML file line #17: Binary XML file line #17: Error inflating class fragment
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: android.view.InflateException: Binary XML file line #17: Binary XML file line #17: Error inflating class fragment
Caused by: android.view.InflateException: Binary XML file line #17: Error inflating class fragment
Caused by: androidx.fragment.app.Fragment$InstantiationException: Unable to instantiate fragment com.example.simplenewsapp.ui.fragments.BreakingNewsFragment: could not find Fragment constructor
at androidx.fragment.app.Fragment.instantiate(Fragment.java:625)
at androidx.fragment.app.FragmentContainer.instantiate(FragmentContainer.java:57)
at androidx.fragment.app.FragmentManager$3.instantiate(FragmentManager.java:483)
at androidx.navigation.fragment.FragmentNavigator.instantiateFragment(FragmentNavigator.java:132)
at androidx.navigation.fragment.FragmentNavigator.navigate(FragmentNavigator.java:162)
at androidx.navigation.fragment.FragmentNavigator.navigate(FragmentNavigator.java:58)
at androidx.navigation.NavGraphNavigator.navigate(NavGraphNavigator.java:71)
at androidx.navigation.NavGraphNavigator.navigate(NavGraphNavigator.java:28)
at androidx.navigation.NavController.navigate(NavController.java:1059)
at androidx.navigation.NavController.onGraphCreated(NavController.java:639)
at androidx.navigation.NavController.setGraph(NavController.java:592)
at androidx.navigation.NavController.setGraph(NavController.java:557)
at androidx.navigation.NavController.setGraph(NavController.java:539)
at androidx.navigation.fragment.NavHostFragment.onCreate(NavHostFragment.java:248)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:2936)
at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:472)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:278)
at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:141)
at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:135)
at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:313)
at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:292)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:780)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:866)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at android.view.LayoutInflater.inflate(LayoutInflater.java:374) E/AndroidRuntime: at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:696)
at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:170)
at com.example.simplenewsapp.ui.NewsActivity.onCreate(NewsActivity.kt:26)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.NoSuchMethodException: <init> []
at java.lang.Class.getConstructor0(Class.java:2327)
at java.lang.Class.getConstructor(Class.java:1725)
at androidx.fragment.app.Fragment.instantiate(Fragment.java:610)
... 47 more
at
com.example.simplenewsapp.ui.NewsActivity.onCreate(NewsActivity.kt:26)
is:
setContentView(R.layout.activity_news)
All the provided answers are wrong as fragments constructor do NOT have to be empty! You can easily constructor inject your dependencies inside your fragments, but you have to use a fragment factory in order to do so.
Here is an example for you:
Fragment
#AndroidEntryPoint
class BreakingNewsFragment(
val newsItemAdapter: NewsAdapter,
) : Fragment(R.layout.fragment_breaking_news) {
...
}
Fragment Factory
class MainFragmentFactory #Inject constructor(
private val newsAdapter: NewsAdapter
// your dependencies
) : FragmentFactory() {
override fun instantiate(classLoader: ClassLoader, className: String): Fragment = when(className) {
BreakingNewsFragment::class.java.name -> BreakingNewsFragment(newsAdapter)
// here you can add every other fragment
else -> super.instantiate(classLoader, className)
}
}
MainNavHostFragment
#AndroidEntryPoint
class MainNavHostFragment : NavHostFragment() {
#Inject lateinit var mainFragmentFactory: MainFragmentFactory
override fun onAttach(context: Context) {
super.onAttach(context)
childFragmentManager.fragmentFactory = mainFragmentFactory
}
}
Then in order to use your new NavHostFragment, you have to change your activity_main.xml
Activity_main.xml
<fragment
android:id="#+id/fragment_container"
android:name="yourPath.MainNavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:navGraph="#navigation/nav_main" />
The important line being here "android:name="yourPath.MainNavHostFragment" or for example "android:name="com.example.app.ui.MainNavHostFragment"
With this you can constructor inject inside your fragment.
NOTE:
You can NOT constructor inject your viewmodel! You should also be careful with using this method and constructor injecting adapters as they can possibility cause a memory leak. With adapters, I would advise you to field inject them
Fragments should have an empty constructor since they are managed by Android, same as activities. Anything you want to inject you have to inject inside the fragment, not through the constructor.
For view-models, it's trivial through the viewModels() API:
private val viewModel: MainViewModel by viewModels()
Don't forget to annotate the fragment with #AndroidEntryPoint and the view-model with #HiltViewModel.
Add #AndroidEntryPoint to your fragment and initialize NewsAdapter() in onViewCreated method of fragments.
Get MainViewModel by using
private val MainViewModel by viewModels()
Fragments MUST have an empty constructor since they are created by System OS.

how to scope the SharedViewModel after migrating an existing app to use the Navigation component

I've been struggling on this the whole day and still can't make it work. In an existing Single Activity app, I'm trying to replace all fragment transactions by implementing the Navigation component.
I've already created a Navigation graph and included the FragmentContainerView as a child of the root ViewGroup as it was proposed in the official docs.
activity_main.xml
<FrameLayout
android:id="#+id/container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/appBarLayout">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/main_content"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/appBarLayout"
app:navGraph="#navigation/nav_graph" />
</FrameLayout>
Now the problem that I'm currently facing is that the SharedViewModel which I am using through the whole app can't be instantiated in the BaseFragment anymore.
BaseFragment.kt
abstract class BaseFragment<E : ViewDataBinding, T : BaseViewModel> : Fragment() {
lateinit var viewModel: T
lateinit var dataBinding: E
abstract fun getLayoutResource(): Int
abstract fun getViewModelClass(): Class<T>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activity?.let {
// java.lang.RuntimeException: Cannot create an instance of class SharedViewModel
viewModel = ViewModelProvider(it).get(getViewModelClass())
// viewModel = ViewModelProvider(getParentFragment()).get(getViewModelClass()) also doesn't work
}
}
...
}
BaseViewModel.kt
abstract class BaseViewModel : ViewModel(), LifecycleObserver
SharedViewModel.kt
abstract class SharedViewModel : BaseViewModel() {
...
}
SharedViewModelImpl.kt
class SharedViewModelImpl(private val repository: AppRepository) : SharedViewModel(){
...
}
I've read posts on SO and as well as Medium articles that recommend creating the SharedViewModel by using by navGraphViewModels like this
val viewModel: SharedViewModel by navGraphViewModels(R.id.navigation_graph)
but it seems that I still can't combine this approach with the generics that I already have.
My assumption is that the Navigation component can't deal with abstract classes.
How can I overcome this problem by keeping my existing app architecture? Many thanks in advance.
UPDATE:
#ianhanniballake asked me to post the entire stack trace. So here it is:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: at.bwappsandmore.doitagain, PID: 13528
java.lang.RuntimeException: Unable to start activity ComponentInfo{at.bwappsandmore.doitagain/at.bwappsandmore.doitagain.ui.MainActivity}: android.view.InflateException: Binary XML file line #44: Binary XML file line #44: Error inflating class androidx.fragment.app.FragmentContainerView
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: android.view.InflateException: Binary XML file line #44: Binary XML file line #44: Error inflating class androidx.fragment.app.FragmentContainerView
Caused by: android.view.InflateException: Binary XML file line #44: Error inflating class androidx.fragment.app.FragmentContainerView
Caused by: java.lang.RuntimeException: Cannot create an instance of class at.bwappsandmore.doitagain.viewModel.SharedViewModel
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:221)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:278)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:106)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
at at.bwappsandmore.doitagain.base.BaseFragment.onCreate(BaseFragment.kt:31)
at at.bwappsandmore.doitagain.ui.DisplayDataFragment.onCreate(DisplayDataFragment.kt:85)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:2684)
at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:280)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1175)
at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2224)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1997)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1953)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2629)
at androidx.fragment.app.FragmentManager.dispatchCreate(FragmentManager.java:2571)
at androidx.fragment.app.Fragment.onCreate(Fragment.java:1685)
at androidx.navigation.fragment.NavHostFragment.onCreate(NavHostFragment.java:264)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:2684)
at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:280)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1175)
at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2224)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1997)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1953)
at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1818)
at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:303)
at androidx.fragment.app.FragmentContainerView.<init>(FragmentContainerView.java:166)
E/AndroidRuntime: at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:51)
at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:135)
at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:356)
at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:335)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:780)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:866)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:696)
at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:170)
at androidx.databinding.DataBindingUtil.setContentView(DataBindingUtil.java:303)
at androidx.databinding.DataBindingUtil.setContentView(DataBindingUtil.java:284)
at at.bwappsandmore.doitagain.base.BaseActivity.onCreate(BaseActivity.kt:27)
at at.bwappsandmore.doitagain.ui.MainActivity.onCreate(MainActivity.kt:46)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.InstantiationException: java.lang.Class<at.bwappsandmore.doitagain.viewModel.SharedViewModel> cannot be instantiated
at java.lang.Class.newInstance(Native Method)
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:219)
... 60 more

Cannot create instance of ViewModel class

I'm doing this inside my onCreate method of MainActivity
journalViewModel = new ViewModelProvider(this).get(JournalViewModel.class);
and my ViewModel is as following:
public class JournalViewModel extends AndroidViewModel {
public JournalViewModel(#NonNull Application application) {
super(application);
repository = new JournalRepository(application);
journals = repository.getAllJournals();
}
}
However, I'm getting the error for this line,
journalViewModel = new ViewModelProvider(this).get(JournalViewModel.class);
saying,
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.diaryapp/com.example.diaryapp.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class com.example.diaryapp.JournalViewModel
As per my knowledge the constructor inside ViewModel shouldn't have any other parameter except the one in my code and both constructor and class should be public.
However, further inside my error logs, I get the error:
java.lang.InstantiationException: java.lang.Class<com.example.diaryapp.JournalViewModel> has no zero argument constructor
Here's the complete error log:
2020-03-23 21:37:18.986 8632-8632/com.example.diaryapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.diaryapp, PID: 8632
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.diaryapp/com.example.diaryapp.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class com.example.diaryapp.JournalViewModel
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2946)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3081)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1831)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6823)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
Caused by: java.lang.RuntimeException: Cannot create an instance of class com.example.diaryapp.JournalViewModel
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:221)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:187)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
at com.example.diaryapp.MainActivity.onCreate(MainActivity.java:40)
at android.app.Activity.performCreate(Activity.java:7224)
at android.app.Activity.performCreate(Activity.java:7213)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1272)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2926)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3081) 
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1831) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loop(Looper.java:201) 
at android.app.ActivityThread.main(ActivityThread.java:6823) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873) 
Caused by: java.lang.InstantiationException: java.lang.Class<com.example.diaryapp.JournalViewModel> has no zero argument constructor
at java.lang.Class.newInstance(Native Method)
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:219)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:187) 
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150) 
at com.example.diaryapp.MainActivity.onCreate(MainActivity.java:40) 
at android.app.Activity.performCreate(Activity.java:7224) 
at android.app.Activity.performCreate(Activity.java:7213) 
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1272) 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2926) 
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3081) 
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1831) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loop(Looper.java:201) 
at android.app.ActivityThread.main(ActivityThread.java:6823) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873) 
You should obtain JournalViewModel like:
journalViewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication())).get(JournalViewModel.class);
instead of
journalViewModel = new ViewModelProvider(this).get(JournalViewModel.class);
Not sure about Java, but this worked for me in Kotlin.
You need to define a ViewModelProvidor.Factory:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModelFactory.setApplication(application)
val journalViewModel = ViewModelProvider(this, viewModelFactory).get(JournalViewModel::class.java)
}
}
object viewModelFactory : ViewModelProvider.Factory {
lateinit var app : Application
fun setApplication(application: Application) {
app = application
}
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return JournalViewModel(app) as T
}
}
I got it working with the help of this answer.
Here's what I did in,
JournalFactory.java
public class JournalFactory extends ViewModelProvider.NewInstanceFactory {
private Application application;
public JournalFactory(#NonNull Application application) {
this.application = application;
}
#NonNull
#Override
public <T extends ViewModel> T create(#NonNull Class<T> modelClass) {
if (modelClass == JournalViewModel.class)
return (T) new JournalViewModel(application);
return null;
}
}
onCreate() method of MainActivity.java
journalViewModel = new ViewModelProvider(this, new JournalFactory(getApplication())).get(JournalViewModel.class);

Get the NavController after creating a NavHostFragment programmatically

I create a NavHostFragment programmatically in the method onCreate method of my Activity just like this article says, but then the method findNavController(R.id.nav_host) throws the following exception:
java.lang.RuntimeException: Unable to start activity ComponentInfo{app.klosed.ui/app.klosed.ui.host.HostActivity}: java.lang.IllegalStateException: Activity app.klosed.ui.host.HostActivity#d3f794e does not have a NavController set on 2131231026
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Caused by: java.lang.IllegalStateException: Activity app.klosed.ui.host.HostActivity#d3f794e does not have a NavController set on 2131231026
at androidx.navigation.Navigation.findNavController(Navigation.java:61)
at androidx.navigation.ActivityKt.findNavController(Activity.kt:30)
at app.klosed.ui.MainActivity.onCreate(MainActivity.kt:78)
at app.klosed.ui.host.HostActivity.onCreate(HostActivity.kt:32)
at android.app.Activity.performCreate(Activity.java:6975)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
How can I get the NavController object?
Have you try this?
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
NavController navController = ((NavHostFragment) Objects.requireNonNull(fragment)).getNavController();
try this
val navController = Navigation.findNavController(this, R.id. nav_host)

java.lang.IllegalStateException: Task is not yet complete (Using Cloud Storage with Coroutines)

My main activity (UserHomePage) hosts a Navigation Drawer with Navigation Header. I am trying to load data into the Navigation Header using Kotlin Coroutines. The main activity code goes like this:
class UserHomePage : AppCompatActivity() {
private lateinit var binding: com.newwebtools.maun.databinding.ActivityUserHomePageBinding
private lateinit var headerBinding: NavHeaderMainBinding
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var toolbar: Toolbar
private lateinit var drawer: DrawerLayout
private lateinit var toggle: ActionBarDrawerToggle
private val currentUser = mAuth.currentUser
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_user_home_page)
headerBinding = NavHeaderMainBinding.bind(binding.navView.getHeaderView(0))
setNavHeader() //This is a runBlocking function to set nav header views
//code continue further dealing with navigation drawer features...
I have defined setNavHeader() as follows:
private fun setNavHeader() = runBlocking {
val name = async{mFireStore.collection("userProfiles")
.whereEqualTo("user_id", currentUser?.uid).get().result?.documents?.first()?.getString("name")}
val downloadUrl = async{mStorage.reference.child("profileImages/${currentUser?.uid}").downloadUrl.result}
Log.i("UserHomePage", "Nav Header View downloadUrl is ${downloadUrl.await()}")
headerBinding.navHeaderName.text = name.await()
headerBinding.navHeaderPhoneNo.text = currentUser?.phoneNumber
}
On running the above code, I get the following error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.newwebtools.maun, PID: 4203
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.newwebtools.maun/com.newwebtools.maun.UserHomePage}: java.lang.IllegalStateException: Task is not yet complete
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2814)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1613)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:173)
at android.app.ActivityThread.main(ActivityThread.java:6634)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:822)
Caused by: java.lang.IllegalStateException: Task is not yet complete
at com.google.android.gms.common.internal.Preconditions.checkState(Unknown Source:29)
at com.google.android.gms.tasks.zzu.zzb(Unknown Source:121)
at com.google.android.gms.tasks.zzu.getResult(Unknown Source:12)
at com.newwebtools.maun.UserHomePage$setNavHeader$1$name$1.invokeSuspend(UserHomePage.kt:151)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:233)
at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.kt:116)
at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:76)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:53)
at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source:1)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:35)
at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source:1)
at com.newwebtools.maun.UserHomePage.setNavHeader(UserHomePage.kt:149)
at com.newwebtools.maun.UserHomePage.onCreate(UserHomePage.kt:40)
at android.app.Activity.performCreate(Activity.java:7074)
at android.app.Activity.performCreate(Activity.java:7065)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1215)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2767)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892) 
at android.app.ActivityThread.-wrap11(Unknown Source:0) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1613) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loop(Looper.java:173) 
at android.app.ActivityThread.main(ActivityThread.java:6634) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:822) 
I/Process: Sending signal. PID: 4203 SIG: 9
Application terminated.
I am new to Kotlin and Android-Studio. Moreover I am still figuring out how to work with Coroutines.

Categories

Resources