I want to start by saying that it's the first time that I have to deal with performance, because it's the first time that I develop an android app.
The app
The app is a source code editor, where you can open files, modify them and save them back. The app consist of 4 parts:
- The navigator view: contains a ListView for the open files and a TreeView for the open folders.
- The code views container: this hold the views containing the actual code.
- The code container: this is a little view containing a text view and a custom EditText (created by me extending EditText class, but its not implements yet, so it behave exactly like an EditText). The TextView is just showing the lines of code.
- The open and save fragments: there are 2 fragments that I use as DialogFragment: the save fragment let you navigate the local file system as well as the Dropbox file system of the linked accounts and save the current file. The open fragment let you navigate the same file systems and open a file.
The problem
After I finished the base code editor, I moved to syntax highlighting. Now, I want to mke clear that the leaks are generated even without the syntax highlighting, so this is not the problem.
Anyway, by testing the syntax highlithing, I was opening "large" files (1200 lines of code) and I noticed that the app becomes extremly slow, which is obvious because I'm regexing the whole text (I will avoid this by highlight only the visible text). This push me to test the app without syntax highlithing with large files and I found that the app become still a bit slow and I noticed that some memory leaks happened.
In particular, when I open a large file (1200 lines of code) the app take 1 second to display the lines of code in the textview and when I type the drawing of the character is slow. In addition whenever I type of remove a character a memory leak happen.
The inspection
I tried to inspect the heap (with MAT), but as said I don't have any experience in this and I'm not sure what to do to investigate this problem. I'm sorry but I cannot upload screenshots (don't have permission by stackoverflow for that), but I can report you some numbers:
System before opening the large file
System overview
Leaks suspects
Problem 1
Details:
Problem 2
Problem 3
Biggest top-level dominator packages
Biggest objects
System after opening the large file
System overview
Leaks suspects:
Problem 1:
Details:
Problem 2:
Problem 3 Problem 4
Biggest top-level dominator packages
Biggest objects
From the Android device monitor:
System before opening the large file
System after opening the large file
Some parts of the allocations:
Thank you in advance
EDIT:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/codeScrollView"
android:fillViewport="true">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:background="@drawable/lines_stroke"
android:textColor="@android:color/white"
android:text="@string/first_line"
android:textSize="15dp"
android:gravity="right"
android:paddingLeft="15dp"
android:paddingRight="5dp"
android:id="@+id/edit_code_lines_view"/>
<com.example.green.bachelorproject.customViews.codeEditView.TouchEditText
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/code_stroke"
android:gravity="top"
android:textColor="@android:color/white"
android:textSize="15dp"
android:paddingLeft="3dp"
android:paddingRight="3dp"
android:textCursorDrawable="@color/white"
android:id="@+id/edit_code_content_view"/>
</LinearLayout>
</ScrollView>
EDIT
Ok guys I found the problem. If you see, every time that I type something, I update the lines EditText and, since the text is long (1200 lines), it take a while to recompute it. Did event though about that! I have to find a faster way to show the lines of code. One option is to use one TextView for each line, in this way I only update the TextView that need to be changed. But I don't know if having 1200 TextView objects is nice.
package com.example.green.bachelorproject.customViews.codeEditView; import android.content.Context; import android.graphics.Color; import android.graphics.Typeface; import android.text.Editable; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextWatcher; import android.text.style.ForegroundColorSpan; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; import utils.Colorizer; import utils.Lexer; import com.example.green.bachelorproject.events.UpdateCacheFileEvent; import com.example.green.bachelorproject.R; import de.greenrobot.event.EventBus; import com.example.green.bachelorproject.internalFileSystem.InternalFile; import java.util.ArrayList; /** * Created by Green on 26/02/15. */ public class CodeEditView extends LinearLayout { private Context context; private TextView lines; private EditText code; private Typeface currentTypeface; private InternalFile internalFile; private Lexer lexer; private Colorizer colorizer; public CodeEditView(Context context) { super(context); this.context = context; init(null); } public CodeEditView(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; init(attrs); } private void init(AttributeSet attrs) { //CHECK THIS LayoutInflater layoutInflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); layoutInflater.inflate(R.layout.edit_code_layout, this); // this.colorizer = new Colorizer(); // this.colorizer.setColor("String", Color.rgb(218, 220, 95)); // this.colorizer.setColor("Number", Color.rgb(173, 125, 255)); // this.colorizer.setColor("Character", Color.rgb(218, 220, 95)); // this.colorizer.setColor("Operator", Color.rgb(234, 38, 116)); // this.colorizer.setColor("Keyword", Color.rgb(234, 38, 116)); // this.colorizer.setColor("Identifier", Color.WHITE); // this.colorizer.setColor("Type", Color.rgb(105, 216, 238)); // this.colorizer.setColor("Comment", Color.rgb(117, 113, 91)); this.lexer = new Lexer(); this.lines = (TextView) findViewById(R.id.edit_code_lines_view); //this.lines.setTypeface(currentTypeface); this.code = (EditText) findViewById(R.id.edit_code_content_view); //this.code.setTypeface(currentTypeface); this.code.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { // writeToFile(); //EventBus.getDefault().post(new UpdateCacheFileEvent(code.getText().toString(), internalFile)); //setLines(); } }); } private void setLines() { int usedLines = code.getLineCount(); String text = "1" + System.lineSeparator(); for(int i = 2; i tokens = lexer.tokenize(content); // SpannableStringBuilder text = new SpannableStringBuilder(content); // // for(Lexer.Token t: tokens) { // text.setSpan(new ForegroundColorSpan(colorizer.getColor(t)), t.start, t.end, Spannable.SPAN_INCLUSIVE_INCLUSIVE); // } // code.setText(text); // code.post(new Runnable() { // @Override // public void run() { // setLines(); // } // }); } public void setFont(Typeface typeFace) { this.lines.setTypeface(typeFace); this.code.setTypeface(typeFace); } }
EDIT: Beside the recent discover, whithout syntax highlighting the typing is fast, but I still encounter lag when enabling the syntax highlighting. When I open the file, the highlight is very quick, but the typing is still slow and memory leak messages
04-28 04:49:58.119: D/dalvikvm(2437): GC_EXPLICIT freed 185K, 17% free 6027K/7244K, paused 1ms+1ms, total 5ms
appear. Anyway, I'm wondering what is the object 1-byte array (byte[], boolean[]) is, because it's actually using 2 MB. Any suggestions?
EDIT:
Definitely found the problem. Since the file is big and lot of spans are created, when I change something on the top of the file, the editext has to recalculate the position of all spans.