[JAVA] Thorough comparison of Android and iOS implementations

Introduction

It seems to be. This article is the 21st day article of IS17er Advent Calendar.

This time, in commemoration of the release of both iOS / Android versions of the study game app called FFMultiplier, which I had been developing for a long time, I felt that it was difficult to develop which one I felt during the development. I would like to make a thorough comparison.

Click here for the app

-iOS (9.0 or above) -Android (5.0 or above)

I think it was common for people who developed both to express their feelings, so this time I would like to focus on how to realize a certain function technically.

timer

Swift The timer in Swift basically uses Timer (formerly NSTimer). If you want to do the same thing every few seconds

timer


Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.updateTime), userInfo: nil, repeats: true)

like this. With the introduction of #selector, typos have been reduced, and basically it is very convenient because you can write safely without worrying about threads.

Java Even in Java, timers are basically implemented using the Timer class. However, as you can see when googled ʻAndroid timer and Java Timer, there are several ways to pass the TimerTask class to Timer`, which may be annoying for beginners. ..

This time it was a countdown of the game, so at first I was thinking of using the same class called CountDownTimer, but upon closer examination, it seems that this has the drawback that it does not measure exactly 1 second, I settled down on Timer. If you create a separate class, the writing method itself is similar.

timer


timer.schedule(timerTask, 0, 1000);

However, in the case of Android, it should be noted that the processing of Timer is executed in another thread, so the drawing processing cannot be written, so the main thread must be called from the processing. In this respect, I felt that the Android timer is a little difficult for beginners.

Grid layout

iOS The grid layout we see this time is a way to create a pure grid that does not include a scroll view like CollectionView in the background.

As a realization method on iOS

--Do it steadily with AutoLayout --Calculated from code and generated --Use the new function StackView --Create with CoollectionView to prevent scrolling

Is there a hit? This time, we adopted StackView. However, I think the drawback is that this feature is not backwards compatible and does not work before iOS 9. However, I was able to arrange it almost as I intended. It's nice that the default is centered and stretched to the whole.

Android For Android, of course, use LinearLayout. This is a function that has been around since the beginning, so it works on any aircraft, and there are many materials on setting ratios, so it's good that the learning cost is low. Even if it isn't, it can be realized quite easily because it has the same function called GridLayout.

It is up to you to set the centering and expanding to the full parent element, but it seems that Android, which was ahead of the game, will be better off in this area.

Association

iOS It's safe to say that layout files (that is, storyboards) and code strings are not as easy as iOS. Strictly speaking, there are some cases where it is a little inconvenient, such as the timing when AutoLayout is applied and the timing when it is connected to the code must be considered in the life cycle, but basically the learning cost is very low, which is attractive. You can also associate one @IBAction with multiple buttons and divide the processing by tag on the GUI.

However, when it comes to processing buttons in CustomView, it's a little tricky. Because it is not possible to directly associate from the parent view controller, it cannot be realized without some ingenuity in the case of processing that affects the elements of the view controller. I think I came up with it

--Create a Delegate --Pass ViewController itself as a property --Pass a closure with no return value --Associate as an Outlet and add a touch event from the code

In my case, I feel that I prefer to use the third method exclusively these days. That is, in CustomView

In Custom View


var action: (()->())!

It is a method of declaring it like this and passing the process when instantiating.

Android On Android, there is basically a file called R that manages all at once, and it feels like registering an id from xml and fetching elements using findViewById on the code. Since it has to be written in code, it is a little troublesome, but instead, if you write it properly, you can associate it at any time you like.

Also, in the past, the ʻonClick event was always done with setOnClickListener, but Android Studio has officially made it possible to set the ʻonClick method from xml.

I think we can really say that there are advantages and disadvantages in this field.

font

iOS When you use fonts, especially your favorite fonts that aren't included by default, you can use them from your code or storyboard by putting them in your project and setting the build phase copy bundle resources on iOS. It's easy.

Android Custom fonts are a bit tricky for Android. First you have to put the font you want to put in assets and then usually create a custom class for the element you want to change the font. Moreover, if you do it without thinking about it, the font file will be copied every time you use it, so you have to make something like FontHolder and manage Typeface.

There is a library called Calligraphy to solve this problem. This makes it easy to manage without creating custom classes.

I really want iOS to come here ... sweat

Alert

iOS Use ʻUIAlertController` to raise an alert. Simple elements such as text fields can be set from code. For example, OK, Cancel button, and one text field alert

Alert


let alert = UIAlertController(title: "register name", message: "please set your username", preferredStyle: .alert)
alert.addTextField {
    textField in
    textField.placeholder = "user name"
}
alert.addAction(UIAlertAction(title: "OK", style: .default) {
    _ in
    let textfield = alert.textFields?.first
    if let name = textfield?.text {
        self.storage.set(name, forKey: "playername")
    }
})
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(alert, animated: true, completion: nil)

It's easy.

