App crashes on First Open only when AdMob is added but working fine on next open











up vote
0
down vote

favorite












My App is working fine and then I tried to add AdMob dependencies. That's when things get complicated. On first install and then open App crashes. But on second and consecutive open the app is working fine, all ads are showing.



For me, this is a bad user experience because at first open they think it is not a good app. And maybe they will uninstall it immediately.



Maybe there's something I need to improve or add but I can't figure it out. I need help regarding polishing my code.



Android Manifest



<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gumangan.uecfispiritualhymns">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">

<!-- TODO: Change android:value when final building -->
<!--Sample AdMob App ID: ca-app-pub-3940256099942544~3347511713-->
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-3940256099942544~3347511713"/>

<activity
android:name="com.gumangan.uecfispiritualhymns.DictionaryActivity"
android:label="@string/app_name"
android:launchMode="singleTop"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

<action android:name="android.intent.action.SEARCH" />
</intent-filter>

<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
<activity android:name="com.gumangan.uecfispiritualhymns.WordDetailActivity"
android:parentActivityName="com.gumangan.uecfispiritualhymns.DictionaryActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.gumangan.uecfispiritualhymns.DictionaryActivity"/>
</activity>
</application>


Gradle Properties



// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
ext.kotlin_version = '1.3.10'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}

allprojects {
repositories {
google()
jcenter()
maven {
url "https://maven.google.com"
}
}
}

task clean(type: Delete) {
delete rootProject.buildDir
}


Gradle Dependencies



apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
compileSdkVersion 27
defaultConfig {
applicationId "com.gumangan.uecfispiritualhymns"
minSdkVersion 16
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:support-v4:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:design:27.1.1'
implementation 'com.android.support:cardview-v7:27.1.1'
implementation 'com.android.support:customtabs:27.1.1'

implementation 'com.google.android.gms:play-services-ads:17.1.2'

testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}


DatabaseHelper



package com.gumangan.uecfispiritualhymns

import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.preference.PreferenceManager

import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream

class DatabaseHelper(private var mContext: Context) : SQLiteOpenHelper(mContext, DATABASE_NAME, null, DATABASE_VERSION) {
companion object {
private val DATABASE_NAME = "simple_dict.db"
private val DATABASE_VERSION = 1
val DB_CREATED = "DB_CREATED"
}

private var mCreateDb = false
private var mUpgradeDb = false

private fun copyDatabaseFromAssets(db: SQLiteDatabase?) {
var inputStream: InputStream? = null
var outputStream: OutputStream? = null

try {
inputStream = mContext.assets.open(DATABASE_NAME)
outputStream = FileOutputStream(db?.path)

val buffer = ByteArray(1024)
var length: Int = inputStream!!.read(buffer)
while (length > 0) {
outputStream.write(buffer, 0, length)
length = inputStream.read(buffer)
}
outputStream.flush()

val copiedDb = mContext.openOrCreateDatabase(DATABASE_NAME, 0, null)

val isDbCreated = copiedDb != null

copiedDb.execSQL("PRAGMA user_version = $DATABASE_VERSION")
copiedDb.close()

// DB_CREATED
val sharedPref = PreferenceManager.getDefaultSharedPreferences(mContext)
val sharePrefEditor = sharedPref.edit()
sharePrefEditor.putBoolean(DB_CREATED, isDbCreated)
sharePrefEditor.apply()
} catch (e: IOException) {
e.printStackTrace()
throw Error("copyDatabaseFromAssets: Error copying database.")
} finally {
try {
outputStream?.close()
inputStream?.close()
}catch (e: IOException) {
e.printStackTrace()
throw Error("copyDatabaseFromAssets: Error closing stream.")
}
}

}

override fun onCreate(db: SQLiteDatabase?) {
mCreateDb = true
}

override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
if(newVersion > oldVersion) {
mUpgradeDb = true
}
}

override fun onOpen(db: SQLiteDatabase?) {
if(mCreateDb) {
mCreateDb = false
copyDatabaseFromAssets(db)
}

if(mUpgradeDb) {
mUpgradeDb = false
copyDatabaseFromAssets(db)
}
}

fun getWords(wordPrefix: String = ""): Cursor {
return if(wordPrefix.isBlank()) {
readableDatabase.query(DictionaryEntryContract.TABLE_NAME, null,
null, null, null, null,
"${DictionaryEntryContract.COLUMN_ID} ASC")
} else {
readableDatabase.query(DictionaryEntryContract.TABLE_NAME, null,
"${DictionaryEntryContract.COLUMN_WORD} LIKE ?", arrayOf("$wordPrefix%"),
null, null, "${DictionaryEntryContract.COLUMN_ID} ASC")
}
}

fun getWord(id: String): Cursor {
return readableDatabase.query(DictionaryEntryContract.TABLE_NAME, null,
"${DictionaryEntryContract.COLUMN_ID}= ?", arrayOf(id),
null, null, null)
}
}


SearchListAdapter



package com.gumangan.uecfispiritualhymns

import android.content.Context
import android.database.Cursor
import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CursorAdapter
import android.widget.TextView

class SearchListAdapter(context: Context, cursor: Cursor) : CursorAdapter(context, cursor, 0) {
private class ViewHolder {
var txtWord: TextView? = null
var txtType: TextView? = null
var txtMeaning: TextView? = null

var wordColumnIndex: Int = 0
var typeColumnIndex: Int = 0
var meaningColumnIndex: Int = 0
}

override fun newView(context: Context?, cursor: Cursor?, parent: ViewGroup?): View {
val layoutInflater = LayoutInflater.from(context)
val newView = layoutInflater.inflate(R.layout.search_list_item, parent, false)

val viewHolder = ViewHolder()
viewHolder.txtWord = newView.findViewById<TextView>(R.id.txtWord)
viewHolder.txtType = newView.findViewById<TextView>(R.id.txtType)
viewHolder.txtMeaning = newView.findViewById<TextView>(R.id.txtMeaning)

viewHolder.wordColumnIndex = cursor!!.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_WORD)
viewHolder.typeColumnIndex = cursor!!.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_TYPE)
viewHolder.meaningColumnIndex = cursor!!.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_MEANING)

newView.tag = viewHolder

return newView
}

override fun bindView(view: View?, context: Context?, cursor: Cursor?) {
val viewHolder = view!!.tag as ViewHolder

viewHolder.txtWord?.text = cursor?.getString(viewHolder.wordColumnIndex)
viewHolder.txtType?.text = cursor?.getString(viewHolder.typeColumnIndex)
viewHolder.txtMeaning?.text = cursor?.getString(viewHolder.meaningColumnIndex)
}

override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val view = super.getView(position, convertView, parent)

if(position % 2 == 0) {
view.setBackgroundColor(Color.LTGRAY)
} else {
view.setBackgroundColor(Color.WHITE)
}

return view;
}
}


DictionaryEntryContract



package com.gumangan.uecfispiritualhymns

import android.provider.BaseColumns

class DictionaryEntryContract : BaseColumns {
private constructor()

companion object {
val TABLE_NAME = "english_words"

val COLUMN_ID = BaseColumns._ID
val COLUMN_WORD = "word"
val COLUMN_TYPE = "type"
val COLUMN_MEANING = "meaning"
}
}


DictionaryActivity



package com.gumangan.uecfispiritualhymns

import android.app.SearchManager
import android.content.Context
import android.content.Intent
import android.os.AsyncTask
import android.os.Bundle
import android.preference.PreferenceManager
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import android.support.v7.widget.SearchView
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.widget.AdapterView
import android.widget.ListView
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.AdView
import com.google.android.gms.ads.MobileAds
import java.lang.ref.WeakReference

class DictionaryActivity : AppCompatActivity() {

companion object {
val TAG = "DictionaryActivity"
val LAST_SEARCH_WORD: String = "LAST_SEARCH_WORD"
}

var mDbHelper: DatabaseHelper? = null
private var mSearchListAdapter: SearchListAdapter? = null
private var mSearchQuery: String = ""

//Google Ads Banner Variable
lateinit var mAdView : AdView

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.content_dictionary)

mSearchQuery = savedInstanceState?.getString(LAST_SEARCH_WORD) ?: ""
mDbHelper = DatabaseHelper(applicationContext)

if(!isDbLoaded()) {
showLoadingUI()
LoadViewTask(this).execute()
} else {
showDictUI()
}

/* TODO: Change ADMOB ID's when final building */
//Google Ads
//MobileAds.initialize(this, "ca-app-pub-3940256099942544~3347511713")
//Google Test Ads
MobileAds.initialize(this, "ca-app-pub-3940256099942544~3347511713")

//Google Ads Banner
mAdView = findViewById(R.id.adView)
val adRequest = AdRequest.Builder().build()
mAdView.loadAd(adRequest)

}

private fun isDbLoaded(): Boolean {
val sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
return sharedPref.getBoolean(DatabaseHelper.DB_CREATED, false)
}

private fun showLoadingUI() {
setContentView(R.layout.activity_dictionary_loading)
}

private fun showDictUI() {
setContentView(R.layout.activity_dictionary)

val toolbar = findViewById<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)

supportActionBar?.setIcon(R.mipmap.ic_launcher)

mSearchListAdapter = SearchListAdapter(applicationContext, mDbHelper!!.getWords(mSearchQuery))
val lstWords = (findViewById<ListView>(R.id.lstWords))
lstWords.adapter = mSearchListAdapter
lstWords.onItemClickListener = AdapterView.OnItemClickListener { _, _, _, id ->
val wordDetailIntent = Intent(applicationContext, WordDetailActivity::class.java)
wordDetailIntent.putExtra(WordDetailActivity.WORD_ID, "$id")
startActivity(wordDetailIntent)
}
}

override fun onSaveInstanceState(outState: Bundle?) {
super.onSaveInstanceState(outState)
outState?.putString(LAST_SEARCH_WORD, mSearchQuery)
}

