Categories
discuss

LocalBroadcastManager has been deprecated. What I should use instead in its place?

I’m working on this project in Android in which an aspect requires a CountdownTimer with a foreground service. A few other answers on Stack Overflow mentioned that LocalBroadcastManager would be suitable for my needs.

The documentation in Android Developers, however, mentions that it has been deprecated. Any suggestions on what I should use in its place? The documentation mentioned about using LiveData, but I was wondering if there are any easier alternatives.

Answer

LocalBroadcastManager is basically an event bus with a lot of unnecessary ceremony around Intents and intent filters. So one replacement is easy, and functions quite similarly: you can use any event bus library. greenrobot’s EventBus is a popular choice (here’s a guide for it) and Guava also has one, if you’re already using Guava (but Guava is pretty heavy to include just for an event bus).

But event buses suffer from the same problems that LocalBroadcastManager does that led to it being deprecated: it’s global, it’s not lifecycle-aware, and as your app gets larger, it becomes much more difficult to reason about the effects of a change to an event. For cases of observing data, LiveData solves this quite nicely because it’s lifecycle-aware, so you won’t get change notifications at the wrong time (like before your View is set up, or after onSaveInstanceState) – but it’ll handle delivering the change notifications when you’re in the right state again. It’s also more tightly scoped – each piece of LiveData is accessed separately rather than having (typically) one event bus/LocalBroadcastManager for the entire app.

For cases where it’s more of an event rather than a piece of data being changed, you can sometimes convert it to a piece of data. Consider if you have “login” and “logout” events – you could instead create a LiveData that stores an Account for logged-in users, and becomes null when the user is logged out. Components could then observe that.

There are certainly cases where it really is difficult to convert it to a piece of observable data (though I can’t immediately think of any examples that would typically be used with an event bus patten). For those, consider writing your own listener interface, similar to how on-click listeners work.

For your example of a countdown timer, I think LiveData is a pretty straightforward solution, and will be much easier than an event bus or even LocalBroadcastManager would be. You can just have a LiveData of the timer’s current value, and subscribe to it from whatever needs to show the value.

Categories
discuss

Android Studio React Native Build fails

I took the project I am developing at my workplace home and wanted to run it here on my machine.

I got many many errors which I fixed, but there are some that I don’t know how. Maybe you guys know a fix.

androidappbuildintermediatesexternal_file_lib_dex_archivesdebugout

this output get generated when building the project from AS.

I read that the fix is to add this: android.enableBuildCache=false to gradle.properties but when I do that I get this error which make 0 sense tbh.

: Cannot parse project property android.enableBuildCache='false ' of type 'class java.lang.String' as boolean. Expected 'true' or 'false'.

EDIT: Ok there was an empty space after false hence the second error but even with that corrected I get the first error.

Running it from vsCode gives me: Execution failed for task ':app:processDebugResources'.

EDIT2: Newest Error in AS:

> Task :app:mergeExtDexDebug
java.nio.file.NoSuchFileException: C:UsersFadedDesktopDevelopmentReact NativeFitnessAppFitnessAppandroidappbuildintermediatesexternal_file_lib_dex_archivesdebugout
    at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:79)
    at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
    at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
    at sun.nio.fs.WindowsDirectoryStream.<init>(WindowsDirectoryStream.java:80)
    at sun.nio.fs.WindowsFileSystemProvider.newDirectoryStream(WindowsFileSystemProvider.java:522)
    at java.nio.file.Files.newDirectoryStream(Files.java:457)
    at java.nio.file.Files.list(Files.java:3451)
    at com.android.build.gradle.internal.tasks.DexMergingParams.getAllDexFiles(DexMergingTask.kt:502)
    at com.android.build.gradle.internal.tasks.DexMergingTaskRunnable.run(DexMergingTask.kt:423)
    at com.android.build.gradle.internal.tasks.Workers$ActionFacade.run(Workers.kt:335)
    at org.gradle.workers.internal.AdapterWorkAction.execute(AdapterWorkAction.java:50)
    at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:50)
    at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1$1.create(NoIsolationWorkerFactory.java:65)
    at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1$1.create(NoIsolationWorkerFactory.java:61)
    at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:98)
    at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.execute(NoIsolationWorkerFactory.java:61)
    at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
    at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:416)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:406)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:102)
    at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36)
    at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
    at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:53)
    at org.gradle.workers.internal.DefaultWorkerExecutor$3.call(DefaultWorkerExecutor.java:217)
    at org.gradle.workers.internal.DefaultWorkerExecutor$3.call(DefaultWorkerExecutor.java:212)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:215)
    at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
    at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:131)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
    at java.lang.Thread.run(Thread.java:748)


