Convert Figma logo to code with AI

square logomortar

A simple library that makes it easy to pair thin views with dedicated controllers, isolated from most of the vagaries of the Activity life cycle.

2,157
156
2,157
33

Top Related Projects

17,430

A fast dependency injector for Android and Java.

8,925

Koin - a pragmatic lightweight dependency injection framework for Kotlin & Kotlin Multiplatform

7,751

Uber's cross-platform mobile architecture framework.

Mavericks: Android on Autopilot

A scope tree based Dependency Injection (DI) library for Java / Kotlin / Android.

Quick Overview

Mortar is an open-source framework for building and deploying machine learning pipelines. It provides a set of tools and abstractions to simplify the process of creating, testing, and deploying machine learning models, with a focus on reproducibility and scalability.

Pros

  • Simplifies the creation and management of machine learning pipelines
  • Promotes reproducibility and version control of ML experiments
  • Supports multiple cloud platforms for deployment
  • Integrates well with popular ML libraries and tools

Cons

  • Steeper learning curve for those new to ML pipeline concepts
  • Limited community support compared to some more established frameworks
  • May be overkill for simple ML projects or small teams
  • Documentation could be more comprehensive for advanced use cases

Code Examples

  1. Defining a feature:
from mortar import Feature

class UserAge(Feature):
    def compute(self, user):
        return user.age

This code defines a feature that computes a user's age.

  1. Creating a model:
from mortar import Model

class AgePredictor(Model):
    def train(self, features, labels):
        # Training logic here
        pass

    def predict(self, features):
        # Prediction logic here
        pass

This example shows how to create a basic model class in Mortar.

  1. Defining a pipeline:
from mortar import Pipeline

class UserPipeline(Pipeline):
    features = [UserAge()]
    model = AgePredictor()

    def process(self, user):
        features = self.compute_features(user)
        return self.model.predict(features)

This code demonstrates how to define a pipeline that combines features and a model.

Getting Started

To get started with Mortar, follow these steps:

  1. Install Mortar:
pip install mortar-ml
  1. Create a new Mortar project:
mortar init my_project
cd my_project
  1. Define your features, models, and pipelines in separate Python files.

  2. Train and test your pipeline:

from mortar import train, test

train("UserPipeline")
test("UserPipeline")
  1. Deploy your pipeline:
mortar deploy UserPipeline

For more detailed instructions and advanced usage, refer to the official Mortar documentation.

Competitor Comparisons

17,430

A fast dependency injector for Android and Java.

Pros of Dagger

  • More actively maintained with frequent updates
  • Broader scope, supporting dependency injection across various Android components
  • Extensive documentation and community support

Cons of Dagger

  • Steeper learning curve due to more complex API
  • Requires more boilerplate code
  • Can increase compile times for larger projects

Code Comparison

Dagger:

@Module
public class AppModule {
    @Provides
    @Singleton
    SharedPreferences provideSharedPreferences(Application application) {
        return PreferenceManager.getDefaultSharedPreferences(application);
    }
}

Mortar:

public class MyPresenter extends Presenter<MyView> {
    @Override
    protected void onLoad(Bundle savedInstanceState) {
        super.onLoad(savedInstanceState);
        getView().showMessage("Hello, Mortar!");
    }
}

Summary

Dagger is a more comprehensive dependency injection framework with wider adoption and active development. It offers greater flexibility but comes with increased complexity. Mortar, while simpler, focuses specifically on MVP architecture and has seen less recent development. The choice between the two depends on project requirements, team expertise, and desired architectural patterns.

8,925

Koin - a pragmatic lightweight dependency injection framework for Kotlin & Kotlin Multiplatform

Pros of Koin

  • Lightweight and easy to set up, with minimal boilerplate code
  • Supports Kotlin multiplatform projects
  • Provides a DSL for dependency declaration, making it more intuitive for Kotlin developers

Cons of Koin

  • Lacks compile-time safety, as dependencies are resolved at runtime
  • May have a steeper learning curve for developers new to dependency injection
  • Limited features compared to more robust DI frameworks

Code Comparison

Koin:

val myModule = module {
    single { MyService() }
    factory { MyViewModel(get()) }
}

Mortar:

@Module
public class MyModule {
    @Provides @Singleton
    MyService provideMyService() {
        return new MyService();
    }
}

Key Differences

  • Koin is specifically designed for Kotlin, while Mortar is Java-based
  • Mortar uses a more traditional annotation-based approach, while Koin utilizes a DSL
  • Koin focuses on simplicity and ease of use, whereas Mortar provides more advanced features for complex applications

