FragmentFirstBinding Error with First Fragment XML Changes - android-studio

I'm in Bumblebee v.2021.1.1. I don't have any database elements in my project. I do have defaults in the first fragment:
import com.my.app.databinding.FragmentFirstBinding
in:
class FirstFragment : Fragment() {
private var _binding: FragmentFirstBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FragmentFirstBinding.inflate(inflater, container, false)
...
return binding.root
}
When I make changes to fragment_first.xml the FirstFragment.kt file blows up: In Android Studio the problems tab reads Unresolved reference: FragmentFirstBinding and Variable expected, each several times for each occurrence. I don't understand the Logcat much at all. The only way I've found to correct it is to remove the null safety (?) from:
private var _binding: FragmentFirstBinding? = null
and then to just add it (the question mark) back in.
Also, I've seen about making databinding true in the build.gradle file, but it was not the default when I chose the Basic Activity template when starting the project. Is it stable to add databinding = true to the build.gradle file?

Thank goodness! I believe the IDE and Kotlin code both work beautifully and I'm right. I have found the error is generated only if a fragment file and a related XML file are running at the same time.
For example: if I open FirstFragment.kt and leave it open and then open and edit fragment_first.xml then the .kt (Kotlin) file gets the error.
But I don't get the error if I don't have the fragment file open, and then change the XML and then open the fragment file for editing.
In other words, when I make changes to a related XML file and then open the related Kotlin file, it can analyze and adjust to the changes made to the XML file that it has to bind to.
In addition, in an attempt to be clear, it looks like having only one tab (one file) open in Android Studio may prevent this from happening.

Related

How can I know the retained class name or keyword when I use navigation framework in Android Studio?

The following code is from the project at https://github.com/mycwcgr/camera/tree/master/CameraXBasic
The project use the latest navigation framework, I find there are some retained class name such as CameraFragmentDirections, GalleryFragmentArgs.
The system have no prompt information for these class name, must I remember these keywords by myself?
Code
/** Method used to re-draw the camera UI controls, called every time configuration changes */
#SuppressLint("RestrictedApi")
private fun updateCameraUi() {
// Listener for button used to view last photo
controls.findViewById<ImageButton>(R.id.photo_view_button).setOnClickListener {
Navigation.findNavController(requireActivity(), R.id.fragment_container).navigate(
CameraFragmentDirections.actionCameraToGallery(outputDirectory.absolutePath))
}
}
/** Fragment used to present the user with a gallery of photos taken */
class GalleryFragment internal constructor() : Fragment() {
/** AndroidX navigation arguments */
private val args: GalleryFragmentArgs by navArgs()
}
No you do not need to remember these things by yourself, if you know of a trick.
For example, if you don't remember the "keyword" Directions, but you know you want to do something related to CameraFragment, you can start typing e.g. CameraFragm in Android Studio. It will then suggest CameraFragment and CameraFragmentDirections for you. That way you can find CameraFragmentDirections easily even though you did not remember the keyword Directions.
There are not that many keywords to worry about though. After working with the Navigation framework for a while, you will remember them all.
If you are curious, you can find the generated classes here after a build:
./app/build/generated/source/navigation-args/...
e.g. after a debug build:
./app/build/generated/source/navigation-args/debug/com/android/example/cameraxbasic/fragments/CameraFragmentDirections.java
If you are even more curious, the code that generates these classes is here:
https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-master-dev/navigation/navigation-safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/java/JavaNavWriter.kt
There you can for example find this code:
internal fun Destination.toClassName(): ClassName {
val destName = name ?: throw IllegalStateException("Destination with actions must have name")
return ClassName.get(destName.packageName(), "${destName.simpleName()}Directions")
}
which is the code that decides what name CameraFragmentDirections gets. (Note "${destName.simpleName()}Directions" at the end.)

How to edit a kotlin file containing compiled code

