Karthikeyan
Karthikeyan

Reputation: 415

How to fix this bug using Kotlin,could not find Fragment constructor?

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

Answers (3)

Rajalakshmi Arumugam
Rajalakshmi Arumugam

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

Abdul Kawee
Abdul Kawee

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

Hemant Parmar
Hemant Parmar

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

Related Questions