Android development and problem solving related to development
Purpose of the article
This article will address the problems of Android development and development in general. We all know that developing a program is a lot of hard work that takes a lot of time and effort, and sometimes you have to spend a lot of time to find a solution to a problem, because some solutions from the Internet do not always work.
This article will address the following questions:
- Custom keyboard for Android
- Multithreading
- Advertising integration into the program
Custom keyboard for Android
In my program, in my calculator, I had to make my keyboard, as it is not convenient to enter mathematical formulas from the system keyboard. Trying to solve this problem, I went through a bunch of forums, tried out several different solutions, but they all did not give the proper result.
Let's start:
- Create a new project in android studio.
- Create a couple of classes.
- Test the application
Make a simple keyboard of 9 characters with the ability to delete these characters. Let's
call our project KeyBoardTest

Let's select an empty activity and start

Done. We have created our new project. Now let's do the most basic, namely, create a layout file in the folder - res / layout and call it keyboard, here we will have the appearance of the keyboard.
Let's draw this keyboard:
<?xml version="1.0" encoding="utf-8"?><FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_gravity="bottom"android:background="@color/colorBlue"android:layout_width="match_parent"android:layout_height="100dp"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="50dp"android:orientation="horizontal"><TextViewandroid:id="@+id/one"android:textColor="@color/colorWhite"android:gravity="center"android:textSize="30sp"android:text="@string/one"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent"/><TextViewandroid:id="@+id/two"android:textColor="@color/colorWhite"android:gravity="center"android:textSize="30sp"android:text="@string/two"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent"/><TextViewandroid:id="@+id/three"android:textColor="@color/colorWhite"android:gravity="center"android:textSize="30sp"android:text="@string/three"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent"/><TextViewandroid:id="@+id/four"android:textColor="@color/colorWhite"android:gravity="center"android:textSize="30sp"android:text="@string/four"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent"/><TextViewandroid:id="@+id/five"android:textColor="@color/colorWhite"android:gravity="center"android:textSize="30sp"android:text="@string/five"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent"/></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="50dp"android:orientation="horizontal"><TextViewandroid:id="@+id/six"android:textColor="@color/colorWhite"android:gravity="center"android:textSize="30sp"android:text="@string/six"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent"/><TextViewandroid:id="@+id/seven"android:textColor="@color/colorWhite"android:gravity="center"android:textSize="30sp"android:text="@string/seven"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent"/><TextViewandroid:id="@+id/eight"android:textColor="@color/colorWhite"android:gravity="center"android:textSize="30sp"android:text="@string/eight"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent"/><TextViewandroid:id="@+id/nine"android:textColor="@color/colorWhite"android:gravity="center"android:textSize="30sp"android:text="@string/nine"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent"/><TextViewandroid:id="@+id/delete"android:textColor="@color/colorWhite"android:gravity="center"android:textSize="30sp"android:text="@string/delete"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent"/></LinearLayout></LinearLayout></FrameLayout>
After our keyboard is drawn, we can create a class that will register all of our keystrokes and write what we need. Note that every textview has an id - this is very important!
Let's call this class KeyBoardListener.
Let's write the constructor of our class, it takes as a argument the View - the field in which we work, in other words, the location of our editText, and also it accepts the editText itself, in which we will type characters from our keyboard.
package keyboard.develop.keyboardtest;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
publicclassKeyBoardListener{
EditText editText;
private StringBuilder finalText = new StringBuilder();
KeyBoardListener(View view, final EditText editText) {
this.editText = editText;
TextView one = view.findViewById(R.id.one);
TextView two = view.findViewById(R.id.two);
TextView three = view.findViewById(R.id.three);
TextView four = view.findViewById(R.id.four);
final TextView five = view.findViewById(R.id.five);
TextView six = view.findViewById(R.id.six);
TextView seven = view.findViewById(R.id.seven);
TextView eight = view.findViewById(R.id.eight);
TextView nine = view.findViewById(R.id.nine);
TextView delete = view.findViewById(R.id.delete);
final LinearLayout layout = view.findViewById(R.id.keyBoard);
one.setOnClickListener(new View.OnClickListener() {
@OverridepublicvoidonClick(View view){
int selection = editText.getSelectionEnd();
finalText.insert(selection, "1");
setTextSelection();
}
});
two.setOnClickListener(new View.OnClickListener() {
@OverridepublicvoidonClick(View view){
int selection = editText.getSelectionEnd();
finalText.insert(selection, "2");
setTextSelection();
}
});
three.setOnClickListener(new View.OnClickListener() {
@OverridepublicvoidonClick(View view){
int selection = editText.getSelectionEnd();
finalText.insert(selection, "3");
setTextSelection();
}
});
four.setOnClickListener(new View.OnClickListener() {
@OverridepublicvoidonClick(View view){
int selection = editText.getSelectionEnd();
finalText.insert(selection, "4");
setTextSelection();
}
});
five.setOnClickListener(new View.OnClickListener() {
@OverridepublicvoidonClick(View view){
int selection = editText.getSelectionEnd();
finalText.insert(selection, "5");
setTextSelection();
}
});
six.setOnClickListener(new View.OnClickListener() {
@OverridepublicvoidonClick(View view){
int selection = editText.getSelectionEnd();
finalText.insert(selection, "6");
setTextSelection();
}
});
seven.setOnClickListener(new View.OnClickListener() {
@OverridepublicvoidonClick(View view){
int selection = editText.getSelectionEnd();
finalText.insert(selection, "7");
setTextSelection();
}
});
eight.setOnClickListener(new View.OnClickListener() {
@OverridepublicvoidonClick(View view){
int selection = editText.getSelectionEnd();
finalText.insert(selection, "8");
setTextSelection();
}
});
nine.setOnClickListener(new View.OnClickListener() {
@OverridepublicvoidonClick(View view){
int selection = editText.getSelectionEnd();
finalText.insert(selection, "9");
setTextSelection();
}
});
delete.setOnClickListener(new View.OnClickListener() {
@OverridepublicvoidonClick(View view){
int selection = editText.getSelectionEnd();
if (finalText.length() > 0) {
finalText = stringToBuilder(finalText.substring(0, selection - 1 == -1 ? 0 : selection - 1) + finalText.substring(selection));
editText.setText(finalText);
}
editText.setSelection(selection - 1 <= 0 ? 0 : selection - 1);
}
});
editText.setOnClickListener(new View.OnClickListener() {
@OverridepublicvoidonClick(View view){
layout.setVisibility(View.VISIBLE);
}
});
}
private StringBuilder stringToBuilder(String s){ returnnew StringBuilder(s); }
privatevoidsetTextSelection(){
int selection = editText.getSelectionEnd();
editText.setText(finalText);
editText.setSelection(selection + 1);
}
}
Now let's take a closer look at this code. In the constructor we passed the editText and view in order to take the buttons and assign them the execution of the input. It should be noted that the method of the delete button uses “syntactic sugar”, in other words, it is an abbreviated entry of the code. Not everyone knows this design, so I decided that we should pay attention to it. This is especially useful for beginners.
This construction works in this way.
int p = (условие) ? вариант 1 : вариант 2;
int p = k == 2 ? 7 : 3;
// это можно записать и такif (k == 2)
p = 7;
else
p = 3;
But we have moved away from the topic. Now after our constructor is ready and we can respond to button presses, we can use our class. First we need to call this class in our main activity.
package keyboard.develop.keyboardtest;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
publicclassMainActivityextendsAppCompatActivity{
private LinearLayout layout;
private ExecutorThread executorThread;
@OverrideprotectedvoidonCreate(Bundle savedInstanceState){
getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); // Убираем системную клавиатуру, при этом оставляем курсорsuper.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText editText = findViewById(R.id.edit);
layout = findViewById(R.id.keyBoard);
new KeyBoardListener(layout, editText);
executorThread = new ExecutorThread((TextView)findViewById(R.id.textView));
editText.addTextChangedListener(new TextWatcher() {
@OverridepublicvoidbeforeTextChanged(CharSequence charSequence, int i, int i1, int i2){}
@OverridepublicvoidonTextChanged(CharSequence charSequence, int i, int i1, int i2){}
@OverridepublicvoidafterTextChanged(Editable editable){
if (!editable.toString().equals("")) {
executorThread.setK(Integer.parseInt(editText.getText().toString()));
executorThread.doWork();
}
}
});
}
@OverridepublicvoidonBackPressed(){
layout.setVisibility(View.GONE); // Клавиатура исчезает
}
}
It is worth paying attention to this line.
getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
In this line, we disable the system keyboard, but leave the cursor so that we can move between characters and insert numbers / letters, etc. That is precisely why we used the StringBuilder class and the insert method in the code above .
Due to the fact that this whole method is called as a separate class, we can add it anywhere and use it in any programs. Thus, the objectivity of the code is obtained.
But I didn’t show you how to do it in xml code, how to specify the location of this keyboard, and everything is very simple
<?xml version="1.0" encoding="utf-8"?><FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="keyboard.develop.keyboardtest.MainActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:textColor="@color/colorPrimary"android:gravity="center"android:textSize="25sp"android:layout_width="match_parent"android:layout_height="50dp"android:text="Write your text here!"/><EditTextandroid:id="@+id/edit"android:layout_width="match_parent"android:layout_height="50dp"/></LinearLayout><LinearLayout // Вот тут и располагается наша клавиатура
android:visibility="gone"android:id="@+id/keyBoard"android:layout_height="wrap_content"android:layout_width="match_parent"android:layout_gravity="bottom"><includelayout="@layout/keyboard"/> // А точнее тут, в этой строчке
</LinearLayout></FrameLayout>
Now with light manipulations we can use our keyboards anywhere, even in fragments.
In our application, the keyboard looks like this

