I want to cast an Android X fragment (androidx.fragment.app.Fragment) to an Android native fragment (android.app.Fragment), because a library I am using does not support Android X fragments yet.
How can I achieve this?
I have already tried casting the Android X fragment to an Android native fragment, which causes a ClassCastException.
This is the code I'm currently using inside the Android X fragment. The function requires an Android native fragment. It throws a ClassCastException.
IntentIntegrator.forFragment(this as android.app.Fragment).initiateScan();
How can I achieve this?
You can't. While those classes fill the same role, they are unrelated from a Java standpoint.
We're having a hard time taking the first step in using a native library in NativeScript.
It's a Map library so I assume it has something to do with registering a new custom UI, but what gets me is the weird xml syntax.
The follow screenshots are from this page : https://developers.arcgis.com/android/latest/guide/develop-your-first-map-app.htm
Native instructions are for Android Studio :
The dependencies (Gradle) :
It also has a weird dependency for Java 8 features :
And lastly, the basic usage, which seems to require lots of platform specific native events :
For now we're only interested in an Android Proof of Concept, but eventually make and release a multi-platform plugin.
I know it's a lot of instructions and things asked for just one question, but here are our main confusions :
1) How to add the custom element to a NativeScript xml? Do we just set up the gradle imports and just add the following element directly? Also i'm assuming the android:id is unnecessary and we can just use id
<com.esri.arcgisruntime.mapping.view.MapView
android:id="#+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</com.esri.arcgisruntime.mapping.view.MapView>
2) How to access the above element by its ID via Javascript? More specifically how to get it using VUE? Native Example :
import com.esri.arcgisruntime.mapping.view.MapView;
MapView = findViewById(R.id.mapView);
ArcGISMap map = new ArcGISMap(Basemap.Type.TOPOGRAPHIC, 34.056295, -117.195800, 16);
mMapView.setMap(map);
3) Are there any other steps we need to take into consideration? Specially considering we intend into making this into a full plugin eventually. Or is this more straightforward/simple than I'm making it?
Ignore the XML example from the SDK docs, that is specific to Android's XML markup.
You have to create a new class (let's call it MapView), extending the base class View (from tns-core-modules/ui/core/view), in the createNativeView callback return instance of com.esri.arcgisruntime.mapping.view.MapView. That's should be it, now you can register the MapView class and use it in your Vue template.
Useful docs:
Building Plugins
Marshalling Java to JS
I'm not sure SO is the right place to ask this question so let me know if I should maybe post it on ProgrammersSE.
I've got an Android library project which comes with some functionality and some basic XML files. In the nearest future I'll be developing multiple apps which will heavily depend on that library - it's possible that some of them will only differ in that they'll be using different XML layout files and image resources. As far as I know Android will automatically pick the ones from the regular projects instead of the library one if the names of the appropriate files are the same so this shouldn't be a problem.
The problem is I expect that some of the projects will have to have a slightly extended functionality - meaning I'd have to, e.g., extend the classes which are in the library project.
I just tried that out but obviously that didn't work as I wasn't overriding the entire code of a class - just adding to it, meaning I seemingly can't have the the library Activities call the classes from my regular project.
Is there any way around that without using reflection?
Is there maybe a better way of handling such a situation?
Edit for clarification:
Thanks to #jucas and #Alex Cohn for the answers and the links. I'm not sure if the solutions you wrote are applicable to my situation - I'd probably have to see examples of those coded to decide if I can do anything similar in my project.
Here's an example of what makes this problematic for me: say in my library project I've got a class called MyActivity which extends Activity and implements OnScrollChangedListener because there's a ScrollView in it whose background has to scale. There could be something like this in it:
#Override
public void onScrollChanged() {
int currentScrollOffsetY = this.scrollView.getScrollY();
// No case for further back than the bottom of the screen (lower than 0)
// and if it's higher than where it should stop, keep it at that point
if (currentScrollOffsetY > this.screenHeightPx * MULTIPLIER_Y_ANIMATION_STOP) {
currentScrollOffsetY = (int) (this.screenHeightPx * MULTIPLIER_Y_ANIMATION_STOP);
}
// Set the pivot points of the background images
this.imageBackground.setPivotX(this.imageBackground.getWidth() / 2.0f);
this.imageBackground.setPivotY(0);
// Scale the background
float newBackgroundScale = 1 - (float) currentScrollOffsetY / (float) this.screenHeightPx;
if (newBackgroundScale < 0.75f) {
newBackgroundScale = 0.75f;
}
this.imageBackground.setScaleX(newBackgroundScale);
this.imageBackground.setScaleY(newBackgroundScale);
}
As you can see, the new scale for the background image is never smaller than 0.75 of the original size. Now if one of the projects using the library project needed that to be 0.8 instead, I could just move the value from the code to the XML values resources and it should be dynamically read from there - that's perfectly fine.
But what if I not only wanted to do that but also scale another ImageView?
this.imageBackground.setScaleX(newBackgroundScale);
this.imageBackground.setScaleY(newBackgroundScale);
this.differentImageBackground.setScaleX(newBackgroundScale);
this.differentImageBackground.setScaleY(newBackgroundScale);
How could this be achieved? I'm sorry if I don't understand this straight away - I've never done anything like this yet and some concepts are a bit difficult for me to get my head around them.
This a very common problem, and one that has several answers that might or might not be the best for your particular case, here are 2 from the top of my mind:
Develop a plugin architecture for your app, to load content and functionality from plugins Plugins architecture for an Android app?, note that this might be overkill if you just need to change a few classes here and there.
Modify your library project's architecture: This is one that I tend to use the most, just because it is simply and doesn't require a very complex refactoring. The steps needed for this are usually like this:
a. Figure out which parts of your activity or fragment might need to be extended by your main app project
b. Create interfaces and classes that implement those interfaces for the extendable functionality
c. This is the tricky part, isolate the creation and use of those classes in specific methods inside your activities or fragments
d. Finally on your main app project, create new classes that implement the same interfaces and override your fragments or activites to create these classes instead
I hope this helps you a bit, and if it doesn't you might want to sketch out some code in order to see exactly what problems you are having
This looks like a good fit for "inversion of control" design pattern. If a ExtendsActivity class is not changed between projects, but sometimes it uses an actor of class MyActor and sometimes ExtendsMyActor, then you should prepare a way for ExtendsActivity to accept the reference to such actor. You can inject this reference on construction, or later during the lifecycle of activity.
It is often recommended to use interface, i.e. define IActor and have both MyActor and any alternative implements this interface. But in some cases, extends fits perfectly, too.
I want to change icon of button thats in actioncontent of ViewNavigatorApplication from a view.
ViewNavigatorApplication loads views which are mxml components. i tried
Object(navigator.activeView).refreshbutton.icon = "../assets/r.gif";
It throws runtime error saying it couldn't find element.
Assuming your button is called refreshbutton and your app is called MyApp
MyApp(FlexGlobals.topLevelApplication).refreshbutton.icon="../assets/r.gif";
It's important to understand that your casting the top level application as your own app so it knows about the contents of your main level app including actionContent.
This isn't a very good development practice in general. I prefer to use a MVC pattern but that would be a very long answer.
I'm looking to write preferences that can be applied to both 3.0 and pre-3.0 devices. Discovering that PreferenceActivity contains deprecated methods (although these are used in the accompanying sample code), I looked at PreferenceFragement and the compatibility package to solve my woes.
It appears, though, that PreferenceFragment isn't in the compatibility package. Can anyone tell me whether this was intentional? If so, can I easily target a range of devices (i.e. < 3.0 and >=3.0) or will I have to jump through hoops? If it wasn't intentionally excluded, can we expect a new release of the compatibility package? Or is there another workaround that is safe to use?
Discovering that PreferenceActivity contains deprecated methods (although these are used in the accompanying sample code)
The deprecated methods are deprecated as of Android 3.0. They are perfectly fine on all versions of Android, but the direction is to use PreferenceFragment on Android 3.0 and higher.
Can anyone tell me whether this was intentional?
My guess is it's a question of engineering time, but that's just a guess.
If so, can I easily target a range of devices (i.e. < 3.0 and >=3.0) or will I have to jump through hoops?
I consider it to be done "easily". Have two separate PreferenceActivity implementations, one using preference headers and PreferenceFragments, the other using the original approach. Choose the right one at the point you need to (e.g., when the user clicks on the options menu item). Here is a sample project demonstrating this. Or, have a single PreferenceActivity that handles both cases, as in this sample project.
If it wasn't intentionally excluded, can we expect a new release of the compatibility package?
You will find out when the rest of us find out, which is to say, if and when it ships.
Or is there another workaround that is safe to use?
See above.
The subtle implication of the answer from #CommonsWare is that - your app must choose between the compatibility API or the built-in fragment API (since SDK 11 or so). In fact that's what the "easily" recommendation has done. In other words, if you want to use PreferenceFragment your app needs to use the built-in fragment API and deal with the deprecated methods on PreferenceActivity. Conversely, if it's important that your app use the compat. API you will be faced with not having a PreferenceFragment class at all. Thus, targeting devices is not a problem, but the hoop-jumping happens when you have to choose one or the other API and thus submit your design to unforeseen workarounds. I need the compat. API so I'm going to create my own PreferenceFragment class and see how that works. In the worst case scenario I'll just create a normal (fragment) layout and bind the view components to the sharedprefs manually...ugh.
EDIT:
After trying and looking at the code at http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/preference/PreferenceFragment.java?av=h -- creating my own PreferenceFragment isn't going to happen. It appears the liberal use of package-private in PreferenceManager instead of 'protected' is the main blocker. It really doesn't look like there's any security or really good motivation to have done that and it isn't great for unit-testing but oh well...less typing I guess...
EDIT v2:
Actually it did happen and it worked. It was definitely a headache to make the code work with the Compatibility API JAR. I had to copy about 70% the com.android.preference package from the SDK to my app and then wrestle with typically mediocre-quality Java code in Android. I used v14 of the SDK. It would have been much easier for a Goog engineer to do what I did, contrary to what I've heard some lead Android engineers say about this topic.
BTW - did I say "targeting devices is not a problem"? It totally is...if you use com.android.preference you are not going to be able to swap out with the Compatibility API without major refactoring. Fun log!
Building upon CommonsWare's answer as well as Tenacious' observations, I have come up with a single descendant class solution capable of targeting all current Android API versions with minimal fuss and no code or resource duplication. Please see my answer to the related question over here:
PreferenceActivity Android 4.0 and earlier
or on my blog:
http://www.blackmoonit.com/2012/07/all_api_prefsactivity/
Tested on two tablets running 4.0.3 and 4.0.4 as well as a phone running 4.0.4 and 2.3.3 and also an emulator running 1.6.
See PreferenceFragment-Compat from Machinarius. It was easy to drop in with gradle and I forget that it's even there.
compile 'com.github.machinarius:preferencefragment:0.1.1'
Important Update: The latest revision of the v7 support library now has a native PreferenceFragmentCompat.
On August 2015 Google released the new Preference Support Library v7.
Now you can use the PreferenceFragmentCompat with any Activity or AppCompatActivity
public static class PrefsFragment extends PreferenceFragmentCompat {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
}
}
You have to set preferenceTheme in your theme:
<style name="AppTheme" parent="#style/Theme.AppCompat.Light">
...
<item name="preferenceTheme">#style/PreferenceThemeOverlay</item>
</style>
In this way you can customize the preferenceTheme to style the layouts used for each preference type without affecting other parts of your Activity.
Tenacious's answer is correct, but here are some more details.
The reason you can't "create a normal layout and bind the view components to the sharedprefs manually" is that there are some surprising omissions in the android.preferences API. PreferenceActivity and PreferenceFragment both have access to critical non-public PreferenceManager methods, without which you can't implement a preference UI of your own.
In particular, to construct a Preference hierarchy from an XML file you need to use a PreferenceManager, but all of PreferenceManager's constructors are either package-private or hidden. The method of attaching the Preference onClick listeners to your activity is also package-private.
And you can't work around this by sneakily putting your implementation in the android.preferences package, because non-public methods in Android APIs are actually omitted from the SDK. With a bit of creativity involving reflection and dynamic proxies, you can still get at them. The only alternative, as Tenacious says, is to fork the entire android.preference package, including at least 15 classes, 5 layouts, and a similar number of style.xml and attrs.xml elements.
So to answer the original question, the reason Google didn't include PreferenceFragment in the compatibility package is that they would have had exactly the same difficulty as Tenacious and myself. Even Google can't go back in time and make those methods public in the old platforms (though I hope they do that in future releases).
My app target is API +14 but due to using support library for some fancy navigation, I couldn't use the android.app.Fragment and had to use android.support.v4.app.Fragment, but I also needed to have PreferenceFragment in place without large changes to code behind.
So my easy fix for having both worlds of support library and PreferenceFragment:
private android.support.v4.app.Fragment fragment;
private android.app.Fragment nativeFragment = null;
private void selectItem(int position) {
fragment = null;
boolean useNativeFragment = false;
switch (position) {
case 0:
fragment = new SampleSupprtFragment1();
break;
case 1:
fragment = new SampleSupprtFragment2();
break;
case 2:
nativeFragment = new SettingsFragment();
useNativeFragment = true;
break;
}
if (useNativeFragment) {
android.app.FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.content_frame, nativeFragment).commit();
} else {
if (nativeFragment != null) {
getFragmentManager().beginTransaction().remove(nativeFragment)
.commit();
nativeFragment = null;
}
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragment).commit();
}
}
I needed integrate Preferences into application's design and keep support for 2.3 android. So I still needed PreferencesFragment.
After some search I found android-support-v4-preferencefragment lib. This lib save a lot of time for copying and refactoring original PreferencesFragment as Tenacious said. Works fine and users enjoy preferences.