Создание IDE для Amdroid на Java. #1

559b41bb0231814cf9fa9503cc62e7ba

Привет, Хабр!

Вступление

В этой статье я буду рассказывать о создании своей IDE для Android. Я не нашел какого-либо материала на эту тему. Хочу разделить статью на несколько подстатей, так как информации будет много. Также буду оставлять ссылки на весь материал который я использовал.

Статья предназначена для новичков, ну и для тех кто хочет создать свою IDE для мобилки. Мы будем делать IDE для языка программирования Lua, но это не имеет особого значения, так как в проект можно будет добавить любой язык. Я лично буду использовать библиотеку Luaj, это очень удоьный и простой в использовании интерпритатор для Lua написаный на Java.

Также нам понадобятся библиотеки MaterialDesign и AndroidX, для создания красивого интерфейса, ну они часто уже есть в проектах по умолчанию, А также SoraEditor для создания удобного редактора с оптимизированой подсветкой синтаксиса.

GitHub — luaj/luaj: Lightweight, fast, Java-centric Lua interpreter written for JME and JSE, with string, table, package, math, io, os, debug, coroutine & luajava libraries, JSR-223 bindings, all metatags, weak tables and unique direct lua-to-java-bytecode compiling.

github.com

GitHub — Rosemoe/sora-editor: A multifunctional Android code editor library. (aka CodeEditor)

github.com

Подготовка

Для начало подключим все нужные библиотеки. Заходим в файл app/build.gradle, и добавляем нужные зависимости:

dependencies {
    implementation("com.google.android.material:material:1.9.0")
    implementation("androidx.appcompat:appcompat:1.6.1")
    
    // sora editor API
    implementation(platform("io.github.Rosemoe.sora-editor:bom:0.23.2"))
    implementation 'io.github.Rosemoe.sora-editor:editor'
    implementation 'io.github.Rosemoe.sora-editor:language-textmate'
}

Пока-что зависимости SoraEditor нам не понадобятся, его мы будем использовать при создании самого редактора.

Также нужно поменять версию Java минимум на 17 для работы SoraEditor. В файле app/build.gradle:

android {
    ...
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }
    ...
}

Также, я отключу viewbinding, так как мне не нравится его использовать, но если вам он нравится, можете оставить.

Создадим класс App он будет наследоваться от Application, он будет хранить различные константы и общие данны, такие как путь к папке с проектами.

Мы будем хранить проекты во внутреннем хранилище, которое будт доступно всем приложениям. Конечно можно хранить и во внешнем, но не виду смысла заморачиваться на этот счет, я всеровно сделаю экспорт проекта в формате ZIP архива.

Пример класса App:

public class App extends Application {
    
    private static Context context;
    
    public static Context getContext() {
        return context;
    }
    
    public static File getProjectsDir() {
        File dir = new File(context.getExternalFilesDir(null), "projects/");
        if(!dir.exists()) dir.mkdirs();
        return dir;
    }
}

Далее в манифесте, в  добавляем тег android: name=».App», псли ваш класс находится в другом пакете, то укажите другой пакет. Пример:


  ...

Создание меню проектов

Создани активность если вы ее еще не создали, я назову свою ProjectsActivity, и она будет находится в пакете .activitys для большего удобства, там будут находится все активности приложения.

В разметке это активности, мы должны добавить 2 view, это Toolbar и RecyclerView.

Toolbar — это верхняя панель в приложении, которая является более гибкой версией ActionBar и AppBar, так мы может расположить ее в любом месте, но я уже по привычке его использую, вы можете использовать свой Toolbar.

RecyclerView — это улучшеная версия ListView, которая дополнительна оптимизирована для большого массива данных, так как использует минимальное кол-во элементов которые можно показать на экране, его рекомендуется использовать.

Вот пример разметки:



    
    
    
    

Я храню все цвета в файле colors.xml, чтоб можно было поменять в любой момент нет бегая по файлам, в также чтобы удобно было делать что-то для другой темы, тоже самое с strings.xml, но для языков. Я это написал потому-что многие не соблюдают эти обычаи.

Далее, нужно создать адаптер, а также сам элемент проекта в layout/.

Я создам дирректорию project, там будут все с этим связаные файле. Там создадим класс Project, для удобного использования, там будет хранится название проекта и путь к нему. Пример кода:

public class Project {
    private String name;
    private File path;

    public Project(File path) {
        this.path = path;
        this.name = path.getName();
    }
    
    public Project(String name) {
        this.name = name;
        this.path = new File(App.getProjectsDir(), name);
    }

    public boolean create() {
        File main = new File(path, "main.lua");
        try {
            main.createNewFile();
        } catch(IOException e) {
            e.printStackTrace();
            return false;
        }
        return path.mkdirs();
    }
    
    // Другие методы...
}

Далее создаем адаптер. Создадим класс ProjectsAdapter, и наследуем RecyclerView.Adapter. VH это класс который мы должны создать для хранения View в каждом элементе в списке он наследуется от RecyclerView.ViewHolder. В моем будет хранится TextView и ImageView для создания меню с выбором действие, например удалить или переименовать.

В адаптере нужно переопределить несколько методов, это onCreateViewHolder (ViewGroup, int), onBindViewHolder (VH, int) и getItemCount ().

onCreateViewHolder — в нес воздается поверхность (ViewHolder).

onBindViewHolder — тут обычно идет остальная настрока каждого элемента списка.

getItemCount — возвращает размер списка с элементам.

Пример адаптера

public class ProjectsAdapter extends RecyclerView.Adapter {
    public class VH extends RecyclerView.ViewHolder {
        private View parent;

        public VH(View parent) {
            super(parent);
            this.parent = parent;
            name = parent.findViewById(R.id.name);
            more = parent.findViewById(R.id.more);
        }

        private TextView name;
        private ImageView more;
    }
    
    private List list;
    private Context context;
    
    public ProjectsAdapter(Context context, List list) {
        this.context = context;
        this.list = list;
    }
    
    @Override
    public VH onCreateViewHolder(ViewGroup parent, int pos) {
        View view = LayoutInflater.from(context).inflate(R.layout.project_item, parent, false);
        return new VH(view);
    }

    @Override
    public void onBindViewHolder(VH vh, int pos) {
        vh.name = list.get(pos).getName();
    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    public void updateList(List list) {
        this.list = list;
        notifyDataSetChanged(); // говорим адаптеру что весь список изменился
    }
}

В App я добавлю метод getProjects () который будет возвращать List

public static List getProjects() {
    List projects = new ArrayList<>();
        for(File file : getProjectsDir().listFiles()) {
        	if(file.isDirectory()) projects.add(file);
        }
    return projects;
}

В ProjectsActivity в методе onCreate, мы создать адаптер, и применить его к RecyclerVie

Пример

ProjectsAdapter adapter;
RecyclerView rv
    
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    rv = findViewById(R.id.projects);
    adapter = new ProjectsAdapter(this, App.getProjects());
    rv.setLayoutManager(new LinearLayoutManager(this));
    rv.setAdapter(adapter);
}
    
public void updateProjects() {
    adapter.updateList(App.getProjects());
}

Функциональность кнопке more, а также создание проектов мы сделаем в следующей статье. Если будут вопросы можете задать их в комментариях.

Пока, Хабр! :-)

© Habrahabr.ru