> Task :app:transformClassesWithDexBuilderForDebug
> Task :app:validateSigningDebug UP-TO-DATE
> Task :app:signingConfigWriterDebug
> Task :app:mergeDebugJavaResource
> Task :app:mergeExtDexDebug FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:mergeExtDexDebug'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
   > java.nio.file.NoSuchFileException: C:UsersFadedDesktopDevelopmentReact NativeFitnessAppFitnessAppandroidappbuildintermediatesexternal_file_lib_dex_archivesdebugout

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.0.1/userguide/command_line_interface.html#sec:command_line_warnings

BUILD FAILED in 19s
150 actionable tasks: 147 executed, 3 up-to-date

Answer

I have encountered a similar error before. As a result of my research as a solution

In the android/app/build.gradle file multiDexEnabled true

android {
    defaultConfig {
        ...
        targetSdkVersion 28
        multiDexEnabled true // here
    }
    ...
}
Categories
discuss

Material UI + React Form Hook + multiple checkboxes + default selected

I am trying to build a form that accommodates multiple ‘grouped’ checkboxes using react-form-hook Material UI.

The checkboxes are created async from an HTTP Request.

I want to provide an array of the objects IDs as the default values:

defaultValues: { boat_ids: trip?.boats.map(boat => boat.id.toString()) || [] }

Also, when I select or deselect a checkbox, I want to add/remove the ID of the object to the values of react-hook-form.

ie. (boat_ids: [25, 29, 4])

How can I achieve that?

Here is a sample that I am trying to reproduce the issue.

Bonus point, validation of minimum selected checkboxes using Yup

boat_ids: Yup.array() .min(2, "")

Answer

Breaking API changes made in 6.X:

  • validation option has been changed to use a resolver function wrapper and a different configuration property name
    Note: Docs were just fixed for validationResolver->resolver, and code examples for validation in repo haven’t been updated yet (still uses validationSchema for tests). It feels as if they aren’t sure what they want to do with the code there, and it is in a state of limbo. I would avoid their Controller entirely until it settles down, or use Controller as a thin wrapper for your own form Controller HOC, which appears to be the direction they want to go in.
    see official sandbox demo and the unexpected behavior of "false" value as a string of the Checkbox for reference
import { yupResolver } from "@hookform/resolvers";
  const { register, handleSubmit, control, getValues, setValue } = useForm({
    resolver: yupResolver(schema),
    defaultValues: Object.fromEntries(
      boats.map((boat, i) => [
        `boat_ids[${i}]`,
        preselectedBoats.some(p => p.id === boats[i].id)
      ])
    )
  });
  • Controller no longer handles Checkbox natively (type="checkbox"), or to better put it, handles values incorrectly. It does not detect boolean values for checkboxes, and tries to cast it to a string value. You have a few choices:
  1. Don’t use Controller. Use uncontrolled inputs
  2. Use the new render prop to use a custom render function for your Checkbox and add a setValue hook
  3. Use Controller like a form controller HOC and control all the inputs manually

Examples avoiding the use of Controller:
https://codesandbox.io/s/optimistic-paper-h39lq
https://codesandbox.io/s/silent-mountain-wdiov
Same as first original example but using yupResolver wrapper


Description for 5.X:

Here is a simplified example that doesn’t require Controller. Uncontrolled is the recommendation in the docs. It is still recommended that you give each input its own name and transform/filter on the data to remove unchecked values, such as with yup and validatorSchema in the latter example, but for the purpose of your example, using the same name causes the values to be added to an array that fits your requirements.
https://codesandbox.io/s/practical-dijkstra-f1yox

Anyways, the problem is that your defaultValues doesn’t match the structure of your checkboxes. It should be {[name]: boolean}, where names as generated is the literal string boat_ids[${boat.id}], until it passes through the uncontrolled form inputs which bunch up the values into one array. eg: form_input1[0] form_input1[1] emits form_input1 == [value1, value2]

https://codesandbox.io/s/determined-paper-qb0lf