Multithreading
Multi-threading - it is clear from the name that it is a lot of threads. A lot of threads - this means the execution of several operations simultaneously. Multithreading is a rather problematic topic in programming. What's in C ++, what's in Java, what other threads with multithreading have always had problems. Fortunately, almost all languages have a high-level solution to this problem. But we are now developing for Android, so about Anroid, or rather about the Java programming language, we will talk.
In Java Java, there is such a thing as Thread - it is convenient when drawing, with frequent instant redrawing of the image, there are many articles on this topic, including on Habré, so I will not consider this option. I am interested in the so-called “falling asleep flow”, the flow that is waiting for its call to solve any task. This is the case when you caused the flow, it worked and fell asleep, without spending the device resources while waiting for a new task.
And the name of what I described above is a class from the standard java.util.concurrent ExecutorServise package.
The essence of this class is that it can reuse the same stream without creating a new one. And now we will consider how it works, we will not create a new program, but continue to work in ours.
To do this, create a new class, which will be called ExecutorThread. Let us set the task that we need to add one to the digit p , until this p is equal to the number entered by us in 4 degrees. Everything is done to make the calculation longer. And so that the whole interface does not hang, we will put it all into a separate thread.
package keyboard.develop.keyboardtest;
import android.widget.TextView;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
publicclassExecutorThread{
private ExecutorService executorService;
private Thread thread;
privateint p = 0;
privateint pow = 0;
privateint k = 0;
private TextView textView;
ExecutorThread(final TextView text) {
p = 0;
textView = text;
thread = new Thread(new Runnable() {
@Overridepublicvoidrun(){
for (int i = 0; i < pow; i++)
p++;
String s = "Result " + k + "^4 = " + String.valueOf(p);
textView.setText(s);
}
});
thread.start();
executorService = Executors.newSingleThreadExecutor();
}
voiddoWork(){
executorService.submit(thread);
}
voidsetK(int k){
p = 0;
this.k = k;
pow = (int) Math.pow(k, 4);
textView.setText("Please wait. We are calcing!");
}
}
As we see, at that moment, while we did not consider it yet, then we can see the entry “Please wait. We are calcing! ”, That is clear -“ Please wait. We believe!". And after we calculate, we will display the text in our textView, which we passed to the constructor of our class. In order for everything to work, we need to add a textView after our editText to our activity_main, which we had when creating the project.
<TextViewandroid:gravity="center"android:textColor="@color/colorPrimary"android:textSize="25sp"android:id="@+id/textView"android:layout_width="match_parent"android:layout_height="50dp"/>
And we also need to add the code below to our main class, MainActivity.
executorThread = new ExecutorThread((TextView)findViewById(R.id.textView));
editText.addTextChangedListener(new TextWatcher() {
@OverridepublicvoidbeforeTextChanged(CharSequence charSequence, int i, int i1, int i2){}
@OverridepublicvoidonTextChanged(CharSequence charSequence, int i, int i1, int i2){}
@OverridepublicvoidafterTextChanged(Editable editable){
if (!editable.toString().equals("")) {
executorThread.setK(Integer.parseInt(editText.getText().toString()));
executorThread.doWork();
}
}
});
It is worth noting that the addTextChangeListener method is responsible for changing the text in our editText. As we can see, inside this method we call the doWork () function, which in turn executes these strings
executorService.submit(thread);
I checked all the above on my phone, so if you did everything right, then you should have no problems or errors.
As we can see, this method is quite convenient and easy to understand, I tried to describe everything as simply as possible, so I hope you understand everything, but I did not miss anything.
And now let's move on to point 3 of our article, namely, the integration of advertising.
Advertising integration
In fact, I can’t tell you much about this, I can only advise. With advertising, not everything is so easy and transparent. Personally, I would advise you to use Appodeal, it is not so long ago on the market, but it works quite successfully.
It is also worth noting that there is a very good Russian-language support, which almost always immediately answers your question or your problem. This immediately makes it clear how loyal this network is.
I want to say right away, if you suddenly use it, be sure to set up payment in AdMob and in Appodeal, otherwise the advertisement will simply not be loaded. Due to the fact that I did not set up accounts, I wasted all day, and then they told me in support: “Did I set up accounts?”. And after I did it, the advertisement appeared 2 hours later.
Conclusion
Since this article is intended for novice programmers, I want to note one obvious thing. If you really like programming, and you are ready to spend tons of hours on solving a particular problem, then programming is yours, otherwise there isn’t. Just do not go beyond. Since it’s too long a decision, something not too complicated and not too simple is not good. But this is an obvious fact. In fact, I read this phrase somewhere on the Internet. In fact, it is true. If you think about it, then really, if programming, serious programming would be so easy, then few people from the total number of all people would be involved in it.
I hope that my article turned out to be useful to someone and really helped someone, helped save time, because I personally, on the keyboard, it would seem such a simple thing, killed 3 days, and it took me 2 streams and the search for a normal solution. of the day