Why doesn't Android store the packages as binaries like on other Linux distros? On Ubuntu, it doesn't store apps as deb files it stores them as plain compiled code. Why doesn't Android do that instead of using Jit and cache? Wouldn't it be more efficient to just compile it completely like on Ubuntu?
There are really two different issues here. Your question about "compiled code" is dealt with by another of today's questions. This is completely separate from whether an app is unpacked from its package file. Don't forget that Ubuntu (and other Linux distros) can have apps written in Java and shipped as JAR files, as well as native executables, and Android apps can include native code as well as Java. In both cases, the binary itself is a small part of the package: the images and other data (known as assets) used by the app are far larger.

It's mainly for historical reasons that applications on GNU/Linux have to be unpacked into separate files. This is much less efficient than keeping the package file itself, since the separate files take up more storage space and are thus slower to load. But because of the way GNU/Linux software is developed, and the way different tools work together, it's much more convenient to keep doing it the same way.

As Android is a new OS (with a Linux-based kernel), it's not limited by its history in the same way as Ubuntu. The init system, and the framework with which apps are written, are set up to support running from the APK file itself, while keeping it read-only. As well as the storage advantages above, it also makes it easier to keep apps protected and isolated from each other, because each app is a single file in read-only storage. There's no need for complicated setup scripts to make sure the correct files are overwritten or replaced in upgrades, and the intent system makes it unnecessary for packages to overwrite or replace each other as with Debian's update-alternatives script.