Reputation: 415
I am developing Android
app using Kotlin.In my app contains Tab
with ViewPager
so i implement the two tabs.when i move to another activity and compack to tab view activity the app getting fource stop and the logcat
shows below the error.
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.crypto.wallet/com.crypto.wallet.activities.MainActivity}: android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment com.crypto.wallet.activities.ReceiveFragment: could not find Fragment constructor
MyFragment.kt
@SuppressLint("ValidFragment")
class ReceiveFragment(private val transactionList: List<TransactionEntity>, val appDatabase: AppDatabase, private val direction: TransactionAdapterDirection,
val networkDefinitionProvider: NetworkDefinitionProvider) : Fragment(){
private var linearLayoutManager: LinearLayoutManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val rootView = inflater.inflate(R.layout.receive_fragment, container, false)
val recyclerView = rootView.findViewById<RecyclerView>(R.id.transaction_recycler_in) as RecyclerView
linearLayoutManager = LinearLayoutManager(getActivity(), LinearLayout.VERTICAL, false)
recyclerView.layoutManager = linearLayoutManager
recyclerView.adapter = TransactionRecyclerAdapter(transactionList,appDatabase,direction,networkDefinitionProvider)
recyclerView.setHasFixedSize(true);
return rootView
}
}
ViewPager.kt
override fun getItem(position: Int): Fragment? {
var fragment: Fragment? = null
when (position) {
//0 -> fragment = ReceiveFragment(MytransactionList,MyappDatabase,Myincoming,MynetworkDefinitionProvider)
0 -> fragment = ReceiveFragment(MyIT,MyAppDatabase,MyIncoming,MyNetwork)
1 -> fragment = SendFragment()
}
return fragment
}
Main.kt OnCreate()
val viewPager = findViewById<ViewPager>(R.id.viewpager)
if (viewPager != null) {
val adapter = ViewPagerAdapter(supportFragmentManager,it,appDatabase,INCOMING,networkDefinitionProvider)
viewPager.adapter = adapter
}
val pref = applicationContext.getSharedPreferences("MyPref", 0) // 0 - for private mode
val editor = pref.edit()
val gson = Gson()
val json = gson.toJson(it)
editor.putString("MyObject", json)
editor.apply()
OnResume()
val prefs = applicationContext.getSharedPreferences("MyPref", 0)
val gson = Gson()
val json = prefs.getString("MyObject", "")
val person1: List<TransactionEntity> = gson.fromJson(json, ArrayList<TransactionEntity>()::class.java)
UPDATE: After i tried this i get same error(i tried both Bundle and Shared pref):
companion object {
@JvmStatic
fun newInstance(myIT: List<TransactionEntity>, myAppDatabase: AppDatabase, myIncoming: TransactionAdapterDirection,
myNetwork: NetworkDefinitionProvider,
bundle: Bundle) =
ReceiveFragment(myIT, myAppDatabase, myIncoming, myNetwork,bundle).apply {
arguments = Bundle().apply {
/* val prefs = getActivity()!!.getApplicationContext().getSharedPreferences("myPrefs", 0)
val gson = Gson()
val json = prefs.getString("MyObject", "")
val person1: List<TransactionEntity> = gson.fromJson(json,
ArrayList<TransactionEntity>()::class.java)
Log.d("Karthi", "Frag-GSON " + person1)*/
val dd = bundle.getSerializable("MySerializable")
Log.d("Karthi", "Frag-GSON " + dd)
}
}
}
Main.kt:
val bundle = Bundle()
val gson_budle = Gson()
val json_bundle = gson_budle.toJson(it)
bundle.putSerializable("MySerializable", json_bundle)
val sharedPreferences = getSharedPreferences(myPreferences, Context.MODE_PRIVATE)
val editor = sharedPreferences.edit()
val gson = Gson()
val json = gson.toJson(it)
editor.putString("MyObject", json)
editor.putString("MyObject_json_bundle", json_bundle)
Log.d("Karthi","After - IT" + json)
Log.d("Karthi","After - IT" + json_bundle)
editor.apply()
FATAL EXCEPTION: main Process: com.crypto.wallet, PID: 29313 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.crypto.wallet/com.crypto.wallet.activities.MainActivity}: android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment com.crypto.wallet.activities.ReceiveFragment: could not find Fragment constructor at android.support.v4.app.FragmentController.restoreAllState(FragmentController.java:152) at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:330) at android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:84) at com.crypto.wallet.activities.MainActivity.onCreate(MainActivity.kt:194)
Upvotes: 10
Views: 26972
Reputation: 389
As mentioned here,
If the no-argument constructor is not available, a runtime exception will occur in some cases during state restore.
So please change your code like this
class ReceiveFragment : Fragment{
private val transactionList: List<TransactionEntity>? = null
val appDatabase: AppDatabase? = null
private val direction: TransactionAdapterDirection? = null
val networkDefinitionProvider: NetworkDefinitionProvider? = null
//Add empty constructor to avoid the exception
constructor() : super()
constructor(transactionList: List<TransactionEntity>, appDatabase: AppDatabase, direction: TransactionAdapterDirection, networkDefinitionProvider: NetworkDefinitionProvider){
this.transactionList = transactionList
this.appDatabase = appDatabase
this.direction = direction
this.networkDefinitionProvider = networkDefinitionProvider
}
}
Upvotes: 3
Reputation: 2727
What you can do, is to make a default constructor with zero parameters
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment LoginFragment.
*/
// TODO: Rename and change types and number of parameters
@JvmStatic
fun newInstance(param1: String, param2: String) =
ReceiveFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
// Or from your code, you can use Gson
val prefs = applicationContext.getSharedPreferences("MyPref", 0)
val gson = Gson()
val json = prefs.getString("MyObject", "")
val person1: List<TransactionEntity> = gson.fromJson(json,
ArrayList<TransactionEntity>()::class.java)
}
}
And you can use it like
0 -> receiveFragment= ReceiveFragment.newInstance(firstParam, secondParam)
And you can receive this params in onCreate
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
email = it.getString(ARG_PARAM1)
password = it.getString(ARG_PARAM2)
}
// Or from your code, you can use Gson
val prefs = applicationContext.getSharedPreferences("MyPref", 0)
val gson = Gson()
val json = prefs.getString("MyObject", "")
val person1: List<TransactionEntity> = gson.fromJson(json,
ArrayList<TransactionEntity>()::class.java)
}
And your fragment constructor like this
class ReceiveFragment: Fragment()
Hope this helps
Upvotes: 5
Reputation: 3976
When you get short description over the error you will see :
Avoid non-default constructors in fragments: use a default constructor plus Fragment setArguments(Bundle)
instead less.
From the Fragment documentation:
Every fragment must have an empty constructor, so it can be instantiated when restoring its activity's state. It is strongly recommended that subclasses do not have other constructors with parameters, since these constructors will not be called when the fragment is re-instantiated; instead, arguments can be supplied by the caller with setArguments(Bundle)
and later retrieved by the Fragment with getArguments()
.
for example :
fun newInstance(bundle : Bundle) : ReceiveFragment{
val fragment = ReceiveFragment()
fragment.arguments=bundle
return fragment
}
Now call the fragment :
0 -> fragment = ReceiveFragment.newInstance(new Bundle)
More info: http://developer.android.com/reference/android/app/Fragment.html#Fragment()
Upvotes: 12