Use Cases

  • Koin: Ideal for small to medium-sized Kotlin projects, especially those targeting multiple platforms
  • Mortar: Better suited for large-scale Java applications with complex dependency graphs and advanced requirements

Both libraries aim to simplify dependency injection, but they cater to different ecosystems and project sizes. The choice between them depends on the specific needs of your project and your preferred programming language.

7,751

Uber's cross-platform mobile architecture framework.

Pros of RIBs

  • More comprehensive architecture, covering routing and business logic
  • Better suited for large-scale applications with complex navigation
  • Active development and community support

Cons of RIBs

  • Steeper learning curve due to its complexity
  • May be overkill for smaller projects
  • Requires more boilerplate code

Code Comparison

RIBs:

class ExampleRouter(
    interactor: ExampleInteractor,
    component: ExampleBuilder.Component
) : Router<ExampleInteractor, ExampleBuilder.Component>(interactor, component) {
    // Router implementation
}

Mortar:

@Layout(R.layout.example_view)
public class ExampleView extends LinearLayout {
    @Inject ExamplePresenter presenter;

    public ExampleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // View implementation
    }
}

Key Differences

  • RIBs uses a more modular approach with separate components for routing, interacting, and building
  • Mortar focuses on view-presenter coupling and scope management
  • RIBs is written in Kotlin, while Mortar is in Java
  • RIBs has a more active development cycle and larger community
  • Mortar is simpler to implement for basic MVP patterns

Use Cases

  • Choose RIBs for large, complex Android applications with intricate navigation
  • Opt for Mortar in smaller projects or when a lightweight MVP framework is sufficient

Mavericks: Android on Autopilot

Pros of Mavericks

  • More recent development and active maintenance
  • Broader scope, supporting multiple cloud providers and deployment options
  • Enhanced flexibility for custom workflows and integrations

Cons of Mavericks

  • Steeper learning curve due to increased complexity
  • Less focused on specific use cases compared to Mortar's Hadoop-centric approach
  • Potentially more resource-intensive for smaller projects

Code Comparison

Mortar (Pig Latin):

REGISTER 'udfs.jar';
data = LOAD 'input' AS (name:chararray, age:int);
filtered = FILTER data BY age >= 18;
STORE filtered INTO 'output';

Mavericks (Python):

from mavericks import Job, Step

job = Job()
job.add_step(Step(
    name='filter_data',
    input='s3://input',
    output='s3://output',
    mapper='filter_mapper.py',
    reducer='filter_reducer.py'
))
job.run()

Summary

Mortar focuses on simplifying Hadoop workflows with Pig Latin, while Mavericks offers a more versatile approach to data processing across various cloud platforms. Mortar may be easier for Hadoop-specific tasks, but Mavericks provides greater flexibility for diverse data processing needs. The choice between them depends on the specific requirements of your project and your team's expertise.

A scope tree based Dependency Injection (DI) library for Java / Kotlin / Android.

Pros of Toothpick

  • Lightweight and fast dependency injection framework
  • Supports both runtime and compile-time dependency resolution
  • Offers easier testing and better code organization

Cons of Toothpick

  • Steeper learning curve for developers new to dependency injection
  • Less mature and smaller community compared to Mortar
  • May require more setup and configuration for complex projects

Code Comparison

Toothpick:

@Inject
public MyClass(Dependency dependency) {
    // Constructor injection
}

Toothpick.inject(this, Toothpick.openScope(this));

Mortar:

@Inject
MyClass myClass;

ObjectGraph objectGraph = ObjectGraph.create(new MyModule());
objectGraph.inject(this);

Both frameworks use annotations for dependency injection, but Toothpick offers more flexibility in scope management and supports constructor injection out of the box. Mortar, on the other hand, relies on field injection and requires more setup for custom scopes.

Toothpick provides a more modern approach to dependency injection in Android development, while Mortar offers a simpler, more established solution. The choice between the two depends on project requirements, team expertise, and desired features.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Mortar

Deprecated

Mortar had a good run and served us well, but new use is strongly discouraged. The app suite at Square that drove its creation is in the process of replacing Mortar with Square Workflow.

What's a Mortar?

Mortar provides a simplified, composable overlay for the Android lifecycle, to aid in the use of Views as the modular unit of Android applications. It leverages Context#getSystemService to act as an a la carte supplier of services like dependency injection, bundle persistence, and whatever else your app needs to provide itself.