I have an aar package, I unzipped it, unzipped the classes.jar file as well, and now have a bunch of .kt and .class files a few of which I would like to edit. But all I see is class and method declaration with their body containing /* compiled code */. Where do I find the Kotlin code so I can edit it like we used to in Java class files?
Now this is my first time handling kotlin and frankly i don't even know the language. I am using android studio to open the files, and i know how to generate a read-only decompiled java version to understand the inner workings. That's how i figured out which file i need to edit.
I have also found some answers on stack that mention how converting kotlin to java and back to kotlin after editing is not a good idea, since the java file is not a perfect decompilation.
Here is the file I want to edit as it appears in AS:
// IntelliJ API Decompiler stub source generated from a class file
// Implementation of methods is not available
package ru.aviasales.screen.results.view
public final class ResultItemView public constructor(context: android.content.Context, attributeSet: android.util.AttributeSet) : ru.aviasales.ui.views.CardView {
private final val segmentViews: kotlin.collections.MutableList<ru.aviasales.screen.results.view.ResultSegmentItemView> /* compiled code */
public final fun onFavouritesButtonClicked(onClick: () -> kotlin.Unit): kotlin.Unit { /* compiled code */ }
protected open fun onFinishInflate(): kotlin.Unit { /* compiled code */ }
public final fun setData(viewModel: ru.aviasales.screen.results.viewmodel.ResultItem.TicketViewModel): kotlin.Unit { /* compiled code */ }
private final fun setUpAvailableSeatsCount(seatsCount: kotlin.Int, type: ru.aviasales.screen.results.viewmodel.ResultViewType): kotlin.Unit { /* compiled code */ }
private final fun setUpFavouritesButton(favoritesEnabled: kotlin.Boolean, addedToFavourites: kotlin.Boolean): kotlin.Unit { /* compiled code */ }
private final fun setUpPrice(price: kotlin.Long, passengersCount: kotlin.Int): kotlin.Unit { /* compiled code */ }
private final fun setUpSegments(segments: kotlin.collections.List<ru.aviasales.screen.results.viewmodel.SegmentViewModel>): kotlin.Unit { /* compiled code */ }
}
Is it even possible to edit these type of files ? if yes then Do i need a different editor or is there a different method to open such files ?
The simple answer after trying everything I could, is that you can't.
Luckily I was able to circumvent the issue, by creating a new activity. The aar package had its own MainActivity activity which was also kotlin class file. I decompiled the .class file, copy pasted the java code into my new activity and use then call the new activity from application file (since the MainActivity was being called automatically at start). I also faced the problem of some variables not initialising properly because of lateinit. I solved that by simply copying the variables through application from MainActivity using registerActivityLifecycleCallback and then calling my activity.

Suppress warning “Access to field exceeds its access rights” in Groovy

I write a Groovy script and I need to access a field that has a private access modifier. This works fine but generates a warning:
Access to <field_name> exceeds its access rights
I want to supress this warning. What value of #SuppressWarnings annotation do I have to use in order to achieve it?
I've tried #SuppressWarnings("all") and it works fine but I would like to have more granular control over suppressions. I've also tried #SuppressWarnings("AccessingNonPublicFieldOfAnotherObject") but it has no effect.
Below how this warning looks in IntelliJ:
Unfortunately automatic hint doesn't suggest any sensible solution:
If you are talking about IntelliJ warning:
then you can hit Alt+Enter on the offender and choose "Suppress for method" as follows:
after which you will see #SuppressWarnings("GroovyAccessibility") over your test method:
I had this "problem" when I had buildSrc folder in Gradle-project which contained Kotlin code for my Gradle build scripts and it was used in Groovy code.
Seems like it was because I was accessing private variable field and not the getter. Kotlin makes field private by default. I solved this by using #JvmField in Kotlin code which makes the variable field public and does not generate getter for that field.
// groovy in gradle build script
compileOptions {
sourceCompatibility(CompileOptions.javaVersion)
}
// kotlin in buildSrc (this gives the warning)
object CompileOptions {
val javaVersion = JavaVersion.VERSION_11
}
// kotlin in buildSrc (this does not give the warning as field is now public)
object CompileOptions {
#JvmField val javaVersion = JavaVersion.VERSION_11
}

Android Studio nullability annoying warning

The problem:
#Nullable
private View view;
public doSomethingWithView() {
checkNotNull(view); //<- this throws NPE if parameter is null
view.showWarningAboutIssue(); //<- IDE reports about possible null here
}
Is there a way to configure the IDE, so that it doesn't report for a possible NPE on the second line?
UPDATE:
I'm using Dagger checkNotNull method which is identical to Guava ones. If I change import from Dagger to Guava my IDE removes the warning.
UPDATE #2
With latest update of Android studio I can not reproduce it anymore
You need to add the following comment before view.showWarningAboutIssue() statement:
//noinspection ConstantConditions
This can also be performed by the GUI : Alt+Enter (or "bubblelight" menu), then choose Assert view!=null and then Suppress for statement:

How to create a ReSharper 8.X Custom Macro that can fetch and process the containing type name

ReSharper 8.X ships with a macro that fetches the "Containing Type Name", but what I want to do is manipulate that name. I'm using this in a Visual Studio 2013 Web API project, and I want a template that takes the class name and builds the URL that has to be called. So, for example, suppose I have this:
public class AnnouncementController : ApiController
{
//Want to put a template here!
[HttpGet]
public HttpResponseMessage GetActiveAnnouncements()
{
/// ...
}
}
now my ReSharper template will look something like this:
/// This sample shows how to call the <see cref="$METHOD$"/> method of controller $CLASS$ using the Web API.
/// https://myurl.mydomain.com/api/$CONTROLLER$/$METHOD$
$Controller$, by convention, is the class name minus the letters 'Controller'. This is because ASP.NET MVC Web API projects expect classes derived from ApiController to end with the string 'Controller',
Since this class is AnnouncementController, the template should output
https://myurl.mydomain.com/api/Announcement/GetActiveAnnouncements
Resharper's Built-In Macros can give me some of what I need, but I want to write a custom macro that fetches the containing type name and chops "Controller" off of it. I would like to do that directly, without storing the containing type name in another parameter.
Also, how do I install this custom macro? I've Googled around, and all I found was a lot of dead links and old walkthroughs written for ReSharper version 7 and below that do NOT work with ReSharper 8.x
After a lot of fighting, here is my solution.
[MacroImplementation(Definition = typeof (ControllerNameMacroDefinition))]
public class ControllerNameMacroImplementation : SimpleMacroImplementation
{
public ControllerNameMacroImplementation([Optional] IReadOnlyCollection<IMacroParameterValueNew> arguments)
{
}
public override HotspotItems GetLookupItems(IHotspotContext context)
{
var ret = "CONTROLLER";
var fileName = GetFileName(context);
if (!fileName.IsNullOrEmpty())
{
//Replace "Controller.cs" in two separate steps in case the extension is absent
ret = fileName.Replace("Controller", "").Replace(".cs", "");
}
return MacroUtil.SimpleEvaluateResult(ret);
}
/// <summary>
/// Returns the filename of the current hotspot context
/// </summary>
private string GetFileName(IHotspotContext context)
{
var psiSourceFile = context.ExpressionRange.Document.GetPsiSourceFile(context.SessionContext.Solution);
return psiSourceFile == null ? string.Empty : psiSourceFile.Name;
}
}
I wanted to do exactly this, but for JavaScript Jasmine tests -- SomethingViewModel.js, with a fixture of SomethingViewModelFixture.js, but wanted to be able to refer to SomethingViewModel in the file. A few slight modifications to the above made it possible.
Unfortunately, there's a ton more things you need to do in order to get your plugin to actually install. Here's a list. I hope it's comprehensive.
NuGet package install JetBrains.ReSharper.SDK, make sure you have the correct version installed!
Copy your Class Library DLL to C:\Users\<you>\AppData\Local\JetBrains\ReSharper\<version>\plugins\<your plugin name>, creating the plugins directory if needed.
You need the plugin Annotations in your AssemblyInfo.cs file:
[assembly: PluginTitle("Your extensions for ReSharper")]
[assembly: PluginDescription("Some description")] -- this is displayed in ReSharper->Options->Plugins
[assembly: PluginVendor("You")]
You need a class in your project that defines the MacroDefinition, as well as the above MacroImplementation
[MacroDefinition("MyNamespace.MyClassName", ShortDescription = "A short description of what it does.", LongDescription = "A long description of what it does.")]
"ShortDescription" - this is displayed in the "Choose Macro" dialog list.
"LongDescription" you'd think this would be in the "Choose Macro" description, but it isn't.
I just added this annotation to the above file.
The file you add the MacroDefinition to needs to implement IMacroDefinition, which has a method (GetPlaceholder) and a property (Parameters) on it. The former can return any string ("a") and the latter can return an empty array.
You can ignore the WiX/NuGet stuff if you want. Just for a local install.
In VS, the ReSharper->Options->Plugins section has some troubleshooting details on why your plugin might not be loading.
Good luck!

Resources