Builds defaultValues: { "boat_ids[0]": false, "boat_ids[1]": true ... }
Controller expects boolean values for toggling checkbox values and as the default values it will feed to the checkboxes.

 const { register, handleSubmit, control, getValues, setValue } = useForm({
    validationSchema: schema,
    defaultValues: Object.fromEntries(
      preselectedBoats.map(boat => [`boat_ids[${boat.id}]`, true])
    )
  });

Schema used for the validationSchema, that verifies there are at least 2 chosen as well as transforms the data to the desired schema before sending it to onSubmit. It filters out false values, so you get an array of string ids:

  const schema = Yup.object().shape({
    boat_ids: Yup.array()
      .transform(function(o, obj) {
        return Object.keys(obj).filter(k => obj[k]);
      })
      .min(2, "")
  });
Categories
discuss

How do I Rotate, Translate, and Scale rectangle from a keyframe using popmotion pure?

How do I make the last keyframe rotate my rectangle to a 35deg angle using popmotion pure?

enter image description here https://codepen.io/matthewharwood/pen/XWmRPaK?editors=1111

HTML:

<div class="flex h-screen w-screen justify-center items-center">
  <div class="portal-b">
    <h1 class="left"></h1>
  </div>
</div>
<button class="trigger fixed z-10 left-0 top-0">
  B replace A
</button>

CSS:

.portal-b {
  background: blue;
  width: 1px;
  height: 100px;
}

JS

const { easing, keyframes, styler } = window.popmotion;
const trigger = document.querySelector('.trigger');
const [_, portalB] = [document.querySelector('.portal-a'), document.querySelector('.portal-b')];
trigger.addEventListener('click', () => {
  const portalS = styler(portalB);
  keyframes({
  values: [
    { translateX: 0, scaleX: 0, rotateZ: 0, transformOrigin: 'left center' },
    { translateX: 200, scaleX: 400, rotateZ: 0, transformOrigin: 'left center' },
    { translateX: 200, scaleX: 400,  rotateZ: 90,  transformOrigin: 'left center' },
  ],
  duration: 3000,
  easings: easing.easeInOut,
}).start(portalS.set)
})

Answer

For this kind of problem I recommend stepping through the values in plain CSS in your browser. I found that the following CSS rule provided the final state you wanted

.portal-b {
  background: blue;
  width: 1px;
  height: 100px;
  transform: translateX(200px) rotate(-35deg) scaleX(400);
}

Then all you need is for your keyframes to step their way there, stating explicitly the values they expect like so

  values: [
    { transform: "translateX(0px) rotate(0deg) scaleX(1)" },
    { transform: "translateX(200px) rotate(0deg) scaleX(400)" },
    { transform: "translateX(200px) rotate(-35deg) scaleX(400)"},
  ],

Here’s your pen with my changes: https://codepen.io/kcerb/pen/wvKyWLv?editors=1111

Categories
discuss

Check if array of objects contain certain key

I need to determine if a certain key exists in an array of objects.

Here is a sample array:

arrOfObj = [{
        "mainKey1": {
            "subKey1": {
                "innerKey1": {
                    "innerMostKey1": {
                        "key1": "value"
                    }
                }
            }
        }
    }, {
        "mainKey2": {
            "key2": "value"
        }
    }, {
        "mainKey3": {
            "subKey3": {
                "key3": "value"
            }
        }
    }
]

I was trying to do this but I get the wrong output:

const objKeys = Object.keys(arrOfObj)
console.log('objKeys = ' + JSON.stringify(arrOfObj))

Output is the index numbers:

objKeys = ["0", "1", "2"]

I want to have a function that works like this:

var isKeyPresent = checkKeyPresenceInArray('mainKey3')

Please note though that I only need to check the topmost level in the objects – in above example, these are the main keys (mainKey1, etc) and that their content is dynamic (some others have deeply nested object inside and some not so.

Help!

Answer

You can try using array.some():

let checkKeyPresenceInArray = key => arrOfObj.some(obj => Object.keys(obj).includes(key));

let arrOfObj = [{
        "mainKey1": {
            "subKey1": {
                "innerKey1": {
                    "innerMostKey1": {
                        "key1": "value"
                    }
                }
            }
        }
    }, {
        "mainKey2": {
            "key2": "value"
        }
    }, {
        "mainKey3": {
            "subKey3": {
                "key3": "value"
            }
        }
    }
]

let checkKeyPresenceInArray = key => arrOfObj.some(obj => Object.keys(obj).includes(key));


var isKeyPresent = checkKeyPresenceInArray('mainKey3')

console.log(isKeyPresent);
Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..