Reputation: 21
I want to send real time data from the Native Module to the React Native when a widget button is clicks but getting an error "java.lang.IllegalStateException: Tried to access a JS module before the React instance was fully set up. Calls to ReactContext#getJSModule should only happen once initialize() has been called on your native module."
On the the Native Module, I am using SingleCounterWidget.kt and MySharedPreferencesModule.kt
SingleCounterWidget.kt file code:
package com.servingsizetdiet
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
import android.os.Build
import android.widget.RemoteViews
import androidx.annotation.RequiresApi
import com.facebook.react.bridge.ReactApplicationContext
import java.time.LocalDate
import java.time.format.TextStyle
import java.util.Locale
import java.util.Random
/**
* Implementation of App Widget functionality.
*/
const val WIDGET_INC = "com.servingsizetdiet.INCREMENT"
const val WIDGET_DEC = "com.servingsizetdiet.DECREMENT"
const val WIDGET_EXEC = "com.servingsizetdiet.EXEC"
const val WIDGET_REF = "com.servingsizetdiet.REF"
class SingleCounterWidget : AppWidgetProvider() {
// private var mCounter: Int = 0
// private val sharedPreferences: SharedPreferences = reactContext.getSharedPreferences("MySharedPrefs", Context.MODE_PRIVATE)
@RequiresApi(Build.VERSION_CODES.O)
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
// There may be multiple widgets active, so update all of them
for (appWidgetId in appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId)
}
}
@RequiresApi(Build.VERSION_CODES.O)
override fun onReceive(context: Context, intent: Intent) {
super.onReceive(context, intent)
if (intent.action == WIDGET_INC){
val sharedPreferences = context.getSharedPreferences("MySharedPrefs", Context.MODE_PRIVATE)
val currData = sharedPreferences.getString("appdata", "No data")
val stringToNum = currData?.toDouble()
val incByOne = 0.5
val afterInc = stringToNum?.plus(incByOne)
val editor = sharedPreferences.edit()
editor.putString("appdata", afterInc.toString())
editor.apply()
val appWidgetManager = AppWidgetManager.getInstance(context)
val appWidgetIds = appWidgetManager.getAppWidgetIds(ComponentName(context, SingleCounterWidget::class.java))
onUpdate(context, appWidgetManager, appWidgetIds)
val mySharedPreferencesModule = MySharedPreferencesModule(ReactApplicationContext(context))
mySharedPreferencesModule.onWidgetButtonClick()
// mySharedPreferencesModule.sendDataToReactNative("currData")
// mySharedPreferencesModule.sendDataToReactNative("Your data")
}
if (intent.action == WIDGET_DEC){
val sharedPreferences = context.getSharedPreferences("MySharedPrefs", Context.MODE_PRIVATE)
val currData = sharedPreferences.getString("appdata", "No data")
val stringToNum = currData?.toDouble()
val decByOne = 0.5
val afterInc = stringToNum?.minus(decByOne)
val editor = sharedPreferences.edit()
editor.putString("appdata", afterInc.toString())
editor.apply()
val appWidgetManager = AppWidgetManager.getInstance(context)
val appWidgetIds = appWidgetManager.getAppWidgetIds(ComponentName(context, SingleCounterWidget::class.java))
onUpdate(context, appWidgetManager, appWidgetIds)
val mySharedPreferencesModule = MySharedPreferencesModule(ReactApplicationContext(context))
mySharedPreferencesModule.onWidgetButtonClick()
// mySharedPreferencesModule.sendDataToReactNative("currData")
// mySharedPreferencesModule.sendDataToReactNative("Your data")
}
if (intent.action == WIDGET_EXEC){
val sharedPreferences = context.getSharedPreferences("MySharedPrefs", Context.MODE_PRIVATE)
val currData = sharedPreferences.getString("appdata", "No data")
val editor = sharedPreferences.edit()
val isExec = sharedPreferences.getString("isExec", "No data")
if(isExec != "true"){
val stringToNum = currData?.toDouble()
val decByOne = 1
val afterDec = stringToNum?.minus(decByOne)
editor.putString("appdata", afterDec.toString())
editor.putString("isExec", "true")
}
editor.apply()
val appWidgetManager = AppWidgetManager.getInstance(context)
val appWidgetIds = appWidgetManager.getAppWidgetIds(ComponentName(context, SingleCounterWidget::class.java))
onUpdate(context, appWidgetManager, appWidgetIds)
val mySharedPreferencesModule = MySharedPreferencesModule(ReactApplicationContext(context))
mySharedPreferencesModule.onWidgetButtonClick()
// mySharedPreferencesModule.sendDataToReactNative("currData")
// mySharedPreferencesModule.sendDataToReactNative("Your data")
}
if (intent.action == WIDGET_REF){
val sharedPreferences = context.getSharedPreferences("MySharedPrefs", Context.MODE_PRIVATE)
// val currData = sharedPreferences.getString("appdata", "No data")
// val stringToNum = currData?.toDouble()
// val decByOne = 1
// val afterInc = stringToNum?.minus(decByOne)
val editor = sharedPreferences.edit()
editor.putString("appdata", "0.0")
editor.putString("isExec", "false")
editor.apply()
val appWidgetManager = AppWidgetManager.getInstance(context)
val appWidgetIds = appWidgetManager.getAppWidgetIds(ComponentName(context, SingleCounterWidget::class.java))
onUpdate(context, appWidgetManager, appWidgetIds)
val mySharedPreferencesModule = MySharedPreferencesModule(ReactApplicationContext(context))
mySharedPreferencesModule.onWidgetButtonClick()
// mySharedPreferencesModule.sendDataToReactNative("currData")
// mySharedPreferencesModule.sendDataToReactNative("Your data")
}
if (intent.action == "android.appwidget.action.APPWIDGET_UPDATE") {
val appWidgetManager = AppWidgetManager.getInstance(context)
val appWidgetIds = appWidgetManager.getAppWidgetIds(ComponentName(context, SingleCounterWidget::class.java))
onUpdate(context, appWidgetManager, appWidgetIds)
}
}
companion object {
@RequiresApi(Build.VERSION_CODES.O)
fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
val sharedPreferences = context.getSharedPreferences("MySharedPrefs", Context.MODE_PRIVATE)
val data = sharedPreferences.getString("appdata", "No data")
// val numVal = data + "2"
val views = RemoteViews(context.packageName, R.layout.single_counter_widget)
views.setTextViewText(R.id.single_counter_number, data)
val (day, monthName, dayOfWeekName) = getCurrentDateMonthAndDayName()
val currMonth = monthName.substring(0, 3)
val date = "$day"
val th = "th"
val currDate = date + th
val currentDateMonth = "$currDate $currMonth"
views.setTextViewText(R.id.current_week_names, dayOfWeekName.substring(0, 3))
views.setTextViewText(R.id.current_dates, currentDateMonth)
//Onclick event on widget
// val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://www.mytasker.com"))
// val pendingIntent = PendingIntent.getActivity(context, 0, intent,
// PendingIntent.FLAG_IMMUTABLE)
// views.setOnClickPendingIntent(R.id.increment_button, pendingIntent)
// increment
val intentInc = Intent(context, SingleCounterWidget::class.java)
intentInc.action = WIDGET_INC
intentInc.putExtra("appWidgetId", appWidgetId)
val pendingIntentInc = PendingIntent.getBroadcast(context, 0, intentInc, PendingIntent.FLAG_IMMUTABLE)
views.setOnClickPendingIntent(R.id.increment_button, pendingIntentInc)
// Decrement
val intentDec = Intent(context, SingleCounterWidget::class.java)
intentDec.action = WIDGET_DEC
intentInc.putExtra("appWidgetId", appWidgetId)
val pendingIntentDec = PendingIntent.getBroadcast(context, 0, intentDec, PendingIntent.FLAG_IMMUTABLE)
views.setOnClickPendingIntent(R.id.decrement_button, pendingIntentDec)
//Exercise
val intentExec = Intent(context, SingleCounterWidget::class.java)
intentExec.action = WIDGET_EXEC
intentExec.putExtra("appWidgetId", appWidgetId)
val pendingIntentExec = PendingIntent.getBroadcast(context, 0, intentExec, PendingIntent.FLAG_IMMUTABLE)
views.setOnClickPendingIntent(R.id.exec_button, pendingIntentExec)
// WIDGET_REF
val intentRef = Intent(context, SingleCounterWidget::class.java)
intentRef.action = WIDGET_REF
intentRef.putExtra("appWidgetId", appWidgetId)
val pendingIntentRef = PendingIntent.getBroadcast(context, 0, intentRef, PendingIntent.FLAG_IMMUTABLE)
views.setOnClickPendingIntent(R.id.ref_button, pendingIntentRef)
appWidgetManager.updateAppWidget(appWidgetId, views)
}
@RequiresApi(Build.VERSION_CODES.O)
fun updateWidgetAfterClick(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
val views = RemoteViews(context.packageName, R.layout.single_counter_widget)
views.setTextViewText(R.id.single_counter_number, "ACS")
appWidgetManager.updateAppWidget(appWidgetId, views)
}
@RequiresApi(Build.VERSION_CODES.O)
fun getCurrentDateMonthAndDayName(): Triple<Int, String, String> {
val currentDate = LocalDate.now()
val dayOfMonth = currentDate.dayOfMonth
val monthName = currentDate.month.getDisplayName(TextStyle.FULL, Locale.getDefault())
val dayOfWeekName = currentDate.dayOfWeek.getDisplayName(TextStyle.FULL, Locale.getDefault())
return Triple(dayOfMonth, monthName, dayOfWeekName)
}
}
}
MySharedPreferencesModule.kt file code:
package com.servingsizetdiet
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.util.Log
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.WritableMap
import com.facebook.react.modules.core.DeviceEventManagerModule
import org.json.JSONException
class MySharedPreferencesModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
private val sharedPreferences: SharedPreferences = reactContext.getSharedPreferences("MySharedPrefs", Context.MODE_PRIVATE)
override fun getName(): String {
return "MySharedPreferences"
}
@ReactMethod
fun saveData(key: String, value: String, promise: Promise) {
val editor = sharedPreferences.edit()
editor.putString(key, value)
editor.apply()
if (editor.commit()) {
// Broadcast the update
Log.d("SharedPreferencesModule", "Broadcast intent sending...")
val intent = Intent("android.appwidget.action.APPWIDGET_UPDATE")
reactApplicationContext.sendBroadcast(intent)
promise.resolve("Data saved successfully")
} else {
promise.reject("Error", "Failed to save data")
}
}
@ReactMethod
fun getData(key: String, promise: Promise) {
try {
val value = sharedPreferences.getString(key, null)
promise.resolve(value)
} catch (e: JSONException) {
promise.reject("JSON_ERROR", "Error processing JSON data", e)
}
}
fun onWidgetButtonClick() {
Log.d("MyNativeModule", "Clicked plus widget btn")
val value = sharedPreferences.getString("appdata", null)
// promise.resolve(value)
// val data = "Updated data" // Get your updated data here
// saveToSharedPreferences(data)
if (value != null) {
Log.d("MyNativeModule", "getting data on widget btn click: $value")
sendEvent(value)
}
// emitEventWhenReady(data)
}
private fun sendEvent(data: String) {
try {
Log.d("MyNativeModule", "sendEventToReactNative called with data: $data")
val reactContext = reactApplicationContext
// reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java).emit("WidgetButtonClick", data)
// reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java).emit("WidgetButtonClick", data)
// reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java).emit("WidgetButtonClick", data)
// reactContext.getJSModule(ReactContext.RCTDeviceEventEmitter::class.java).emit("WidgetButtonClick", data)
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java).emit("WidgetButtonClick", data)
// reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
// reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
Log.d("MyNativeModule", "Event emitted")
} catch (e: Exception) {
Log.e("MyNativeModule", "Error emitting event", e)
}
}
}
And this is my React Native Code file WeeklyCounter.jsx:
import { NativeEventEmitter, NativeModules } from 'react-native';
const { MyNativeModule } = NativeModules;
// const myNativeModuleEmitter = new NativeEventEmitter(MyNativeModule);
// myNativeModuleEmitter.addListener('MyEvent', (data) => {
// console.log('Received data from native module:', data);
// // Update your state or do something with the data
// });
const { MySharedPreferences } = NativeModules;
const saveData = async (key, value) => {
try {
const jsonString = JSON.stringify(value); // Convert the object to a JSON string
await MySharedPreferences.saveData(key, jsonString);
console.log('Data saved successfully');
} catch (e) {
console.error(e);
}
};
const getData = async (key) => {
try {
const jsonString = await MySharedPreferences.getData(key);
const value = JSON.parse(jsonString); // Convert the JSON string back to an object
console.log('Retrieved value:', value);
} catch (e) {
console.error(e);
}
};
useEffect(() => {
const currentDate = new Date();
const currentWeek = currentDate.getDay();
const currentCounterAccordToCurrentDate = currentWeek == 0 ? sunVal : currentWeek == 1 ? monVal : currentWeek == 2 ? tueVal : currentWeek == 3 ? wedVal : currentWeek == 4 ? thuVal : currentWeek == 5 ? friVal : currentWeek == 6 ? satVal : "";
saveData("appdata", currentCounterAccordToCurrentDate);
getData("appdata");
const eventEmitter = new NativeEventEmitter(MyNativeModule);
// let eventListener = eventEmitter.addListener('WidgetButtonClick', event => {
// // console.log(event) // "someValue"
// console.log('Received data from native module:', event);
// });
// Removes the listener once unmounted
// return () => {
// eventListener.remove();
// };
// const eventEmitter = new NativeEventEmitter(MyNativeModule);
eventEmitter.addListener('WidgetButtonClick', (data) => {
console.log('Received data from native module:', data);
// Handle the updated data here
});
// console.log('Event listener registered');
// // Clean up the subscription on unmount
// return () => {
// console.log('Event listener removed');
// subscription.remove();
// };
// DeviceEventEmitter.addListener("WidgetButtonClick", data => {
// console.log(data)
// })
}, [, monVal, tueVal, wedVal, thuVal, friVal, satVal, sunVal])
// more code
Upvotes: 1
Views: 60