override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
mSearchQuery = savedInstanceState?.getString(LAST_SEARCH_WORD) ?: ""
super.onRestoreInstanceState(savedInstanceState)
}

override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)

if(intent?.action.equals(Intent.ACTION_SEARCH)) {
val searchQuery = intent?.getStringExtra(SearchManager.QUERY) ?: ""
updateListByQuery(searchQuery)
}
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_dictionary, menu)

val searchView: SearchView? = menu.findItem(R.id.action_search).actionView as? SearchView
val searchManager: SearchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
searchView?.setSearchableInfo(searchManager.getSearchableInfo(componentName))

searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}

override fun onQueryTextChange(newText: String?): Boolean {
updateListByQuery(newText ?: "")
return true
}
})

return true
}

private fun updateListByQuery(searchQuery: String) {
mSearchQuery = searchQuery
mSearchListAdapter?.changeCursor(mDbHelper!!.getWords(searchQuery))
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_search -> {
onSearchRequested()
true
}
else -> super.onOptionsItemSelected(item)
}
}

private class LoadViewTask(activity: DictionaryActivity) : AsyncTask<Void, Void, Void>() {
private var mActivity = WeakReference<DictionaryActivity>(activity)

override fun doInBackground(vararg params: Void): Void? {
if(getActivityInstance()?.mDbHelper?.readableDatabase?.isOpen == true) {
Log.d(TAG, "Db is OK.")
}
return null
}

override fun onPostExecute(result: Void?) {
if(getActivityInstance()?.isDbLoaded() == true) {
getActivityInstance()?.showDictUI()
}
}

private fun getActivityInstance() = mActivity.get()
}
}


WordDetailActivity



package com.gumangan.uecfispiritualhymns

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView

class WordDetailActivity : AppCompatActivity() {

companion object {
const val WORD_ID = "WORD_ID"
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_word_detail)

val wordId = intent.getStringExtra(WORD_ID) ?: ""
if(wordId.isBlank()) {
finish()
}

val dbHelper = DatabaseHelper(applicationContext)
val cursor = dbHelper.getWord(wordId)
if(cursor.moveToFirst()) {
val txtWord = findViewById<TextView>(R.id.txtWord)
val txtType = findViewById<TextView>(R.id.txtType)
val txtMeaning = findViewById<TextView>(R.id.txtMeaning)

txtWord?.text = cursor.getString(cursor.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_WORD))
txtType?.text = cursor.getString(cursor.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_TYPE))
txtMeaning?.text = cursor.getString(cursor.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_MEANING))
}
}
}


activity_dictionary.xml



<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.gumangan.uecfispiritualhymns.DictionaryActivity">

<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />

</android.support.design.widget.AppBarLayout>

<include layout="@layout/content_dictionary" />

</android.support.design.widget.CoordinatorLayout>


content_dictionary.xml



<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.gumangan.uecfispiritualhymns.DictionaryActivity"
tools:showIn="@layout/activity_dictionary">

<ListView
android:id="@+id/lstWords"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="0dp"
android:layout_marginEnd="0dp"
android:layout_marginStart="0dp"
android:layout_marginTop="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />


<!--Google Ads Banner Display-->
<com.google.android.gms.ads.AdView
xmlns:ads="http://schemas.android.com/apk/res-auto"
android:id="@+id/adView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="5dp"
android:visibility="visible"
ads:adSize="LARGE_BANNER"
ads:adUnitId="ca-app-pub-3940256099942544/6300978111"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">

</com.google.android.gms.ads.AdView>

</android.support.constraint.ConstraintLayout>


activity_dictionary_loading.xml



<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.gumangan.uecfispiritualhymns.DictionaryActivity">

<TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@string/dictionary_db_preparing"
android:textAlignment="center"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="@string/dictionary_db_preparing" />
</android.support.constraint.ConstraintLayout>


search_list_item.xml



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">

<TextView
android:id="@+id/txtWord"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textStyle="bold"
tools:text="Word" />

<TextView
android:id="@+id/txtType"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textStyle="italic"
tools:text="Type" />

<TextView
android:id="@+id/txtMeaning"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
tools:text="Meaning" />
</LinearLayout>


activity_word_detail.xml



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context="com.gumangan.uecfispiritualhymns.WordDetailActivity">

<TextView
android:id="@+id/txtWord"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textStyle="bold"
tools:text="Word" />

<TextView
android:id="@+id/txtType"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textStyle="italic"
tools:text="Type" />

<TextView
android:id="@+id/txtMeaning"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
tools:text="Meaning" />

</LinearLayout>


This is the LogCat error



12-09 07:52:40.554 14146-14146/com.gumangan.uecfispiritualhymns E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.gumangan.uecfispiritualhymns/com.gumangan.uecfispiritualhymns.DictionaryActivity}: java.lang.IllegalStateException: findViewById(R.id.adView) must not be null
at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
at android.app.ActivityThread.access$600(ActivityThread.java:130)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalStateException: findViewById(R.id.adView) must not be null
at com.gumangan.uecfispiritualhymns.DictionaryActivity.onCreate(DictionaryActivity.kt:57)
at android.app.Activity.performCreate(Activity.java:5008)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084) 
at android.app.ActivityThread.access$600(ActivityThread.java:130) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195) 
at android.os.Handler.dispatchMessage(Handler.java:99) 
at android.os.Looper.loop(Looper.java:137) 
at android.app.ActivityThread.main(ActivityThread.java:4745) 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:511) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 
at dalvik.system.NativeStart.main(Native Method) 


The app is about dictionary









share







New contributor