Android Android is ʻAlert Dialog`. However, since text fields etc. are not prepared, I will create xml and apply it.

AlertDialog


LayoutInflater inflater = LayoutInflater.from(gameActivity);
View dialog = inflater.inflate(R.layout.input_dialog, null);
final EditText editText = (EditText) 
dialog.findViewById(R.id.editNameText);
new AlertDialog.Builder(gameActivity).setTitle("please set your name").setView(dialog).setPositiveButton("ok", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    final String userName = editText.getText().toString();
                    sp.edit().putString("name", userName).commit();
                }
            }).show();

It's a little more troublesome, but you can add what you like to make it, so you can say that you have a lot of freedom.

Popup View-like thing

iOS The pop-up type has a lot of restrictions such as having to have a parent element if it is the default one, so I think it is best to use a library to display the View on the top.

That's why I used this.

STZPoupupView

If you prepare a layout with Storyboard or xib, you can display it quite easily.

Android On the other hand, I think there are various ways to realize it on Android, but there is a function called PopupWindow.

This allows you to achieve what you want to do, although there are a few setting items.

However, it may be easier to customize the AlertDialog for this item ...

Handling of Firebase

Basically, both are handled in the same way, but there are differences depending on the characteristics of the language in terms of usage that is somewhat easy to handle. For example, when registering

Firebase/setvalue


ref.child("hello").child(device_id).setValue(["id": id, "rank": rank as NSNumber], andPriority: -newScore.score)

In this way, you can register using Dictionary on iOS. On the other hand, Android can be used in the same way by using Map <String, Object>, but this is used in the hash tree and is not purely standard, so instead define the class as follows. hand

Firebase/class


@IgnoreExtraProperties
public class DatabaseScore {
    public String id;
    public int rank;

    public DatabaseScore() {}

    public DatabaseScore(String id, int rank) {
        this.id = id;
        this.rank = rank;
    }

    public int getId() {
        return id;
    }

    public String getRank() {
        return rank;
    }
}

By passing an instance of this, the variable name is automatically converted to a key and handled. Like this

Firebase/setvalue


ref.child("hello").child(id).setValue(databaseScore);

When reading the database, Swift is ʻobserve (.value, with: handler) and Android is ʻaddValueEventListener (valueEventListener). Each characteristic has come out. It can be read in the same format as when it was registered.

Realm treatment

There is a similar tendency to how to handle Realm with Firebase.

Let's compare simple reading and writing. First, on iOS, it looks like this:

Realm model


import RealmSwift

final class Score: Object {
    dynamic var date = NSDate(timeIntervalSince1970: 1)
    dynamic var score: Int = 0
}

First, define the model with this. You added the dynamic modifier to what you wanted to save for Realm's internal processing. And

Realm write


let newScore = Score(value: ["date": NSDate(), "score": acceptedNum])
let realm = try! Realm()
try! realm.write {
    realm.add(newScore)
}

If you enter the write thread with try and add it like this

Realm load


let scores = realm.objects(Score.self).sorted(byProperty: "score", ascending: false)

In this way, it was possible to retrieve what was saved by the method called ʻobjects`.

Then let's do the same on Android. Then the model / write / read will be as follows.

Realm model


import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;

import java.util.Date;

public class ScoreModel extends RealmObject {
    private int score;
    private Date date;

    public void setScore(int score) {
        this.score = score;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public Date getDate() {
        return date;
    }

    public int getScore() {
        return score;
    }
}

Realm writing


final ScoreModel scoreModel = new ScoreModel();
scoreModel.setScore(correctCnt * 10);
scoreModel.setDate(cal.getTime());
Realm realm = Realm.getDefaultInstance();
realm.executeTransactionAsync(new Realm.Transaction() {
    @Override
    public void execute(Realm realm) {
        realm.copyToRealm(scoreModel);
    }
});

Loading Realm


RealmResults<ScoreModel> results = realm.where(ScoreModel.class).findAllSorted("score", Sort.DESCENDING);

The flow is the same, but it is characteristic that it is necessary to set getter and setter in the model first, writing as asynchronous processing in the interface, and the result is returned in the type called RealmResults. I think.

It's hard to say which one is better, but I get the impression that Swift is more concise.

Developer registration

iOS It's 11,800 yen a year. The payment method is an Apple Store gift card or credit card, so if you don't have a credit card, you can have an event to go to the Apple Store every year.

No, it ’s expensive. .. ..

Android There is no registration fee other than $ 25. Honest! Payment is by credit card or debit card, but it seems that people who do not have a credit card can pay like a prepaid card at a convenience store by using the VISA service called V Preca.

Summary

Nowadays, smartphone apps have become the mainstay of application development, but it seems that it is still quite difficult to achieve similar things with both.

Especially in Android, there are many situations where you need to be aware of threads, and Java is not null-safe, so you need to be careful about that. On the other hand, if you don't master iOS properly, the degree of freedom will drop considerably.

In that sense, the emergence of tools such as Xamarin that can create both binaries with a single code will be a turning point in future mobile development. However, I think it will be very educational to study so that you can do the same thing with both, so please take this opportunity to challenge yourself! !!

Recommended Posts

Thorough comparison of Android and iOS implementations
Comparison of Android Handler Looper and runOnUiThread
Implementation comparison of production that makes images shine on iOS and Android
[Java / Swift] Comparison of Java Interface and Swift Protocol
Comparison of JavaScript objects and Ruby classes
Chrome59 Comparison of normal and headless mode operation
The comparison of enums is ==, and equals is good [Java]
Equivalence comparison of Java wrapper classes and primitive types
iOS app development: Timer app (5. Implementation of alarm and vibration)
[Java] String comparison and && and ||
I will explain the difference between Android application development and iOS application development from the perspective of iOS engineers
Definition of Android constants
Comparison of Web App for Containers and Azure Container Instances