I am trying to build a lazy loaded list that shows a set of adaptive cards using adaptive cards android build 2.7.0. I was able to get the first set of data successfully parsed and rendered. But when the second set of data is fetched from the backend, the deserializer complains by throwing the following error.
JNI DETECTED ERROR IN APPLICATION: JNI FindClass called with pending exception java.lang.NullPointerException: null upcall object in AdaptiveCards::BaseCardElementParser::Deserialize
java_vm_ext.cc:577] at long io.adaptivecards.objectmodel.AdaptiveCardObjectModelJNI.AdaptiveCard_DeserializeFromString__SWIG_0(java.lang.String, java.lang.String, long, io.adaptivecards.objectmodel.ParseContext) (AdaptiveCardObjectModelJNI.java:-2)
java_vm_ext.cc:577] at io.adaptivecards.objectmodel.ParseResult io.adaptivecards.objectmodel.AdaptiveCard.DeserializeFromString(java.lang.String, java.lang.String, io.adaptivecards.objectmodel.ParseContext) (AdaptiveCard.java:211)
java_vm_ext.cc:577] at io.adaptivecards.objectmodel.ParseResult com.mrg.cardfeed.PSCardLoader.deserialize(java.lang.String)
error is thrown at the following call
ParseResult parseResult = AdaptiveCard.DeserializeFromString(card, AdaptiveCardRenderer.VERSION, context);
// the simplified version of the method I use to render a card
public void renderCardView(CardDO cardDO) {
try {
RawDO rawcard = cardDO.getRowData();
String card = rawcard.raw_json;
ParseResult parseResult = AdaptiveCard.DeserializeFromString(card, AdaptiveCardRenderer.VERSION, context);
JsonObject jsonObject = JsonParser.parseString(additionalData).getAsJsonObject(); // other data
RenderedAdaptiveCard renderedCard = AdaptiveCardRenderer.getInstance().render(activity, ((FragmentActivity) activity).getSupportFragmentManager(), parseResult.GetAdaptiveCard(), (ICardActionHandler) activity, PSHostConfig.psconfig.current);
for (AdaptiveWarning warning : renderedCard.getWarnings()) {
System.out.println(warning.getMessage());
}
View rendered = renderedCard.getView();
rendered.canScrollVertically(1);
String additionalData = parseResult.GetAdaptiveCard().GetAdditionalProperties().getString(); // for other data
// Present the view
} catch (Exception e) {
System.out.println(e);
}
}
I am using an async task to fetch the data, parse and render the cards. So I assume the problem has something to do with thread safety. Has anyone run in to this problem with adaptive cards android.
Please let me know if I am making a rookie mistake as I am very new to adaptive cards.
Any help is highly appreciated.
The mistake I had made was calling AdaptiveCard.DeserializeFromString() in a seperate thread. Once I moved the deserializing and rendering of the adaptivecard to the main thread, the problem was solved.
Related
I'm creating a media player in JavaFX. In one of my methods, I've created a way to search for metadata in a Media-file and then display it in ImageView. Works fine first time, but as soon as I want to call it again using another Media object, the image doesn't show up. I'm a bit confused and inexperienced, but I think that perhaps I need to reset/stop the listener before going to next object in line?
So my question is! How do you remove the listener when "image" has been found, what do you type to make it happen?
If you think that there's another reason why my image wont display the second time, please let me know as well.
Thanks on purpose.
private void displayAlbumCover (){
// Will start to show a blank CD
File file = new File("src/sample/images/blank_cd.jpeg");
Image image = new Image(file.toURI().toString());
albumCoverView.setImage(image);
// However if an album cover is found in the meta-data it will be displayed
ObservableMap<String,Object> meta_data=me.getMetadata();
meta_data.addListener((MapChangeListener<String, Object>) ch -> {
if(ch.wasAdded()){
String key=ch.getKey();
Object value=ch.getValueAdded();
switch(key){
case "image":
albumCoverView.setImage((Image)value);
break;
}
}
});
}
ObservableMap has removeListner method. You can keep the listener instance to variable and then remove it later.
private MapChangeListener<String, Object> listener;
private void displayAlbumCover (){
// ...
this.listener = //...
meta_data.addListener(listener);
}
private void removeListener() {
me.getMetadata().removeListener(this.listener);
}
https://docs.oracle.com/javase/8/javafx/api/javafx/collections/ObservableMap.html#removeListener-javafx.collections.MapChangeListener-
I´m looking for a way to get the messages from WhatsApp notifications when there is more than one line.
I´m trying to get the value from a private variable inside an inner class via Reflection in Android. I´m trying to get the 'mTexts' ArrayList of charsequence used to build an InboxStyle Notification. I´m looking for the messages from whatsapp since the last whats update there is no EXTRA on Notifications listened by notificationListener() that have the multiple lines notification (I can only get the first line).
Any way to get the lines is worth it.
This is my code.
#Override
public void onNotificationPosted(StatusBarNotification sbn) {
super.onNotificationPosted(sbn);
Class[] declaredClasses = sbn.getNotification().getClass().getClasses();
for (Class c : declaredClasses){
if(c.getName().contains("Notification$InboxStyle")){
Class inboxStyleClass = c.getClass();
Field[] fields = inboxStyleClass.getDeclaredFields();
for(Field field : fields){
if(field.getName().contains("mText")){
Field fmText = null;
try {
fmText = inboxStyleClass.getDeclaredField("mTexts");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
ArrayList<CharSequence> mTextsArrayList = null;
fmText.setAccessible(true);
try{
mTextsArrayList = (ArrayList<CharSequence>) fmText.get(**WICH OBJECT MAY USE HERE**);
}catch(IllegalAccessException e){
e.printStackTrace();
}
for(CharSequence value : mTextsArrayList){
Log.i("XXX","Results are: "+value.toString());
}
}
}
}
}
}
I reach the mText field correctly but I can´t get the value from it.
I tried to use a new Notification.InboxStyle() object
Notification.InboxStyle iStyleObjectToGetTheValue = new Notification.InboxStyle();
to see if it works well, and it does
inboxStyle = (ArrayList<CharSequence>) fmText.get(iStyleObjectToGetTheValue);
but I need the values from the notification. Any idea on how can I achieve that?
I also tried to get the message lines inflating the RemoteViews that you can retrieve by StatusBarNotification.getNotification().THE_REMOTE_VIEW because using DeviceMonitor you can take an screenshoot of the device and see the IDs of the views... but had no lucky with that.
Any way to get the lines is worth it.
All the help is welcomed!!
Thanks!!
According to the docs for RemoteView.apply():
View apply(Context context, ViewGroup parent) - Inflates the view hierarchy represented by this object and applies all of the actions.
You can create a parent and provide the context to RemoteView.apply(). Inspect the resulting View to find the text:
#Nullable
public View getBigContentView (StatusBarNotification statusBarNotification) {
RemoteViews bigContentView = statusBarNotification.getNotification().bigContentView;
return bigContentView != null ? bigContentView.apply(ctx, null) : null;
}
This might not work in Nougat phones, as according to the documentation (reading this more carefully tells me that Google probably did not mean for you to read this parameter and that it should only be used when building the notification):
* As of N, this field may be null. The expanded notification view is determined by the
* inputs to {#link Notification.Builder}; a custom RemoteViews can optionally be
* supplied with {#link Notification.Builder#setCustomBigContentView(RemoteViews)}.
Intro to me and my application school project
Hi,
iam pretty new with android and for some school project iam building an application where users can configure regions to recieve alerts from. The app need also make it posible to recieve alerts around the current location of the app user.
The app gets its info from a xml feed and sorts the data by the configured regions. The workflow is 1. to get the alerts which are in the configured regions. 2. When gps alerts are enabled the app need to get the location and when it is known it needs to do the first step again but this time the gps region is included. (i need to optimize this proces LATER)
(questions bellow)
intro to my app and problem
I'm using a asynctask in my application to download some xml feed. When the asynctask is ready i need to call 3 places for do something with the result.
1 class saves the result in the local database (alertmanager)
2 fragments (in a tabview) needs to show the results (1 in a map an one in a listview)
Now i use weakreferences for giving the call back "references" to the asynctask. in the onPostExecute() i use theWeakReference.get().updateMethod(result); for updating the class/fragments.
The alertmanager (the class who needs to recieve the updates) also calls a gps manager in the same method where it calls the asynctask to get the gps location. When i comment out (in my case with a if) the line what calls the gps manager the weak reference of the alertmanager will go to null in the asynctask between the constructor (all references are filled) and the doInBackground (the alertmanager reference is null, the other 2 still filled) which results in a crashing app.
When i dont comment out the if the app works fine.....
Alertmanager information
This is the method in the alertmanager who calls the async task. The references are filled on this place.
public void GetAlerts(List<WeakReference<e_Alerts>> callbackReferences, Context context) {
//Update the alerts in the listview and mapview with the local alerts.
List<Alert> localAlerts = internalDc.GetAllAlerts();
try {
for (WeakReference<e_Alerts> callback : callbackReferences) {
callback.get().UpdateAlerts(localAlerts);
}
} catch (Exception e) {
Log.e("AlertManager", e.getMessage());
}
//If connected to the internet then update the local db and the views
if (isConnectingToInternet(context)) {
WeakReference<e_Alerts> wr = new WeakReference<e_Alerts>(this);
callbackReferences.add(wr);
// Update the alerts where no location is needed for so the user has a quick result
externalDc.getAlerts(callbackReferences, areaManager.GetActiveAreas(false));
// If gps region is enabled then find the phones location and update the alerts
if (areaManager.GetGpsArea().IsActive()) {
new GpsManager(this.context, this, callbackReferences);
}
}
}
The GpsManager extends the LocationListener:
public class GpsManager extends Service implements LocationListener {
The listener is implemented by the Alertmanager
// This method is caled by the GPS Manager when the GPS location is changed
#Override
public void OnLocationChanged(Location location, List<WeakReference<e_Alerts>> references) {Area gpsArea = areaManager.GetGpsArea();
gpsArea.SetLocation(location);
areaManager.SaveArea(gpsArea);
externalDc.getAlerts(references, areaManager.GetActiveAreas(true));
}
Asynctask information
This are the asynctask methods:
Asynctask constructor:
Here the list callbackReferences contains 3 weakrefrences and all of them are filled (2x fragment reference 1x alertmanager reference)
public At_allAlerts(List<WeakReference<e_Alerts>> callbackReferences, List<Area> areas) {
this.mCallbackReferences = callbackReferences;
this.mAreas = areas;
}
doInBackground code:
The XmlDownloader: Downloads an xml feed an parses the xml to objects with a library
The AlertConverter: converts the xml object to the object i use in my app
Both classes can work without the asynctask class and don't use the references.
#Override
protected String doInBackground(String... inputUrl) {
Log.i("At_allAlerts", "Asynctask for downloading and parsing mAlerts is started");
try {
//Downloads the alert XMLs from the internet and parses it to xmlAlerts
this.mAlerts = new XmlDownloader().DownloadAlerts(inputUrl);
// Filters the mXml mAlerts so only the mAlerts where the enduser is interessed in will remain
this.mAlerts = filterAlerts(this.mAlerts);
// Converts the remaining xmlAlerts to Alerts;
this.mResult = new AlertConverter().Convert(this.mAlerts);
}catch (Exception e) {
Log.e("At_allAlerts",e.getMessage());
}
return null;
}
The onPostExecute method:
When the programm comes in this method the this.references.get(2) reference (alertmanager reference) = null, the other 2 references are still filed
#Override
protected void onPostExecute(String xml){
for (WeakReference<e_Alerts> reference : activityWeakReferences)
{
reference.get().UpdateAlerts(this.result);
}
}
filterAlerts Method:
private List<Item> filterAlerts(List<Item> alerts) {
List<Item> filteredXmlAlerts = new ArrayList<>();
for (Item alert : alerts)
{
Location alertLocation = new Location("");
alertLocation.setLatitude(alert.getGeometries().get(0).getLocations().get(0).getLat());
alertLocation.setLongitude(alert.getGeometries().get(0).getLocations().get(0).getLng());
for(Area area : this.mAreas)
{
if (area.IsOrganization() && alert.getCountryCode().toLowerCase().equals(area.getOrganizationcode().toLowerCase())){
filteredXmlAlerts.add(alert);
break;
}
else if(!area.IsOrganization() && isAlertInRegion(alertLocation, area)) {
filteredXmlAlerts.add(alert);
break;
}
}
}
return filteredXmlAlerts;
}
My Question(s)
I think Weakreference are the right way for giving references to asynctask is this correct or do i need to give it as an other object? (class or object or whatever?).
Why goes my reference to null? and only one of the 3? and only when i dont use the gps location class? and how to solve this?
I read something about the garbage collector what can be the cause of this problem, is this true and when yes how can i solve this?
It would be fine when the answere are simple to understand since android is pretty new for me.
I got the task to migrate to wicket 1.4 to wicket 1.5. Despite lack of information in migration guide I was somehow able to refactor most issues. Unfortunetly I'm stuck with "resource" - atm I'm getting this error
java.lang.IllegalArgumentException: Argument 'resource' may not be null.
What I understand by that is that something was change and wicket can no longer "get" to my resources. So I used to have (in wicket 1.4) that piece of code that was responsible for creating image and passing it (the method is in class that extends WebPage) :
private void addImageLogo() {
Resource res = new Resource() {
#Override
public IResourceStream getResourceStream() {
String logo = ConfigurationManager.getInstance().getPathValue(ConfigurationManager.LOGO_FILE_PATH);
return new FileResourceStream(new File(logo));
};
Image logo = new Image("logo", res);
add(logo);
}
Now Resource class no longer exists or I can't find it. While searching internet I was able to change it into this
private void addImageLogo() {
String logoTxt = ConfigurationManager.getInstance().getPathValue(ConfigurationManager.LOGO_FILE_PATH);
ResourceReference res = new ResourceReference(logoTxt) {
#Override
public IResource getResource() {
return null;
}
};
Image logo = new Image("logo", res);
add(logo);
}
This is responsible for obtaining path (and its working): ConfigurationManager.getInstance().getPathValue(ConfigurationManager.LOGO_FILE_PATH)
Unfortunetly I'm still getting this error that I mentioned above. The method getResource() generated automaticly and I believe this is an issue because I'm retuning null but I have no idea what (or how) should I return.
Since it worked with a IResourceStream in 1.4.x then you can just use org.apache.wicket.request.resource.ResourceStreamResource as a IResource for the Image.
Your first code snippet is not complete so I cannot give you exact replacement code.
I am getting "Path requests must specify a user by using UserEnvironment" error by using
Environment.getExternalStorageDirectory().getPath()
I traced my code and I found that in java.io.Environment there is a function to produce this error :
private static void throwIfUserRequired() {
if (sUserRequired) {
Log.wtf(TAG, "Path requests must specify a user by using UserEnvironment",
new Throwable());
}
}
I searched in the web and found this solution from here
Environment.setUserRequired(false);
But this solution is not working for me because I cannot access to the "setUserRequired" method of Environment. I get compilation error. I searched this function in the Environment class and I found this :
/** {#hide} */
public static void setUserRequired(boolean userRequired) {
sUserRequired = userRequired;
}
Can anyone help me how can I access to my external storage of my phone? any solution ? it is emergency. Thanks a lot
You need to use UserEnvironment and get the path for this user.
int userId = UserHandle.myUserId();
sCurrentUser = new UserEnvironment(userId);
This code stolen from Environment.java and the code they use to initialize their internal user.
I could solve my problem by removing
Environment.getExternalStorageDirectory().getPath()
inside try-catch block and writing outside of the try-catch block,and it is working now.
Through the reflection to solve this problem
fun setUserRequired() {
var state = Environment.getExternalStorageDirectory()
if ("mounted".equals(state)) {
try {
var environmentcls = Class.forName("android.os.Environment");
var setUserRequiredM = environmentcls.getMethod("setUserRequired", Boolean::class.java);
setUserRequiredM.invoke(null, false);
} catch (e: Exception) {
e.printStackTrace()
}
}
}