Gumangan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
























    up vote
    0
    down vote

    favorite












    My App is working fine and then I tried to add AdMob dependencies. That's when things get complicated. On first install and then open App crashes. But on second and consecutive open the app is working fine, all ads are showing.



    For me, this is a bad user experience because at first open they think it is not a good app. And maybe they will uninstall it immediately.



    Maybe there's something I need to improve or add but I can't figure it out. I need help regarding polishing my code.



    Android Manifest



    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.gumangan.uecfispiritualhymns">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">

    <!-- TODO: Change android:value when final building -->
    <!--Sample AdMob App ID: ca-app-pub-3940256099942544~3347511713-->
    <meta-data
    android:name="com.google.android.gms.ads.APPLICATION_ID"
    android:value="ca-app-pub-3940256099942544~3347511713"/>

    <activity
    android:name="com.gumangan.uecfispiritualhymns.DictionaryActivity"
    android:label="@string/app_name"
    android:launchMode="singleTop"
    android:theme="@style/AppTheme.NoActionBar">
    <intent-filter>
    <action android:name="android.intent.action.MAIN" />

    <category android:name="android.intent.category.LAUNCHER" />

    <action android:name="android.intent.action.SEARCH" />
    </intent-filter>

    <meta-data
    android:name="android.app.searchable"
    android:resource="@xml/searchable" />
    </activity>
    <activity android:name="com.gumangan.uecfispiritualhymns.WordDetailActivity"
    android:parentActivityName="com.gumangan.uecfispiritualhymns.DictionaryActivity">
    <meta-data
    android:name="android.support.PARENT_ACTIVITY"
    android:value="com.gumangan.uecfispiritualhymns.DictionaryActivity"/>
    </activity>
    </application>


    Gradle Properties



    // Top-level build file where you can add configuration options common to all sub-projects/modules.

    buildscript {
    ext.kotlin_version = '1.3.10'
    repositories {
    google()
    jcenter()
    }
    dependencies {
    classpath 'com.android.tools.build:gradle:3.2.1'
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

    // NOTE: Do not place your application dependencies here; they belong
    // in the individual module build.gradle files
    }
    }

    allprojects {
    repositories {
    google()
    jcenter()
    maven {
    url "https://maven.google.com"
    }
    }
    }

    task clean(type: Delete) {
    delete rootProject.buildDir
    }


    Gradle Dependencies



    apply plugin: 'com.android.application'

    apply plugin: 'kotlin-android'

    apply plugin: 'kotlin-android-extensions'

    android {
    compileSdkVersion 27
    defaultConfig {
    applicationId "com.gumangan.uecfispiritualhymns"
    minSdkVersion 16
    targetSdkVersion 27
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
    release {
    minifyEnabled false
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    }
    }

    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support:support-v4:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    implementation 'com.android.support:design:27.1.1'
    implementation 'com.android.support:cardview-v7:27.1.1'
    implementation 'com.android.support:customtabs:27.1.1'

    implementation 'com.google.android.gms:play-services-ads:17.1.2'

    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    }


    DatabaseHelper



    package com.gumangan.uecfispiritualhymns

    import android.content.Context
    import android.database.Cursor
    import android.database.sqlite.SQLiteDatabase
    import android.database.sqlite.SQLiteOpenHelper
    import android.preference.PreferenceManager

    import java.io.FileOutputStream
    import java.io.IOException
    import java.io.InputStream
    import java.io.OutputStream

    class DatabaseHelper(private var mContext: Context) : SQLiteOpenHelper(mContext, DATABASE_NAME, null, DATABASE_VERSION) {
    companion object {
    private val DATABASE_NAME = "simple_dict.db"
    private val DATABASE_VERSION = 1
    val DB_CREATED = "DB_CREATED"
    }

    private var mCreateDb = false
    private var mUpgradeDb = false

    private fun copyDatabaseFromAssets(db: SQLiteDatabase?) {
    var inputStream: InputStream? = null
    var outputStream: OutputStream? = null

    try {
    inputStream = mContext.assets.open(DATABASE_NAME)
    outputStream = FileOutputStream(db?.path)

    val buffer = ByteArray(1024)
    var length: Int = inputStream!!.read(buffer)
    while (length > 0) {
    outputStream.write(buffer, 0, length)
    length = inputStream.read(buffer)
    }
    outputStream.flush()

    val copiedDb = mContext.openOrCreateDatabase(DATABASE_NAME, 0, null)

    val isDbCreated = copiedDb != null

    copiedDb.execSQL("PRAGMA user_version = $DATABASE_VERSION")
    copiedDb.close()

    // DB_CREATED
    val sharedPref = PreferenceManager.getDefaultSharedPreferences(mContext)
    val sharePrefEditor = sharedPref.edit()
    sharePrefEditor.putBoolean(DB_CREATED, isDbCreated)
    sharePrefEditor.apply()
    } catch (e: IOException) {
    e.printStackTrace()
    throw Error("copyDatabaseFromAssets: Error copying database.")
    } finally {
    try {
    outputStream?.close()
    inputStream?.close()
    }catch (e: IOException) {
    e.printStackTrace()
    throw Error("copyDatabaseFromAssets: Error closing stream.")
    }
    }

    }

    override fun onCreate(db: SQLiteDatabase?) {
    mCreateDb = true
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
    if(newVersion > oldVersion) {
    mUpgradeDb = true
    }
    }

    override fun onOpen(db: SQLiteDatabase?) {
    if(mCreateDb) {
    mCreateDb = false
    copyDatabaseFromAssets(db)
    }

    if(mUpgradeDb) {
    mUpgradeDb = false
    copyDatabaseFromAssets(db)
    }
    }

    fun getWords(wordPrefix: String = ""): Cursor {
    return if(wordPrefix.isBlank()) {
    readableDatabase.query(DictionaryEntryContract.TABLE_NAME, null,
    null, null, null, null,
    "${DictionaryEntryContract.COLUMN_ID} ASC")
    } else {
    readableDatabase.query(DictionaryEntryContract.TABLE_NAME, null,
    "${DictionaryEntryContract.COLUMN_WORD} LIKE ?", arrayOf("$wordPrefix%"),
    null, null, "${DictionaryEntryContract.COLUMN_ID} ASC")
    }
    }

    fun getWord(id: String): Cursor {
    return readableDatabase.query(DictionaryEntryContract.TABLE_NAME, null,
    "${DictionaryEntryContract.COLUMN_ID}= ?", arrayOf(id),
    null, null, null)
    }
    }


    SearchListAdapter



    package com.gumangan.uecfispiritualhymns

    import android.content.Context
    import android.database.Cursor
    import android.graphics.Color
    import android.view.LayoutInflater
    import android.view.View
    import android.view.ViewGroup
    import android.widget.CursorAdapter
    import android.widget.TextView

    class SearchListAdapter(context: Context, cursor: Cursor) : CursorAdapter(context, cursor, 0) {
    private class ViewHolder {
    var txtWord: TextView? = null
    var txtType: TextView? = null
    var txtMeaning: TextView? = null

    var wordColumnIndex: Int = 0
    var typeColumnIndex: Int = 0
    var meaningColumnIndex: Int = 0
    }

    override fun newView(context: Context?, cursor: Cursor?, parent: ViewGroup?): View {
    val layoutInflater = LayoutInflater.from(context)
    val newView = layoutInflater.inflate(R.layout.search_list_item, parent, false)

    val viewHolder = ViewHolder()
    viewHolder.txtWord = newView.findViewById<TextView>(R.id.txtWord)
    viewHolder.txtType = newView.findViewById<TextView>(R.id.txtType)
    viewHolder.txtMeaning = newView.findViewById<TextView>(R.id.txtMeaning)

    viewHolder.wordColumnIndex = cursor!!.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_WORD)
    viewHolder.typeColumnIndex = cursor!!.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_TYPE)
    viewHolder.meaningColumnIndex = cursor!!.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_MEANING)

    newView.tag = viewHolder

    return newView
    }

    override fun bindView(view: View?, context: Context?, cursor: Cursor?) {
    val viewHolder = view!!.tag as ViewHolder

    viewHolder.txtWord?.text = cursor?.getString(viewHolder.wordColumnIndex)
    viewHolder.txtType?.text = cursor?.getString(viewHolder.typeColumnIndex)
    viewHolder.txtMeaning?.text = cursor?.getString(viewHolder.meaningColumnIndex)
    }

    override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
    val view = super.getView(position, convertView, parent)

    if(position % 2 == 0) {
    view.setBackgroundColor(Color.LTGRAY)
    } else {
    view.setBackgroundColor(Color.WHITE)
    }

    return view;
    }
    }


    DictionaryEntryContract



    package com.gumangan.uecfispiritualhymns

    import android.provider.BaseColumns

    class DictionaryEntryContract : BaseColumns {
    private constructor()

    companion object {
    val TABLE_NAME = "english_words"

    val COLUMN_ID = BaseColumns._ID
    val COLUMN_WORD = "word"
    val COLUMN_TYPE = "type"
    val COLUMN_MEANING = "meaning"
    }
    }


    DictionaryActivity



    package com.gumangan.uecfispiritualhymns

    import android.app.SearchManager
    import android.content.Context
    import android.content.Intent
    import android.os.AsyncTask
    import android.os.Bundle
    import android.preference.PreferenceManager
    import android.support.v7.app.AppCompatActivity
    import android.support.v7.widget.Toolbar
    import android.support.v7.widget.SearchView
    import android.util.Log
    import android.view.Menu
    import android.view.MenuItem
    import android.widget.AdapterView
    import android.widget.ListView
    import com.google.android.gms.ads.AdRequest
    import com.google.android.gms.ads.AdView
    import com.google.android.gms.ads.MobileAds
    import java.lang.ref.WeakReference

    class DictionaryActivity : AppCompatActivity() {

    companion object {
    val TAG = "DictionaryActivity"
    val LAST_SEARCH_WORD: String = "LAST_SEARCH_WORD"
    }

    var mDbHelper: DatabaseHelper? = null
    private var mSearchListAdapter: SearchListAdapter? = null
    private var mSearchQuery: String = ""

    //Google Ads Banner Variable
    lateinit var mAdView : AdView

    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.content_dictionary)

    mSearchQuery = savedInstanceState?.getString(LAST_SEARCH_WORD) ?: ""
    mDbHelper = DatabaseHelper(applicationContext)

    if(!isDbLoaded()) {
    showLoadingUI()
    LoadViewTask(this).execute()
    } else {
    showDictUI()
    }

    /* TODO: Change ADMOB ID's when final building */
    //Google Ads
    //MobileAds.initialize(this, "ca-app-pub-3940256099942544~3347511713")
    //Google Test Ads
    MobileAds.initialize(this, "ca-app-pub-3940256099942544~3347511713")

    //Google Ads Banner
    mAdView = findViewById(R.id.adView)
    val adRequest = AdRequest.Builder().build()
    mAdView.loadAd(adRequest)

    }

    private fun isDbLoaded(): Boolean {
    val sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
    return sharedPref.getBoolean(DatabaseHelper.DB_CREATED, false)
    }

    private fun showLoadingUI() {
    setContentView(R.layout.activity_dictionary_loading)
    }

    private fun showDictUI() {
    setContentView(R.layout.activity_dictionary)

    val toolbar = findViewById<Toolbar>(R.id.toolbar)
    setSupportActionBar(toolbar)

    supportActionBar?.setIcon(R.mipmap.ic_launcher)

    mSearchListAdapter = SearchListAdapter(applicationContext, mDbHelper!!.getWords(mSearchQuery))
    val lstWords = (findViewById<ListView>(R.id.lstWords))
    lstWords.adapter = mSearchListAdapter
    lstWords.onItemClickListener = AdapterView.OnItemClickListener { _, _, _, id ->
    val wordDetailIntent = Intent(applicationContext, WordDetailActivity::class.java)
    wordDetailIntent.putExtra(WordDetailActivity.WORD_ID, "$id")
    startActivity(wordDetailIntent)
    }
    }

    override fun onSaveInstanceState(outState: Bundle?) {
    super.onSaveInstanceState(outState)
    outState?.putString(LAST_SEARCH_WORD, mSearchQuery)
    }

    override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
    mSearchQuery = savedInstanceState?.getString(LAST_SEARCH_WORD) ?: ""
    super.onRestoreInstanceState(savedInstanceState)
    }

    override fun onNewIntent(intent: Intent?) {
    super.onNewIntent(intent)

    if(intent?.action.equals(Intent.ACTION_SEARCH)) {
    val searchQuery = intent?.getStringExtra(SearchManager.QUERY) ?: ""
    updateListByQuery(searchQuery)
    }
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
    menuInflater.inflate(R.menu.menu_dictionary, menu)

    val searchView: SearchView? = menu.findItem(R.id.action_search).actionView as? SearchView
    val searchManager: SearchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
    searchView?.setSearchableInfo(searchManager.getSearchableInfo(componentName))

    searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
    override fun onQueryTextSubmit(query: String?): Boolean {
    return false
    }

    override fun onQueryTextChange(newText: String?): Boolean {
    updateListByQuery(newText ?: "")
    return true
    }
    })

    return true
    }

    private fun updateListByQuery(searchQuery: String) {
    mSearchQuery = searchQuery
    mSearchListAdapter?.changeCursor(mDbHelper!!.getWords(searchQuery))
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
    R.id.action_search -> {
    onSearchRequested()
    true
    }
    else -> super.onOptionsItemSelected(item)
    }
    }

    private class LoadViewTask(activity: DictionaryActivity) : AsyncTask<Void, Void, Void>() {
    private var mActivity = WeakReference<DictionaryActivity>(activity)

    override fun doInBackground(vararg params: Void): Void? {
    if(getActivityInstance()?.mDbHelper?.readableDatabase?.isOpen == true) {
    Log.d(TAG, "Db is OK.")
    }
    return null
    }

    override fun onPostExecute(result: Void?) {
    if(getActivityInstance()?.isDbLoaded() == true) {
    getActivityInstance()?.showDictUI()
    }
    }

    private fun getActivityInstance() = mActivity.get()
    }
    }


    WordDetailActivity



    package com.gumangan.uecfispiritualhymns

    import android.support.v7.app.AppCompatActivity
    import android.os.Bundle
    import android.widget.TextView

    class WordDetailActivity : AppCompatActivity() {

    companion object {
    const val WORD_ID = "WORD_ID"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_word_detail)

    val wordId = intent.getStringExtra(WORD_ID) ?: ""
    if(wordId.isBlank()) {
    finish()
    }

    val dbHelper = DatabaseHelper(applicationContext)
    val cursor = dbHelper.getWord(wordId)
    if(cursor.moveToFirst()) {
    val txtWord = findViewById<TextView>(R.id.txtWord)
    val txtType = findViewById<TextView>(R.id.txtType)
    val txtMeaning = findViewById<TextView>(R.id.txtMeaning)

    txtWord?.text = cursor.getString(cursor.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_WORD))
    txtType?.text = cursor.getString(cursor.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_TYPE))
    txtMeaning?.text = cursor.getString(cursor.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_MEANING))
    }
    }
    }


    activity_dictionary.xml



    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.gumangan.uecfispiritualhymns.DictionaryActivity">

    <android.support.design.widget.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/AppTheme.AppBarOverlay">

    <android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_dictionary" />

    </android.support.design.widget.CoordinatorLayout>


    content_dictionary.xml



    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.gumangan.uecfispiritualhymns.DictionaryActivity"
    tools:showIn="@layout/activity_dictionary">

    <ListView
    android:id="@+id/lstWords"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:layout_marginBottom="0dp"
    android:layout_marginEnd="0dp"
    android:layout_marginStart="0dp"
    android:layout_marginTop="0dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />


    <!--Google Ads Banner Display-->
    <com.google.android.gms.ads.AdView
    xmlns:ads="http://schemas.android.com/apk/res-auto"
    android:id="@+id/adView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    android:layout_marginBottom="5dp"
    android:visibility="visible"
    ads:adSize="LARGE_BANNER"
    ads:adUnitId="ca-app-pub-3940256099942544/6300978111"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent">

    </com.google.android.gms.ads.AdView>

    </android.support.constraint.ConstraintLayout>


    activity_dictionary_loading.xml



    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.gumangan.uecfispiritualhymns.DictionaryActivity">

    <TextView
    android:id="@+id/textView"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginBottom="8dp"
    android:layout_marginEnd="8dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:text="@string/dictionary_db_preparing"
    android:textAlignment="center"
    android:textSize="18sp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    tools:text="@string/dictionary_db_preparing" />
    </android.support.constraint.ConstraintLayout>


    search_list_item.xml



    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <TextView
    android:id="@+id/txtWord"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="18sp"
    android:textStyle="bold"
    tools:text="Word" />

    <TextView
    android:id="@+id/txtType"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="14sp"
    android:textStyle="italic"
    tools:text="Type" />

    <TextView
    android:id="@+id/txtMeaning"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="18sp"
    tools:text="Meaning" />
    </LinearLayout>


    activity_word_detail.xml



    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context="com.gumangan.uecfispiritualhymns.WordDetailActivity">

    <TextView
    android:id="@+id/txtWord"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="20sp"
    android:textStyle="bold"
    tools:text="Word" />

    <TextView
    android:id="@+id/txtType"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="18sp"
    android:textStyle="italic"
    tools:text="Type" />

    <TextView
    android:id="@+id/txtMeaning"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="20sp"
    tools:text="Meaning" />

    </LinearLayout>


    This is the LogCat error



    12-09 07:52:40.554 14146-14146/com.gumangan.uecfispiritualhymns E/AndroidRuntime: FATAL EXCEPTION: main
    java.lang.RuntimeException: Unable to start activity
    ComponentInfo{com.gumangan.uecfispiritualhymns/com.gumangan.uecfispiritualhymns.DictionaryActivity}: java.lang.IllegalStateException: findViewById(R.id.adView) must not be null
    at
    android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
    at
    android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
    at android.app.ActivityThread.access$600(ActivityThread.java:130)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4745)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
    at dalvik.system.NativeStart.main(Native Method)
    Caused by: java.lang.IllegalStateException: findViewById(R.id.adView) must not be null
    at com.gumangan.uecfispiritualhymns.DictionaryActivity.onCreate(DictionaryActivity.kt:57)
    at android.app.Activity.performCreate(Activity.java:5008)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084) 
    at android.app.ActivityThread.access$600(ActivityThread.java:130) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195) 
    at android.os.Handler.dispatchMessage(Handler.java:99) 
    at android.os.Looper.loop(Looper.java:137) 
    at android.app.ActivityThread.main(ActivityThread.java:4745) 
    at java.lang.reflect.Method.invokeNative(Native Method) 
    at java.lang.reflect.Method.invoke(Method.java:511) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 
    at dalvik.system.NativeStart.main(Native Method) 


    The app is about dictionary









    share







    New contributor




    Gumangan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.






















      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      My App is working fine and then I tried to add AdMob dependencies. That's when things get complicated. On first install and then open App crashes. But on second and consecutive open the app is working fine, all ads are showing.



      For me, this is a bad user experience because at first open they think it is not a good app. And maybe they will uninstall it immediately.



      Maybe there's something I need to improve or add but I can't figure it out. I need help regarding polishing my code.



      Android Manifest



      <?xml version="1.0" encoding="utf-8"?>
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.gumangan.uecfispiritualhymns">

      <uses-permission android:name="android.permission.INTERNET" />

      <application
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:supportsRtl="true"
      android:theme="@style/AppTheme">

      <!-- TODO: Change android:value when final building -->
      <!--Sample AdMob App ID: ca-app-pub-3940256099942544~3347511713-->
      <meta-data
      android:name="com.google.android.gms.ads.APPLICATION_ID"
      android:value="ca-app-pub-3940256099942544~3347511713"/>

      <activity
      android:name="com.gumangan.uecfispiritualhymns.DictionaryActivity"
      android:label="@string/app_name"
      android:launchMode="singleTop"
      android:theme="@style/AppTheme.NoActionBar">
      <intent-filter>
      <action android:name="android.intent.action.MAIN" />

      <category android:name="android.intent.category.LAUNCHER" />

      <action android:name="android.intent.action.SEARCH" />
      </intent-filter>

      <meta-data
      android:name="android.app.searchable"
      android:resource="@xml/searchable" />
      </activity>
      <activity android:name="com.gumangan.uecfispiritualhymns.WordDetailActivity"
      android:parentActivityName="com.gumangan.uecfispiritualhymns.DictionaryActivity">
      <meta-data
      android:name="android.support.PARENT_ACTIVITY"
      android:value="com.gumangan.uecfispiritualhymns.DictionaryActivity"/>
      </activity>
      </application>


      Gradle Properties



      // Top-level build file where you can add configuration options common to all sub-projects/modules.

      buildscript {
      ext.kotlin_version = '1.3.10'
      repositories {
      google()
      jcenter()
      }
      dependencies {
      classpath 'com.android.tools.build:gradle:3.2.1'
      classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

      // NOTE: Do not place your application dependencies here; they belong
      // in the individual module build.gradle files
      }
      }

      allprojects {
      repositories {
      google()
      jcenter()
      maven {
      url "https://maven.google.com"
      }
      }
      }

      task clean(type: Delete) {
      delete rootProject.buildDir
      }


      Gradle Dependencies



      apply plugin: 'com.android.application'

      apply plugin: 'kotlin-android'

      apply plugin: 'kotlin-android-extensions'

      android {
      compileSdkVersion 27
      defaultConfig {
      applicationId "com.gumangan.uecfispiritualhymns"
      minSdkVersion 16
      targetSdkVersion 27
      versionCode 1
      versionName "1.0"
      testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
      }
      buildTypes {
      release {
      minifyEnabled false
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
      }
      }
      }

      dependencies {
      implementation fileTree(dir: 'libs', include: ['*.jar'])
      implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
      implementation 'com.android.support:appcompat-v7:27.1.1'
      implementation 'com.android.support:support-v4:27.1.1'
      implementation 'com.android.support.constraint:constraint-layout:1.1.3'
      implementation 'com.android.support:design:27.1.1'
      implementation 'com.android.support:cardview-v7:27.1.1'
      implementation 'com.android.support:customtabs:27.1.1'

      implementation 'com.google.android.gms:play-services-ads:17.1.2'

      testImplementation 'junit:junit:4.12'
      androidTestImplementation 'com.android.support.test:runner:1.0.2'
      androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
      }


      DatabaseHelper



      package com.gumangan.uecfispiritualhymns

      import android.content.Context
      import android.database.Cursor
      import android.database.sqlite.SQLiteDatabase
      import android.database.sqlite.SQLiteOpenHelper
      import android.preference.PreferenceManager

      import java.io.FileOutputStream
      import java.io.IOException
      import java.io.InputStream
      import java.io.OutputStream

      class DatabaseHelper(private var mContext: Context) : SQLiteOpenHelper(mContext, DATABASE_NAME, null, DATABASE_VERSION) {
      companion object {
      private val DATABASE_NAME = "simple_dict.db"
      private val DATABASE_VERSION = 1
      val DB_CREATED = "DB_CREATED"
      }

      private var mCreateDb = false
      private var mUpgradeDb = false

      private fun copyDatabaseFromAssets(db: SQLiteDatabase?) {
      var inputStream: InputStream? = null
      var outputStream: OutputStream? = null

      try {
      inputStream = mContext.assets.open(DATABASE_NAME)
      outputStream = FileOutputStream(db?.path)

      val buffer = ByteArray(1024)
      var length: Int = inputStream!!.read(buffer)
      while (length > 0) {
      outputStream.write(buffer, 0, length)
      length = inputStream.read(buffer)
      }
      outputStream.flush()

      val copiedDb = mContext.openOrCreateDatabase(DATABASE_NAME, 0, null)

      val isDbCreated = copiedDb != null

      copiedDb.execSQL("PRAGMA user_version = $DATABASE_VERSION")
      copiedDb.close()

      // DB_CREATED
      val sharedPref = PreferenceManager.getDefaultSharedPreferences(mContext)
      val sharePrefEditor = sharedPref.edit()
      sharePrefEditor.putBoolean(DB_CREATED, isDbCreated)
      sharePrefEditor.apply()
      } catch (e: IOException) {
      e.printStackTrace()
      throw Error("copyDatabaseFromAssets: Error copying database.")
      } finally {
      try {
      outputStream?.close()
      inputStream?.close()
      }catch (e: IOException) {
      e.printStackTrace()
      throw Error("copyDatabaseFromAssets: Error closing stream.")
      }
      }

      }

      override fun onCreate(db: SQLiteDatabase?) {
      mCreateDb = true
      }

      override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
      if(newVersion > oldVersion) {
      mUpgradeDb = true
      }
      }

      override fun onOpen(db: SQLiteDatabase?) {
      if(mCreateDb) {
      mCreateDb = false
      copyDatabaseFromAssets(db)
      }

      if(mUpgradeDb) {
      mUpgradeDb = false
      copyDatabaseFromAssets(db)
      }
      }

      fun getWords(wordPrefix: String = ""): Cursor {
      return if(wordPrefix.isBlank()) {
      readableDatabase.query(DictionaryEntryContract.TABLE_NAME, null,
      null, null, null, null,
      "${DictionaryEntryContract.COLUMN_ID} ASC")
      } else {
      readableDatabase.query(DictionaryEntryContract.TABLE_NAME, null,
      "${DictionaryEntryContract.COLUMN_WORD} LIKE ?", arrayOf("$wordPrefix%"),
      null, null, "${DictionaryEntryContract.COLUMN_ID} ASC")
      }
      }

      fun getWord(id: String): Cursor {
      return readableDatabase.query(DictionaryEntryContract.TABLE_NAME, null,
      "${DictionaryEntryContract.COLUMN_ID}= ?", arrayOf(id),
      null, null, null)
      }
      }


      SearchListAdapter



      package com.gumangan.uecfispiritualhymns

      import android.content.Context
      import android.database.Cursor
      import android.graphics.Color
      import android.view.LayoutInflater
      import android.view.View
      import android.view.ViewGroup
      import android.widget.CursorAdapter
      import android.widget.TextView

      class SearchListAdapter(context: Context, cursor: Cursor) : CursorAdapter(context, cursor, 0) {
      private class ViewHolder {
      var txtWord: TextView? = null
      var txtType: TextView? = null
      var txtMeaning: TextView? = null

      var wordColumnIndex: Int = 0
      var typeColumnIndex: Int = 0
      var meaningColumnIndex: Int = 0
      }

      override fun newView(context: Context?, cursor: Cursor?, parent: ViewGroup?): View {
      val layoutInflater = LayoutInflater.from(context)
      val newView = layoutInflater.inflate(R.layout.search_list_item, parent, false)

      val viewHolder = ViewHolder()
      viewHolder.txtWord = newView.findViewById<TextView>(R.id.txtWord)
      viewHolder.txtType = newView.findViewById<TextView>(R.id.txtType)
      viewHolder.txtMeaning = newView.findViewById<TextView>(R.id.txtMeaning)

      viewHolder.wordColumnIndex = cursor!!.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_WORD)
      viewHolder.typeColumnIndex = cursor!!.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_TYPE)
      viewHolder.meaningColumnIndex = cursor!!.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_MEANING)

      newView.tag = viewHolder

      return newView
      }

      override fun bindView(view: View?, context: Context?, cursor: Cursor?) {
      val viewHolder = view!!.tag as ViewHolder

      viewHolder.txtWord?.text = cursor?.getString(viewHolder.wordColumnIndex)
      viewHolder.txtType?.text = cursor?.getString(viewHolder.typeColumnIndex)
      viewHolder.txtMeaning?.text = cursor?.getString(viewHolder.meaningColumnIndex)
      }

      override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
      val view = super.getView(position, convertView, parent)

      if(position % 2 == 0) {
      view.setBackgroundColor(Color.LTGRAY)
      } else {
      view.setBackgroundColor(Color.WHITE)
      }

      return view;
      }
      }


      DictionaryEntryContract



      package com.gumangan.uecfispiritualhymns

      import android.provider.BaseColumns

      class DictionaryEntryContract : BaseColumns {
      private constructor()

      companion object {
      val TABLE_NAME = "english_words"

      val COLUMN_ID = BaseColumns._ID
      val COLUMN_WORD = "word"
      val COLUMN_TYPE = "type"
      val COLUMN_MEANING = "meaning"
      }
      }


      DictionaryActivity



      package com.gumangan.uecfispiritualhymns

      import android.app.SearchManager
      import android.content.Context
      import android.content.Intent
      import android.os.AsyncTask
      import android.os.Bundle
      import android.preference.PreferenceManager
      import android.support.v7.app.AppCompatActivity
      import android.support.v7.widget.Toolbar
      import android.support.v7.widget.SearchView
      import android.util.Log
      import android.view.Menu
      import android.view.MenuItem
      import android.widget.AdapterView
      import android.widget.ListView
      import com.google.android.gms.ads.AdRequest
      import com.google.android.gms.ads.AdView
      import com.google.android.gms.ads.MobileAds
      import java.lang.ref.WeakReference

      class DictionaryActivity : AppCompatActivity() {

      companion object {
      val TAG = "DictionaryActivity"
      val LAST_SEARCH_WORD: String = "LAST_SEARCH_WORD"
      }

      var mDbHelper: DatabaseHelper? = null
      private var mSearchListAdapter: SearchListAdapter? = null
      private var mSearchQuery: String = ""

      //Google Ads Banner Variable
      lateinit var mAdView : AdView

      override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.content_dictionary)

      mSearchQuery = savedInstanceState?.getString(LAST_SEARCH_WORD) ?: ""
      mDbHelper = DatabaseHelper(applicationContext)

      if(!isDbLoaded()) {
      showLoadingUI()
      LoadViewTask(this).execute()
      } else {
      showDictUI()
      }

      /* TODO: Change ADMOB ID's when final building */
      //Google Ads
      //MobileAds.initialize(this, "ca-app-pub-3940256099942544~3347511713")
      //Google Test Ads
      MobileAds.initialize(this, "ca-app-pub-3940256099942544~3347511713")

      //Google Ads Banner
      mAdView = findViewById(R.id.adView)
      val adRequest = AdRequest.Builder().build()
      mAdView.loadAd(adRequest)

      }

      private fun isDbLoaded(): Boolean {
      val sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
      return sharedPref.getBoolean(DatabaseHelper.DB_CREATED, false)
      }

      private fun showLoadingUI() {
      setContentView(R.layout.activity_dictionary_loading)
      }

      private fun showDictUI() {
      setContentView(R.layout.activity_dictionary)

      val toolbar = findViewById<Toolbar>(R.id.toolbar)
      setSupportActionBar(toolbar)

      supportActionBar?.setIcon(R.mipmap.ic_launcher)

      mSearchListAdapter = SearchListAdapter(applicationContext, mDbHelper!!.getWords(mSearchQuery))
      val lstWords = (findViewById<ListView>(R.id.lstWords))
      lstWords.adapter = mSearchListAdapter
      lstWords.onItemClickListener = AdapterView.OnItemClickListener { _, _, _, id ->
      val wordDetailIntent = Intent(applicationContext, WordDetailActivity::class.java)
      wordDetailIntent.putExtra(WordDetailActivity.WORD_ID, "$id")
      startActivity(wordDetailIntent)
      }
      }

      override fun onSaveInstanceState(outState: Bundle?) {
      super.onSaveInstanceState(outState)
      outState?.putString(LAST_SEARCH_WORD, mSearchQuery)
      }

      override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
      mSearchQuery = savedInstanceState?.getString(LAST_SEARCH_WORD) ?: ""
      super.onRestoreInstanceState(savedInstanceState)
      }

      override fun onNewIntent(intent: Intent?) {
      super.onNewIntent(intent)

      if(intent?.action.equals(Intent.ACTION_SEARCH)) {
      val searchQuery = intent?.getStringExtra(SearchManager.QUERY) ?: ""
      updateListByQuery(searchQuery)
      }
      }

      override fun onCreateOptionsMenu(menu: Menu): Boolean {
      menuInflater.inflate(R.menu.menu_dictionary, menu)

      val searchView: SearchView? = menu.findItem(R.id.action_search).actionView as? SearchView
      val searchManager: SearchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
      searchView?.setSearchableInfo(searchManager.getSearchableInfo(componentName))

      searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
      override fun onQueryTextSubmit(query: String?): Boolean {
      return false
      }

      override fun onQueryTextChange(newText: String?): Boolean {
      updateListByQuery(newText ?: "")
      return true
      }
      })

      return true
      }

      private fun updateListByQuery(searchQuery: String) {
      mSearchQuery = searchQuery
      mSearchListAdapter?.changeCursor(mDbHelper!!.getWords(searchQuery))
      }

      override fun onOptionsItemSelected(item: MenuItem): Boolean {
      return when (item.itemId) {
      R.id.action_search -> {
      onSearchRequested()
      true
      }
      else -> super.onOptionsItemSelected(item)
      }
      }

      private class LoadViewTask(activity: DictionaryActivity) : AsyncTask<Void, Void, Void>() {
      private var mActivity = WeakReference<DictionaryActivity>(activity)

      override fun doInBackground(vararg params: Void): Void? {
      if(getActivityInstance()?.mDbHelper?.readableDatabase?.isOpen == true) {
      Log.d(TAG, "Db is OK.")
      }
      return null
      }

      override fun onPostExecute(result: Void?) {
      if(getActivityInstance()?.isDbLoaded() == true) {
      getActivityInstance()?.showDictUI()
      }
      }

      private fun getActivityInstance() = mActivity.get()
      }
      }


      WordDetailActivity



      package com.gumangan.uecfispiritualhymns

      import android.support.v7.app.AppCompatActivity
      import android.os.Bundle
      import android.widget.TextView

      class WordDetailActivity : AppCompatActivity() {

      companion object {
      const val WORD_ID = "WORD_ID"
      }

      override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_word_detail)

      val wordId = intent.getStringExtra(WORD_ID) ?: ""
      if(wordId.isBlank()) {
      finish()
      }

      val dbHelper = DatabaseHelper(applicationContext)
      val cursor = dbHelper.getWord(wordId)
      if(cursor.moveToFirst()) {
      val txtWord = findViewById<TextView>(R.id.txtWord)
      val txtType = findViewById<TextView>(R.id.txtType)
      val txtMeaning = findViewById<TextView>(R.id.txtMeaning)

      txtWord?.text = cursor.getString(cursor.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_WORD))
      txtType?.text = cursor.getString(cursor.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_TYPE))
      txtMeaning?.text = cursor.getString(cursor.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_MEANING))
      }
      }
      }


      activity_dictionary.xml



      <?xml version="1.0" encoding="utf-8"?>
      <android.support.design.widget.CoordinatorLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      tools:context="com.gumangan.uecfispiritualhymns.DictionaryActivity">

      <android.support.design.widget.AppBarLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:theme="@style/AppTheme.AppBarOverlay">

      <android.support.v7.widget.Toolbar
      android:id="@+id/toolbar"
      android:layout_width="match_parent"
      android:layout_height="?attr/actionBarSize"
      android:background="?attr/colorPrimary"
      app:popupTheme="@style/AppTheme.PopupOverlay" />

      </android.support.design.widget.AppBarLayout>

      <include layout="@layout/content_dictionary" />

      </android.support.design.widget.CoordinatorLayout>


      content_dictionary.xml



      <?xml version="1.0" encoding="utf-8"?>
      <android.support.constraint.ConstraintLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      app:layout_behavior="@string/appbar_scrolling_view_behavior"
      tools:context="com.gumangan.uecfispiritualhymns.DictionaryActivity"
      tools:showIn="@layout/activity_dictionary">

      <ListView
      android:id="@+id/lstWords"
      android:layout_width="0dp"
      android:layout_height="0dp"
      android:layout_marginBottom="0dp"
      android:layout_marginEnd="0dp"
      android:layout_marginStart="0dp"
      android:layout_marginTop="0dp"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent" />


      <!--Google Ads Banner Display-->
      <com.google.android.gms.ads.AdView
      xmlns:ads="http://schemas.android.com/apk/res-auto"
      android:id="@+id/adView"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentBottom="true"
      android:layout_centerHorizontal="true"
      android:layout_marginBottom="5dp"
      android:visibility="visible"
      ads:adSize="LARGE_BANNER"
      ads:adUnitId="ca-app-pub-3940256099942544/6300978111"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintRight_toRightOf="parent">

      </com.google.android.gms.ads.AdView>

      </android.support.constraint.ConstraintLayout>


      activity_dictionary_loading.xml



      <?xml version="1.0" encoding="utf-8"?>
      <android.support.constraint.ConstraintLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      tools:context="com.gumangan.uecfispiritualhymns.DictionaryActivity">

      <TextView
      android:id="@+id/textView"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginBottom="8dp"
      android:layout_marginEnd="8dp"
      android:layout_marginStart="8dp"
      android:layout_marginTop="8dp"
      android:text="@string/dictionary_db_preparing"
      android:textAlignment="center"
      android:textSize="18sp"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      tools:text="@string/dictionary_db_preparing" />
      </android.support.constraint.ConstraintLayout>


      search_list_item.xml



      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:orientation="vertical"
      android:padding="16dp">

      <TextView
      android:id="@+id/txtWord"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:textSize="18sp"
      android:textStyle="bold"
      tools:text="Word" />

      <TextView
      android:id="@+id/txtType"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:textSize="14sp"
      android:textStyle="italic"
      tools:text="Type" />

      <TextView
      android:id="@+id/txtMeaning"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:textSize="18sp"
      tools:text="Meaning" />
      </LinearLayout>


      activity_word_detail.xml



      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:orientation="vertical"
      android:padding="16dp"
      tools:context="com.gumangan.uecfispiritualhymns.WordDetailActivity">

      <TextView
      android:id="@+id/txtWord"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:textSize="20sp"
      android:textStyle="bold"
      tools:text="Word" />

      <TextView
      android:id="@+id/txtType"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:textSize="18sp"
      android:textStyle="italic"
      tools:text="Type" />

      <TextView
      android:id="@+id/txtMeaning"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:textSize="20sp"
      tools:text="Meaning" />

      </LinearLayout>


      This is the LogCat error



      12-09 07:52:40.554 14146-14146/com.gumangan.uecfispiritualhymns E/AndroidRuntime: FATAL EXCEPTION: main
      java.lang.RuntimeException: Unable to start activity
      ComponentInfo{com.gumangan.uecfispiritualhymns/com.gumangan.uecfispiritualhymns.DictionaryActivity}: java.lang.IllegalStateException: findViewById(R.id.adView) must not be null
      at
      android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
      at
      android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
      at android.app.ActivityThread.access$600(ActivityThread.java:130)
      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
      at android.os.Handler.dispatchMessage(Handler.java:99)
      at android.os.Looper.loop(Looper.java:137)
      at android.app.ActivityThread.main(ActivityThread.java:4745)
      at java.lang.reflect.Method.invokeNative(Native Method)
      at java.lang.reflect.Method.invoke(Method.java:511)
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
      at dalvik.system.NativeStart.main(Native Method)
      Caused by: java.lang.IllegalStateException: findViewById(R.id.adView) must not be null
      at com.gumangan.uecfispiritualhymns.DictionaryActivity.onCreate(DictionaryActivity.kt:57)
      at android.app.Activity.performCreate(Activity.java:5008)
      at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084) 
      at android.app.ActivityThread.access$600(ActivityThread.java:130) 
      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195) 
      at android.os.Handler.dispatchMessage(Handler.java:99) 
      at android.os.Looper.loop(Looper.java:137) 
      at android.app.ActivityThread.main(ActivityThread.java:4745) 
      at java.lang.reflect.Method.invokeNative(Native Method) 
      at java.lang.reflect.Method.invoke(Method.java:511) 
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) 
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 
      at dalvik.system.NativeStart.main(Native Method) 


      The app is about dictionary









      share







      New contributor




      Gumangan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      My App is working fine and then I tried to add AdMob dependencies. That's when things get complicated. On first install and then open App crashes. But on second and consecutive open the app is working fine, all ads are showing.



      For me, this is a bad user experience because at first open they think it is not a good app. And maybe they will uninstall it immediately.



      Maybe there's something I need to improve or add but I can't figure it out. I need help regarding polishing my code.



      Android Manifest



      <?xml version="1.0" encoding="utf-8"?>
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.gumangan.uecfispiritualhymns">

      <uses-permission android:name="android.permission.INTERNET" />

      <application
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:supportsRtl="true"
      android:theme="@style/AppTheme">

      <!-- TODO: Change android:value when final building -->
      <!--Sample AdMob App ID: ca-app-pub-3940256099942544~3347511713-->
      <meta-data
      android:name="com.google.android.gms.ads.APPLICATION_ID"
      android:value="ca-app-pub-3940256099942544~3347511713"/>

      <activity
      android:name="com.gumangan.uecfispiritualhymns.DictionaryActivity"
      android:label="@string/app_name"
      android:launchMode="singleTop"
      android:theme="@style/AppTheme.NoActionBar">
      <intent-filter>
      <action android:name="android.intent.action.MAIN" />

      <category android:name="android.intent.category.LAUNCHER" />

      <action android:name="android.intent.action.SEARCH" />
      </intent-filter>

      <meta-data
      android:name="android.app.searchable"
      android:resource="@xml/searchable" />
      </activity>
      <activity android:name="com.gumangan.uecfispiritualhymns.WordDetailActivity"
      android:parentActivityName="com.gumangan.uecfispiritualhymns.DictionaryActivity">
      <meta-data
      android:name="android.support.PARENT_ACTIVITY"
      android:value="com.gumangan.uecfispiritualhymns.DictionaryActivity"/>
      </activity>
      </application>


      Gradle Properties



      // Top-level build file where you can add configuration options common to all sub-projects/modules.

      buildscript {
      ext.kotlin_version = '1.3.10'
      repositories {
      google()
      jcenter()
      }
      dependencies {
      classpath 'com.android.tools.build:gradle:3.2.1'
      classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

      // NOTE: Do not place your application dependencies here; they belong
      // in the individual module build.gradle files
      }
      }

      allprojects {
      repositories {
      google()
      jcenter()
      maven {
      url "https://maven.google.com"
      }
      }
      }

      task clean(type: Delete) {
      delete rootProject.buildDir
      }


      Gradle Dependencies



      apply plugin: 'com.android.application'

      apply plugin: 'kotlin-android'

      apply plugin: 'kotlin-android-extensions'

      android {
      compileSdkVersion 27
      defaultConfig {
      applicationId "com.gumangan.uecfispiritualhymns"
      minSdkVersion 16
      targetSdkVersion 27
      versionCode 1
      versionName "1.0"
      testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
      }
      buildTypes {
      release {
      minifyEnabled false
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
      }
      }
      }

      dependencies {
      implementation fileTree(dir: 'libs', include: ['*.jar'])
      implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
      implementation 'com.android.support:appcompat-v7:27.1.1'
      implementation 'com.android.support:support-v4:27.1.1'
      implementation 'com.android.support.constraint:constraint-layout:1.1.3'
      implementation 'com.android.support:design:27.1.1'
      implementation 'com.android.support:cardview-v7:27.1.1'
      implementation 'com.android.support:customtabs:27.1.1'

      implementation 'com.google.android.gms:play-services-ads:17.1.2'

      testImplementation 'junit:junit:4.12'
      androidTestImplementation 'com.android.support.test:runner:1.0.2'
      androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
      }


      DatabaseHelper



      package com.gumangan.uecfispiritualhymns

      import android.content.Context
      import android.database.Cursor
      import android.database.sqlite.SQLiteDatabase
      import android.database.sqlite.SQLiteOpenHelper
      import android.preference.PreferenceManager

      import java.io.FileOutputStream
      import java.io.IOException
      import java.io.InputStream
      import java.io.OutputStream

      class DatabaseHelper(private var mContext: Context) : SQLiteOpenHelper(mContext, DATABASE_NAME, null, DATABASE_VERSION) {
      companion object {
      private val DATABASE_NAME = "simple_dict.db"
      private val DATABASE_VERSION = 1
      val DB_CREATED = "DB_CREATED"
      }

      private var mCreateDb = false
      private var mUpgradeDb = false

      private fun copyDatabaseFromAssets(db: SQLiteDatabase?) {
      var inputStream: InputStream? = null
      var outputStream: OutputStream? = null

      try {
      inputStream = mContext.assets.open(DATABASE_NAME)
      outputStream = FileOutputStream(db?.path)

      val buffer = ByteArray(1024)
      var length: Int = inputStream!!.read(buffer)
      while (length > 0) {
      outputStream.write(buffer, 0, length)
      length = inputStream.read(buffer)
      }
      outputStream.flush()

      val copiedDb = mContext.openOrCreateDatabase(DATABASE_NAME, 0, null)

      val isDbCreated = copiedDb != null

      copiedDb.execSQL("PRAGMA user_version = $DATABASE_VERSION")
      copiedDb.close()

      // DB_CREATED
      val sharedPref = PreferenceManager.getDefaultSharedPreferences(mContext)
      val sharePrefEditor = sharedPref.edit()
      sharePrefEditor.putBoolean(DB_CREATED, isDbCreated)
      sharePrefEditor.apply()
      } catch (e: IOException) {
      e.printStackTrace()
      throw Error("copyDatabaseFromAssets: Error copying database.")
      } finally {
      try {
      outputStream?.close()
      inputStream?.close()
      }catch (e: IOException) {
      e.printStackTrace()
      throw Error("copyDatabaseFromAssets: Error closing stream.")
      }
      }

      }

      override fun onCreate(db: SQLiteDatabase?) {
      mCreateDb = true
      }

      override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
      if(newVersion > oldVersion) {
      mUpgradeDb = true
      }
      }

      override fun onOpen(db: SQLiteDatabase?) {
      if(mCreateDb) {
      mCreateDb = false
      copyDatabaseFromAssets(db)
      }

      if(mUpgradeDb) {
      mUpgradeDb = false
      copyDatabaseFromAssets(db)
      }
      }

      fun getWords(wordPrefix: String = ""): Cursor {
      return if(wordPrefix.isBlank()) {
      readableDatabase.query(DictionaryEntryContract.TABLE_NAME, null,
      null, null, null, null,
      "${DictionaryEntryContract.COLUMN_ID} ASC")
      } else {
      readableDatabase.query(DictionaryEntryContract.TABLE_NAME, null,
      "${DictionaryEntryContract.COLUMN_WORD} LIKE ?", arrayOf("$wordPrefix%"),
      null, null, "${DictionaryEntryContract.COLUMN_ID} ASC")
      }
      }

      fun getWord(id: String): Cursor {
      return readableDatabase.query(DictionaryEntryContract.TABLE_NAME, null,
      "${DictionaryEntryContract.COLUMN_ID}= ?", arrayOf(id),
      null, null, null)
      }
      }


      SearchListAdapter



      package com.gumangan.uecfispiritualhymns

      import android.content.Context
      import android.database.Cursor
      import android.graphics.Color
      import android.view.LayoutInflater
      import android.view.View
      import android.view.ViewGroup
      import android.widget.CursorAdapter
      import android.widget.TextView

      class SearchListAdapter(context: Context, cursor: Cursor) : CursorAdapter(context, cursor, 0) {
      private class ViewHolder {
      var txtWord: TextView? = null
      var txtType: TextView? = null
      var txtMeaning: TextView? = null

      var wordColumnIndex: Int = 0
      var typeColumnIndex: Int = 0
      var meaningColumnIndex: Int = 0
      }

      override fun newView(context: Context?, cursor: Cursor?, parent: ViewGroup?): View {
      val layoutInflater = LayoutInflater.from(context)
      val newView = layoutInflater.inflate(R.layout.search_list_item, parent, false)

      val viewHolder = ViewHolder()
      viewHolder.txtWord = newView.findViewById<TextView>(R.id.txtWord)
      viewHolder.txtType = newView.findViewById<TextView>(R.id.txtType)
      viewHolder.txtMeaning = newView.findViewById<TextView>(R.id.txtMeaning)

      viewHolder.wordColumnIndex = cursor!!.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_WORD)
      viewHolder.typeColumnIndex = cursor!!.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_TYPE)
      viewHolder.meaningColumnIndex = cursor!!.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_MEANING)

      newView.tag = viewHolder

      return newView
      }

      override fun bindView(view: View?, context: Context?, cursor: Cursor?) {
      val viewHolder = view!!.tag as ViewHolder

      viewHolder.txtWord?.text = cursor?.getString(viewHolder.wordColumnIndex)
      viewHolder.txtType?.text = cursor?.getString(viewHolder.typeColumnIndex)
      viewHolder.txtMeaning?.text = cursor?.getString(viewHolder.meaningColumnIndex)
      }

      override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
      val view = super.getView(position, convertView, parent)

      if(position % 2 == 0) {
      view.setBackgroundColor(Color.LTGRAY)
      } else {
      view.setBackgroundColor(Color.WHITE)
      }

      return view;
      }
      }


      DictionaryEntryContract



      package com.gumangan.uecfispiritualhymns

      import android.provider.BaseColumns

      class DictionaryEntryContract : BaseColumns {
      private constructor()

      companion object {
      val TABLE_NAME = "english_words"

      val COLUMN_ID = BaseColumns._ID
      val COLUMN_WORD = "word"
      val COLUMN_TYPE = "type"
      val COLUMN_MEANING = "meaning"
      }
      }


      DictionaryActivity



      package com.gumangan.uecfispiritualhymns

      import android.app.SearchManager
      import android.content.Context
      import android.content.Intent
      import android.os.AsyncTask
      import android.os.Bundle
      import android.preference.PreferenceManager
      import android.support.v7.app.AppCompatActivity
      import android.support.v7.widget.Toolbar
      import android.support.v7.widget.SearchView
      import android.util.Log
      import android.view.Menu
      import android.view.MenuItem
      import android.widget.AdapterView
      import android.widget.ListView
      import com.google.android.gms.ads.AdRequest
      import com.google.android.gms.ads.AdView
      import com.google.android.gms.ads.MobileAds
      import java.lang.ref.WeakReference

      class DictionaryActivity : AppCompatActivity() {

      companion object {
      val TAG = "DictionaryActivity"
      val LAST_SEARCH_WORD: String = "LAST_SEARCH_WORD"
      }

      var mDbHelper: DatabaseHelper? = null
      private var mSearchListAdapter: SearchListAdapter? = null
      private var mSearchQuery: String = ""

      //Google Ads Banner Variable
      lateinit var mAdView : AdView

      override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.content_dictionary)

      mSearchQuery = savedInstanceState?.getString(LAST_SEARCH_WORD) ?: ""
      mDbHelper = DatabaseHelper(applicationContext)

      if(!isDbLoaded()) {
      showLoadingUI()
      LoadViewTask(this).execute()
      } else {
      showDictUI()
      }

      /* TODO: Change ADMOB ID's when final building */
      //Google Ads
      //MobileAds.initialize(this, "ca-app-pub-3940256099942544~3347511713")
      //Google Test Ads
      MobileAds.initialize(this, "ca-app-pub-3940256099942544~3347511713")

      //Google Ads Banner
      mAdView = findViewById(R.id.adView)
      val adRequest = AdRequest.Builder().build()
      mAdView.loadAd(adRequest)

      }

      private fun isDbLoaded(): Boolean {
      val sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
      return sharedPref.getBoolean(DatabaseHelper.DB_CREATED, false)
      }

      private fun showLoadingUI() {
      setContentView(R.layout.activity_dictionary_loading)
      }

      private fun showDictUI() {
      setContentView(R.layout.activity_dictionary)

      val toolbar = findViewById<Toolbar>(R.id.toolbar)
      setSupportActionBar(toolbar)

      supportActionBar?.setIcon(R.mipmap.ic_launcher)

      mSearchListAdapter = SearchListAdapter(applicationContext, mDbHelper!!.getWords(mSearchQuery))
      val lstWords = (findViewById<ListView>(R.id.lstWords))
      lstWords.adapter = mSearchListAdapter
      lstWords.onItemClickListener = AdapterView.OnItemClickListener { _, _, _, id ->
      val wordDetailIntent = Intent(applicationContext, WordDetailActivity::class.java)
      wordDetailIntent.putExtra(WordDetailActivity.WORD_ID, "$id")
      startActivity(wordDetailIntent)
      }
      }

      override fun onSaveInstanceState(outState: Bundle?) {
      super.onSaveInstanceState(outState)
      outState?.putString(LAST_SEARCH_WORD, mSearchQuery)
      }

      override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
      mSearchQuery = savedInstanceState?.getString(LAST_SEARCH_WORD) ?: ""
      super.onRestoreInstanceState(savedInstanceState)
      }

      override fun onNewIntent(intent: Intent?) {
      super.onNewIntent(intent)

      if(intent?.action.equals(Intent.ACTION_SEARCH)) {
      val searchQuery = intent?.getStringExtra(SearchManager.QUERY) ?: ""
      updateListByQuery(searchQuery)
      }
      }

      override fun onCreateOptionsMenu(menu: Menu): Boolean {
      menuInflater.inflate(R.menu.menu_dictionary, menu)

      val searchView: SearchView? = menu.findItem(R.id.action_search).actionView as? SearchView
      val searchManager: SearchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
      searchView?.setSearchableInfo(searchManager.getSearchableInfo(componentName))

      searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
      override fun onQueryTextSubmit(query: String?): Boolean {
      return false
      }

      override fun onQueryTextChange(newText: String?): Boolean {
      updateListByQuery(newText ?: "")
      return true
      }
      })

      return true
      }

      private fun updateListByQuery(searchQuery: String) {
      mSearchQuery = searchQuery
      mSearchListAdapter?.changeCursor(mDbHelper!!.getWords(searchQuery))
      }

      override fun onOptionsItemSelected(item: MenuItem): Boolean {
      return when (item.itemId) {
      R.id.action_search -> {
      onSearchRequested()
      true
      }
      else -> super.onOptionsItemSelected(item)
      }
      }

      private class LoadViewTask(activity: DictionaryActivity) : AsyncTask<Void, Void, Void>() {
      private var mActivity = WeakReference<DictionaryActivity>(activity)

      override fun doInBackground(vararg params: Void): Void? {
      if(getActivityInstance()?.mDbHelper?.readableDatabase?.isOpen == true) {
      Log.d(TAG, "Db is OK.")
      }
      return null
      }

      override fun onPostExecute(result: Void?) {
      if(getActivityInstance()?.isDbLoaded() == true) {
      getActivityInstance()?.showDictUI()
      }
      }

      private fun getActivityInstance() = mActivity.get()
      }
      }


      WordDetailActivity



      package com.gumangan.uecfispiritualhymns

      import android.support.v7.app.AppCompatActivity
      import android.os.Bundle
      import android.widget.TextView

      class WordDetailActivity : AppCompatActivity() {

      companion object {
      const val WORD_ID = "WORD_ID"
      }

      override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_word_detail)

      val wordId = intent.getStringExtra(WORD_ID) ?: ""
      if(wordId.isBlank()) {
      finish()
      }

      val dbHelper = DatabaseHelper(applicationContext)
      val cursor = dbHelper.getWord(wordId)
      if(cursor.moveToFirst()) {
      val txtWord = findViewById<TextView>(R.id.txtWord)
      val txtType = findViewById<TextView>(R.id.txtType)
      val txtMeaning = findViewById<TextView>(R.id.txtMeaning)

      txtWord?.text = cursor.getString(cursor.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_WORD))
      txtType?.text = cursor.getString(cursor.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_TYPE))
      txtMeaning?.text = cursor.getString(cursor.getColumnIndexOrThrow(DictionaryEntryContract.COLUMN_MEANING))
      }
      }
      }


      activity_dictionary.xml



      <?xml version="1.0" encoding="utf-8"?>
      <android.support.design.widget.CoordinatorLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      tools:context="com.gumangan.uecfispiritualhymns.DictionaryActivity">

      <android.support.design.widget.AppBarLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:theme="@style/AppTheme.AppBarOverlay">

      <android.support.v7.widget.Toolbar
      android:id="@+id/toolbar"
      android:layout_width="match_parent"
      android:layout_height="?attr/actionBarSize"
      android:background="?attr/colorPrimary"
      app:popupTheme="@style/AppTheme.PopupOverlay" />

      </android.support.design.widget.AppBarLayout>

      <include layout="@layout/content_dictionary" />

      </android.support.design.widget.CoordinatorLayout>


      content_dictionary.xml



      <?xml version="1.0" encoding="utf-8"?>
      <android.support.constraint.ConstraintLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      app:layout_behavior="@string/appbar_scrolling_view_behavior"
      tools:context="com.gumangan.uecfispiritualhymns.DictionaryActivity"
      tools:showIn="@layout/activity_dictionary">

      <ListView
      android:id="@+id/lstWords"
      android:layout_width="0dp"
      android:layout_height="0dp"
      android:layout_marginBottom="0dp"
      android:layout_marginEnd="0dp"
      android:layout_marginStart="0dp"
      android:layout_marginTop="0dp"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent" />


      <!--Google Ads Banner Display-->
      <com.google.android.gms.ads.AdView
      xmlns:ads="http://schemas.android.com/apk/res-auto"
      android:id="@+id/adView"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentBottom="true"
      android:layout_centerHorizontal="true"
      android:layout_marginBottom="5dp"
      android:visibility="visible"
      ads:adSize="LARGE_BANNER"
      ads:adUnitId="ca-app-pub-3940256099942544/6300978111"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintRight_toRightOf="parent">

      </com.google.android.gms.ads.AdView>

      </android.support.constraint.ConstraintLayout>


      activity_dictionary_loading.xml



      <?xml version="1.0" encoding="utf-8"?>
      <android.support.constraint.ConstraintLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      tools:context="com.gumangan.uecfispiritualhymns.DictionaryActivity">

      <TextView
      android:id="@+id/textView"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginBottom="8dp"
      android:layout_marginEnd="8dp"
      android:layout_marginStart="8dp"
      android:layout_marginTop="8dp"
      android:text="@string/dictionary_db_preparing"
      android:textAlignment="center"
      android:textSize="18sp"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      tools:text="@string/dictionary_db_preparing" />
      </android.support.constraint.ConstraintLayout>


      search_list_item.xml



      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:orientation="vertical"
      android:padding="16dp">

      <TextView
      android:id="@+id/txtWord"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:textSize="18sp"
      android:textStyle="bold"
      tools:text="Word" />

      <TextView
      android:id="@+id/txtType"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:textSize="14sp"
      android:textStyle="italic"
      tools:text="Type" />

      <TextView
      android:id="@+id/txtMeaning"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:textSize="18sp"
      tools:text="Meaning" />
      </LinearLayout>


      activity_word_detail.xml



      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:orientation="vertical"
      android:padding="16dp"
      tools:context="com.gumangan.uecfispiritualhymns.WordDetailActivity">

      <TextView
      android:id="@+id/txtWord"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:textSize="20sp"
      android:textStyle="bold"
      tools:text="Word" />

      <TextView
      android:id="@+id/txtType"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:textSize="18sp"
      android:textStyle="italic"
      tools:text="Type" />

      <TextView
      android:id="@+id/txtMeaning"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:textSize="20sp"
      tools:text="Meaning" />

      </LinearLayout>


      This is the LogCat error



      12-09 07:52:40.554 14146-14146/com.gumangan.uecfispiritualhymns E/AndroidRuntime: FATAL EXCEPTION: main
      java.lang.RuntimeException: Unable to start activity
      ComponentInfo{com.gumangan.uecfispiritualhymns/com.gumangan.uecfispiritualhymns.DictionaryActivity}: java.lang.IllegalStateException: findViewById(R.id.adView) must not be null
      at
      android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
      at
      android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
      at android.app.ActivityThread.access$600(ActivityThread.java:130)
      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
      at android.os.Handler.dispatchMessage(Handler.java:99)
      at android.os.Looper.loop(Looper.java:137)
      at android.app.ActivityThread.main(ActivityThread.java:4745)
      at java.lang.reflect.Method.invokeNative(Native Method)
      at java.lang.reflect.Method.invoke(Method.java:511)
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
      at dalvik.system.NativeStart.main(Native Method)
      Caused by: java.lang.IllegalStateException: findViewById(R.id.adView) must not be null
      at com.gumangan.uecfispiritualhymns.DictionaryActivity.onCreate(DictionaryActivity.kt:57)
      at android.app.Activity.performCreate(Activity.java:5008)
      at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084) 
      at android.app.ActivityThread.access$600(ActivityThread.java:130) 
      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195) 
      at android.os.Handler.dispatchMessage(Handler.java:99) 
      at android.os.Looper.loop(Looper.java:137) 
      at android.app.ActivityThread.main(ActivityThread.java:4745) 
      at java.lang.reflect.Method.invokeNative(Native Method) 
      at java.lang.reflect.Method.invoke(Method.java:511) 
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) 
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 
      at dalvik.system.NativeStart.main(Native Method) 


      The app is about dictionary







      android database xml sqlite kotlin





      share







      New contributor




      Gumangan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.










      share







      New contributor




      Gumangan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.








      share



      share






      New contributor




      Gumangan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 2 mins ago









      Gumangan

      12




      12




      New contributor




      Gumangan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      Gumangan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      Gumangan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.



























          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });






          Gumangan is a new contributor. Be nice, and check out our Code of Conduct.










          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209301%2fapp-crashes-on-first-open-only-when-admob-is-added-but-working-fine-on-next-open%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown






























          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          Gumangan is a new contributor. Be nice, and check out our Code of Conduct.










          draft saved

          draft discarded


















          Gumangan is a new contributor. Be nice, and check out our Code of Conduct.













          Gumangan is a new contributor. Be nice, and check out our Code of Conduct.












          Gumangan is a new contributor. Be nice, and check out our Code of Conduct.
















          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209301%2fapp-crashes-on-first-open-only-when-admob-is-added-but-working-fine-on-next-open%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Costa Masnaga

          Fotorealismo

          Sidney Franklin