One of the most useful services Mortar can provide is its BundleService, which gives any View (or any object with access to the Activity context) safe access to the Activity lifecycle's persistence bundle. For fans of the Model View Presenter pattern, we provide a persisted Presenter class that builds on BundleService. Presenters are completely isolated from View concerns. They're particularly good at surviving configuration changes, weathering the storm as Android destroys your portrait Activity and Views and replaces them with landscape doppelgangers.

Mortar can similarly make Dagger ObjectGraphs (or Dagger2 Components) visible as system services. Or not — these services are completely decoupled.

Everything is managed by MortarScope singletons, typically backing the top level Application and Activity contexts. You can also spawn your own shorter lived scopes to manage transient sessions, like the state of an object being built by a set of wizard screens.

These nested scopes can shadow the services provided by higher level scopes. For example, a Dagger extension graph specific to your wizard session can cover the one normally available, transparently to the wizard Views. Calls like ObjectGraphService.inject(getContext(), this) are now possible without considering which graph will do the injection.

The Big Picture

An application will typically have a singleton MortarScope instance. Its job is to serve as a delegate to the app's getSystemService method, something like:

public class MyApplication extends Application {
  private MortarScope rootScope;

  @Override public Object getSystemService(String name) {
    if (rootScope == null) rootScope = MortarScope.buildRootScope().build(getScopeName());

    return rootScope.hasService(name) ? rootScope.getService(name) : super.getSystemService(name);
  }
}

This exposes a single, core service, the scope itself. From the scope you can spawn child scopes, and you can register objects that implement the Scoped interface with it for setup and tear-down calls.

  • Scoped#onEnterScope(MortarScope)
  • Scoped#onExitScope(MortarScope)

To make a scope provide other services, like a Dagger ObjectGraph, you register them while building the scope. That would make our Application's getSystemService method look like this:

  @Override public Object getSystemService(String name) {
    if (rootScope == null) {
      rootScope = MortarScope.buildRootScope()
        .with(ObjectGraphService.SERVICE_NAME, ObjectGraph.create(new RootModule()))
        .build(getScopeName());
    }

    return rootScope.hasService(name) ? rootScope.getService(name) : super.getSystemService(name);
  }

Now any part of our app that has access to a Context can inject itself:

public class MyView extends LinearLayout {
  @Inject SomeService service;

  public MyView(Context context, AttributeSet attrs) {
    super(context, attrs);
    ObjectGraphService.inject(context, this);
  }
}

To take advantage of the BundleService describe above, you'll put similar code into your Activity. If it doesn't exist already, you'll build a sub-scope to back the Activity's getSystemService method, and while building it set up the BundleServiceRunner. You'll also notify the BundleServiceRunner each time onCreate and onSaveInstanceState are called, to make the persistence bundle available to the rest of the app.

public class MyActivity extends Activity {
  private MortarScope activityScope;

  @Override public Object getSystemService(String name) {
    MortarScope activityScope = MortarScope.findChild(getApplicationContext(), getScopeName());

    if (activityScope == null) {
      activityScope = MortarScope.buildChild(getApplicationContext()) //
          .withService(BundleServiceRunner.SERVICE_NAME, new BundleServiceRunner())
          .withService(HelloPresenter.class.getName(), new HelloPresenter())
          .build(getScopeName());
    }

    return activityScope.hasService(name) ? activityScope.getService(name)
        : super.getSystemService(name);
  }

  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    BundleServiceRunner.getBundleServiceRunner(this).onCreate(savedInstanceState);
    setContentView(R.layout.main_view);
  }

  @Override protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    BundleServiceRunner.getBundleServiceRunner(this).onSaveInstanceState(outState);
  }
}

With that in place, any object in your app can sign up with the BundleService to save and restore its state. This is nice for views, since Bundles are less of a hassle than the Parcelable objects required by View#onSaveInstanceState, and a boon to any business objects in the rest of your app.

Download

Download the latest JAR or grab via Maven:

<dependency>
    <groupId>com.squareup.mortar</groupId>
    <artifactId>mortar</artifactId>
    <version>(insert latest version)</version>
</dependency>

Gradle:

compile 'com.squareup.mortar:mortar:(latest version)'

Full Disclosure

This stuff has been in "rapid" development over a pretty long gestation period, but is finally stabilizing. We don't expect drastic changes before cutting a 1.0 release, but we still cannot promise a stable API from release to release.

Mortar is a key component of multiple Square apps, including our flagship Square Register app.

License

Copyright 2013 Square, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.