Android studio сообщение об ошибке

guys I have a problem with implement error handling in my application.
I want to display the error message to the user of my application when the response code from rest is not 200. In other words: If the connection is wrong, I want to display the message, that the user have to check his internet connection and try again. If everything is fine I want to do everything as usual so load the content.

I write something like this:

Toast errorToast = Toast.makeText(NewsActivity.this, "Error, pls chech your internet connection and try again!", Toast.LENGTH_SHORT);
errorToast.show();

and this:

if(response.getStatusLine().getStatusCode() == 200){}

But i don’t know If this is good code and where should I insert it. I will be very grateful for your help and advice.

This is this code:

public class NewsActivity extends Activity {

private static final String URL = "http://10.0.2.2:8083/rest/aktualnosci";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_news);

    new FetchItems().execute();
}

private class FetchItems extends AsyncTask<String, Void, JSONArray> {

    protected JSONArray doInBackground(String... params) {
        HttpClient httpclient = new DefaultHttpClient();
        HttpGet httpget = new HttpGet(URL);
        httpget.setHeader("Content-type", "application/json");

        JSONArray json = new JSONArray();

        try {
            HttpResponse response = httpclient.execute(httpget);
                json = new JSONArray(EntityUtils.toString(response.getEntity()));
                return json;
            }

        } catch (Exception e) {
            Log.v("Błędne wczytanie", e.getMessage());
        }

        return json;
    }

    protected void onPostExecute(JSONArray result) {
        ListView lst = (ListView) findViewById(R.id.aktualnosci_list);
        ArrayList<String> listItems = new ArrayList<String>();
        String contentToEdit;
        String titleContainer;
        TextView newsHeaderTextView = null;
        for (int i = 0; i < result.length(); i++) {
            try {
                titleContainer = result.getJSONObject(i).getString("title").toString();
                listItems.add(titleContainer);
                contentToEdit=result.getJSONObject(i).getString("body").toString();
                contentToEdit= Html.fromHtml(contentToEdit).toString();
                listItems.add(contentToEdit);

            } catch (Exception e) {
                Log.v("Błędne wczytanie1", e.getMessage());
            }
        }

        ArrayAdapter ad = new ArrayAdapter(NewsActivity.this, android.R.layout.simple_list_item_1, listItems);
        lst.setAdapter(ad);
    }
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

}


You may have an EditText in your app to take some input from your user for a variety of reasons.
But it should be configured properly to handle problematic data.

For example, if you want the user to enter a number, then you should check whether the data entered in the EditText is a number or not.
In case the data entered fails your check then you should show an error message telling the user about the problem.
This process is also known as input validation.

The best method I have found to do that is using a Toast Notification which pops up on the lower half of the screen with a dark background for a short time telling the error message.
NOTE: This method is no longer the recommended method but still used by a lot of developers.

In the below code I show you how to show a Toast notification error, if the input is empty

if (inputtext.getText().toString()==null || inputtext.getText().toString().trim().equals("")){
                    Toast.makeText(getBaseContext(),"Input Field is Empty", Toast.LENGTH_LONG).show();
                }
                else{
                //do what you want with the entered text
                }

where, inputtext is an object of EditText type.
You will need to declare it(inside onCreate () in most of the cases) as follows:

EditText inputtext= (EditText)findViewById(R.id.edittext);

So basically, Toast.makeText(getBaseContext(),"Your message", Toast.LENGTH_LONG).show(); will generate the toast message and if you want to it to be displayed for some particular case, then just put the condition inside the if statement.

Manas Sharma

Ph.D. researcher at Friedrich-Schiller University Jena, Germany. I’m a physicist specializing in computational material science. I write efficient codes for simulating light-matter interactions at atomic scales. I like to develop Physics, DFT, and Machine Learning related apps and software from time to time. Can code in most of the popular languages. I like to share my knowledge in Physics and applications using this Blog and a YouTube channel.

[wpedon id=»7041″ align=»center»]

guys I have a problem with implement error handling in my application.
I want to display the error message to the user of my application when the response code from rest is not 200. In other words: If the connection is wrong, I want to display the message, that the user have to check his internet connection and try again. If everything is fine I want to do everything as usual so load the content.

I write something like this:

Toast errorToast = Toast.makeText(NewsActivity.this, "Error, pls chech your internet connection and try again!", Toast.LENGTH_SHORT);
errorToast.show();

and this:

if(response.getStatusLine().getStatusCode() == 200){}

But i don’t know If this is good code and where should I insert it. I will be very grateful for your help and advice.

This is this code:

public class NewsActivity extends Activity {

private static final String URL = "http://10.0.2.2:8083/rest/aktualnosci";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_news);

    new FetchItems().execute();
}

private class FetchItems extends AsyncTask<String, Void, JSONArray> {

    protected JSONArray doInBackground(String... params) {
        HttpClient httpclient = new DefaultHttpClient();
        HttpGet httpget = new HttpGet(URL);
        httpget.setHeader("Content-type", "application/json");

        JSONArray json = new JSONArray();

        try {
            HttpResponse response = httpclient.execute(httpget);
                json = new JSONArray(EntityUtils.toString(response.getEntity()));
                return json;
            }

        } catch (Exception e) {
            Log.v("Błędne wczytanie", e.getMessage());
        }

        return json;
    }

    protected void onPostExecute(JSONArray result) {
        ListView lst = (ListView) findViewById(R.id.aktualnosci_list);
        ArrayList<String> listItems = new ArrayList<String>();
        String contentToEdit;
        String titleContainer;
        TextView newsHeaderTextView = null;
        for (int i = 0; i < result.length(); i++) {
            try {
                titleContainer = result.getJSONObject(i).getString("title").toString();
                listItems.add(titleContainer);
                contentToEdit=result.getJSONObject(i).getString("body").toString();
                contentToEdit= Html.fromHtml(contentToEdit).toString();
                listItems.add(contentToEdit);

            } catch (Exception e) {
                Log.v("Błędne wczytanie1", e.getMessage());
            }
        }

        ArrayAdapter ad = new ArrayAdapter(NewsActivity.this, android.R.layout.simple_list_item_1, listItems);
        lst.setAdapter(ad);
    }
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

}

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:orientation="vertical"

    tools:context=".MainActivity"

    tools:ignore="HardcodedText">

    <EditText

        android:id="@+id/firstName"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_marginStart="16dp"

        android:layout_marginTop="16dp"

        android:layout_marginEnd="16dp"

        android:hint="First Name"

        android:inputType="text" />

    <EditText

        android:id="@+id/lastName"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_marginStart="16dp"

        android:layout_marginTop="16dp"

        android:layout_marginEnd="16dp"

        android:hint="Last Name"

        android:inputType="text" />

    <EditText

        android:id="@+id/email"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_marginStart="16dp"

        android:layout_marginTop="16dp"

        android:layout_marginEnd="16dp"

        android:hint="Email"

        android:inputType="textEmailAddress" />

    <EditText

        android:id="@+id/password"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_marginStart="16dp"

        android:layout_marginTop="16dp"

        android:layout_marginEnd="16dp"

        android:hint="Password"

        android:inputType="textPassword" />

    <LinearLayout

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_marginTop="8dp"

        android:gravity="end"

        android:orientation="horizontal">

        <Button

            android:id="@+id/cancelButton"

            style="@style/Widget.AppCompat.Button.Borderless"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginEnd="4dp"

            android:text="CANCEL"

            android:textColor="@color/colorPrimary" />

        <Button

            android:id="@+id/proceedButton"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginEnd="16dp"

            android:backgroundTint="@color/colorPrimary"

            android:text="PROCEED"

            android:textColor="@android:color/white"

            tools:ignore="ButtonStyle" />

    </LinearLayout>

</LinearLayout>

Alert Dialog in an android UI prompts a small window to make decision on mobile screen. Sometimes before making a decision it is required to give an alert to the user without moving to next activity. To solve this problem alert dialog came into practise. For example you have seen this type of alert when you try to exit the App and App ask you to confirm exiting.
Alert Dialog Example In Android Studio


AlertDialog.Builder Components Used In Alert Dialog

AlertDialog.Builder is used to create an interface for Alert Dialog in Android for setting like alert title, message, image, button, button onclick functionality etc.

AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);

Alert Dialog ComponentsBelow are the components of Alert Dialog:

1. setTitle(CharSequence title) – This component is used to set the title of the alert dialog. It is optional component.

  // Setting Alert Dialog Title
        alertDialogBuilder.setTitle("Confirm Exit..!!!");

2. setIcon(Drawable icon) – This component add icon before the title. You will need to save image in drawable icon.

 // Icon Of Alert Dialog
        alertDialogBuilder.setIcon(R.drawable.question);

3. setMessage(CharSequence message) – This component displays the required message in the alert dialog.

  // Setting Alert Dialog Message
        alertDialogBuilder.setMessage("Are you sure,You want to exit");

4. setCancelable(boolean cancelable) – This component has boolean value i.e true/false. If set to false it allows to cancel the dialog box by clicking on area outside the dialog else it allows.

  alertDialogBuilder.setCancelable(false);

Custom Alert Dialog Component In Android Studio
5. setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener) – This component add positive button and further with this user confirm he wants the alert dialog question to happen.

  alertDialogBuilder.setPositiveButton("yes", new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface arg0, int arg1) {
                                finish();
                            }
                        });

6. setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener) – This component add negative button and further with this user confirm he doesn’t want the alert dialog question to happen.

alertDialogBuilder.setNegativeButton("No", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                Toast.makeText(MainActivity.this,"You clicked over No",Toast.LENGTH_SHORT).show();
                            }
                        });

7. setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener) – This component simply add a new button and on this button developer can set any other onclick functionality like cancel button on alert dialog.

 alertDialogBuilder.setNeutralButton("Cancel", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                Toast.makeText(getApplicationContext(),"You clicked on Cancel",Toast.LENGTH_SHORT).show();
                            }
                         });

Alert Dialog Example In Android Studio

Below is the example of Alert Dialog in which the functionality of Alert Dialog is defined over button click. In this example we have used a simple button and on that button click the alert dialog window will appear.

Below you can download code, see final output and step by step explanation of Alert Dialog example in Android Studio.

Download Code

Alert Dialog Example In Android Studio
Step 1: Create a new project and name it AlertDialogExample.

Step 2: Open res -> layout -> activity_main.xml (or) main.xml and add following code:

Here we add the button UI on click of which alert dialog will appear. We also used textview for asking user to click on button.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.alertdialogexample.MainActivity">

    <Button
        android:text="@string/exit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/button"
        android:onClick="exit"
        android:textStyle="normal|bold" 
        style="@style/Widget.AppCompat.Button.Colored"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="131dp"/>

    <TextView
        android:text="@string/click_over_button_to_exit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="68dp"
        android:id="@+id/textView2"
        android:layout_above="@+id/button"
        android:layout_centerHorizontal="true"
        android:textSize="18sp"
        android:textStyle="normal|bold"
        android:gravity="center" />
</RelativeLayout>

Step 3 : Now open app -> java -> package -> MainActivity.java and add the below code.

In this step firstly AlertDialog.Builder is used to create a interface like setting alert title, message, image, button, button onclick functionality etc.

Important Note: Add a image to the drawable folder before setting the alert dialog icon.

package com.example.alertdialogexample;

import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void exit(View view){
        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
        // Setting Alert Dialog Title
        alertDialogBuilder.setTitle("Confirm Exit..!!!");
        // Icon Of Alert Dialog 
        alertDialogBuilder.setIcon(R.drawable.question);
        // Setting Alert Dialog Message
        alertDialogBuilder.setMessage("Are you sure,You want to exit");
        alertDialogBuilder.setCancelable(false);

                alertDialogBuilder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface arg0, int arg1) {
                                finish();
                            }
                        });

                alertDialogBuilder.setNegativeButton("No", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                Toast.makeText(MainActivity.this,"You clicked over No",Toast.LENGTH_SHORT).show();
                            }
                        });
                alertDialogBuilder.setNeutralButton("Cancel", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                Toast.makeText(getApplicationContext(),"You clicked on Cancel",Toast.LENGTH_SHORT).show();
                            }
                         });

        AlertDialog alertDialog = alertDialogBuilder.create();
        alertDialog.show();
    }
}

Output:

Now run the App and click on the button. The alert dialog will appear asking user to confirm if he wants to exit App. If user click on ‘No’, he remains in the App and if he click on ‘Yes’ the user will get exit from the App.


Custom Alert Dialog:

The custom dialog uses DIALOG to create custom alert in android studio. Dialog display a small window i.e a popup which draws the user attention over the activity before they continue moving forward. For more details read custom dialog tutorial

Alert Dialog Vs Custom Alert Dialog in Android

Continue Reading Below Tutorial

  • ExpandableListAdapter Tutorial With Example In Android Studio
  • BaseExpandableListAdapter Tutorial With Example In Android Studio
  • SimpleExpandableListAdapter Tutorial With Example In Android Studio
  • MultiAutoCompleteTextView Tutorial With Example In Android Studio
  • Switch Tutorial With Example In Android Studio

В этом уроке мы:

— рассмотрим логи приложения и всплывающие сообщения

Создадим проект:

Project name: P0121_LogAndMess
Build Target: Android 2.3.3
Application name: LogAndMess
Package name: ru.startandroid.develop.logandmess
Create Activity: MainActivity

Создадим в main.xml экран, знакомый нам по прошлым урокам про обработчики:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:orientation="horizontal">
    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_margin="30dp">
        <TextView
            android:layout_width="wrap_content"
            android:text="TextView"
            android:layout_height="wrap_content"
            android:id="@+id/tvOut"
            android:layout_gravity="center_horizontal"
            android:layout_marginBottom="50dp">
        </TextView>
        <Button
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:id="@+id/btnOk"
            android:text="OK"
            android:layout_width="100dp">
        </Button>
        <Button
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:id="@+id/btnCancel"
            android:text="Cancel"
            android:layout_width="100dp">
        </Button>
    </LinearLayout>
</LinearLayout>

Алгоритм приложения будет тот же. По нажатию кнопок меняется текст. Обработчик  — Activity.

public class MainActivity extends Activity implements OnClickListener {

  TextView tvOut;
  Button btnOk;
  Button btnCancel;

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    // найдем View-элементы
    tvOut = (TextView) findViewById(R.id.tvOut);
    btnOk = (Button) findViewById(R.id.btnOk);
    btnCancel = (Button) findViewById(R.id.btnCancel);

    // присваиваем обработчик кнопкам
    btnOk.setOnClickListener(this);
    btnCancel.setOnClickListener(this);
  }

  @Override
  public void onClick(View v) {
    // по id определяем кнопку, вызвавшую этот обработчик
    switch (v.getId()) {
    case R.id.btnOk:
      // кнопка ОК
      tvOut.setText("Нажата кнопка ОК");
      break;
    case R.id.btnCancel:
      // кнопка Cancel
      tvOut.setText("Нажата кнопка Cancel");
      break;
    }
  }

}

Сохраним, запустим. Убедимся, что все работает.

Логи приложения

Когда вы тестируете работу приложения, вы можете видеть логи работы. Они отображаются в окне LogCat. Чтобы отобразить окно откройте меню Window > Show View > Other … В появившемся окне выберите Android > LogCat

Должна появится вкладка LogCat

Рассмотрим эту вкладку подробней. Логи имеют разные уровни важности: ERROR, WARN, INFO, DEBUG, VERBOSE (по убыванию). Кнопки V D I W E (в кружках) – это фильтры и соответствуют типам логов. Опробуйте их и обратите внимание, что фильтр показывает логи не только своего уровня, но и уровней более высокой важности. Также вы можете создавать, редактировать и удалять свои фильтры – это мы рассмотрим чуть дальше.

Давайте смотреть, как самим писать логи. Делается это совсем несложно с помощью класса Log и его методов Log.v() Log.d() Log.i() Log.w() and Log.e(). Названия методов соответствуют уровню логов, которые они запишут.

Изменим код MainActivity.java. Возьмем все каменты из кода и добавим в DEBUG-логи с помощью метода Log.d. Метод требует на вход тэг и текст сообщения. Тэг – это что-то типа метки, чтобы легче было потом в куче системных логов найти именно наше сообщение. Добавим описание тега (TAG) и запишем все тексты каментов в лог.

public class MainActivity extends Activity implements OnClickListener {

  TextView tvOut;
  Button btnOk;
  Button btnCancel;

  private static final String TAG = "myLogs";

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    // найдем View-элементы
    Log.d(TAG, "найдем View-элементы");
    tvOut = (TextView) findViewById(R.id.tvOut);
    btnOk = (Button) findViewById(R.id.btnOk);
    btnCancel = (Button) findViewById(R.id.btnCancel);

    // присваиваем обработчик кнопкам
    Log.d(TAG, "присваиваем обработчик кнопкам");
    btnOk.setOnClickListener(this);
    btnCancel.setOnClickListener(this);
  }

  @Override
  public void onClick(View v) {
    // по id определяем кнопку, вызвавшую этот обработчик
    Log.d(TAG, "по id определяем кнопку, вызвавшую этот обработчик");
    switch (v.getId()) {
    case R.id.btnOk:
      // кнопка ОК
      Log.d(TAG, "кнопка ОК");
      tvOut.setText("Нажата кнопка ОК");
      break;
    case R.id.btnCancel:
      // кнопка Cancel
      Log.d(TAG, "кнопка Cancel");
      tvOut.setText("Нажата кнопка Cancel");
      break;
    }
  }

}

Eclipse ругнется, что не знает класс Log. Обновите импорт (CTRL+SHIFT+O) и, если спросит, выберите android.util.Log. Запустим приложение, понажимаем кнопки и посмотрим логи

Видно, что все отлично записалось. Чтобы сделать просмотр удобней, создадим свой фильтр. Жмем значок +

Имя фильтра произвольное, например, «My logs».  Log Tag – это как раз значение константы TAG, которая описана в нашем коде и использовалась в методе Log.d, т.е. — «myLogs«. Pid оставляем пустым, это id процесса. Уровень поставим Debug

и жмем OK. Появилась новая вкладка My logs, на которой отображаются логи, соответствующие только что созданному фильтру.

Мы помещали в лог текст, но разумеется, вы можете писать, например, значения интересующих вас переменных (приведенные к типу String).

Иногда бывает, что логи не отображаются во вкладке LogCat, хотя AVD запущен, приложение работает без проблем. В таком случае должно помочь следующее: в Eclipse идем в меню Window > Open Perspective > Other > DDMS. Откроется немного другой набор окон чем обычно. Там найдите вкладку Devices и в ней должно быть видно ваше AVD-устройство, кликните на него и логи должны появиться. Чтобы вернуться в разработку: Window > Open Perspective > Java.

Всплывающие сообщения

Приложение может показывать всплывающие сообщения с помощью класса Toast. Давайте подредактируем метод onClick. Сделаем так, чтобы всплывало сообщение о том, какая кнопка была нажата.

  public void onClick(View v) {
    // по id определяем кнопку, вызвавшую этот обработчик
    Log.d(TAG, "по id определяем кнопку, вызвавшую этот обработчик");
    switch (v.getId()) {
    case R.id.btnOk:
      // кнопка ОК
      Log.d(TAG, "кнопка ОК");
      tvOut.setText("Нажата кнопка ОК");
      Toast.makeText(this, "Нажата кнопка ОК", Toast.LENGTH_LONG).show();
      break;
    case R.id.btnCancel:
      // кнопка Cancel
      Log.d(TAG, "кнопка Cancel");
      tvOut.setText("Нажата кнопка Cancel");
      Toast.makeText(this, "Нажата кнопка Cancel", Toast.LENGTH_LONG).show();
      break;
    }
  }

Разберем синтаксис вызова. Статический метод makeText создает View-элемент Toast. Параметры метода:

context – пока не будем вдаваться в подробности, что это такое и используем текущую Activity, т.е. this.
text – текст, который надо показать
duration – продолжительность показа (Toast.LENGTH_LONG — длинная, Toast.LENGTH_SHORT — короткая)

Toast создан и чтобы он отобразился на экране, вызывается метод show(). Сохраняем, запускаем, проверяем.

Если у вас есть Андроид-смартфон, я думаю вы уже видели подобные сообщения. Теперь вы знаете, как это делается )

На следующем уроке:

— создаем пункты меню


Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance 

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня


Пользователям часто нужны напоминания,
которые будут указывать на выбор или
ошибки. Для этого в Android есть специальная
встроенная программа, которая гибко
настраивается под любые задачи – android
studio всплывающее окно. При помощи сервиса
удается экономить память и другие
ресурсы, создавая заголовки, информационный
массив, клавиши и прочее.

Что такое
Android Studio? Это специальная среда
IDE, которая позволит работать, настраивать
и управлять операционной системой
Android.

Android Studio: всплывающее диалоговое окно AlertDialog

С одной клавишей

Для начала
следует разобраться с легким примером,
в котором используется только 1 клавиша.
Первым делом формируется
объем AlertDialog.Builder, передающий в виде
примера контекст. После в работу входит
техника Builder и формируется для всплывающего
меню заголовок, используя команду
setTitle(). Для текста подходит способ
setMessage(), установка значка формируется
в виде setIcon(). Чтобы установить клавишу,
применяется техника setNegativeButton(), а
обеспечить возможность нажатия на
сделанную кнопку поможет комбинация
cancel(). Обращать внимание на название
техник не нужно, они не несут большой
нагрузки.

android studio всплывающее окно

Для исключения
закрытия диалогового окна при помощи
кнопки возврата на смартфоне, применяется
метод setCancelable() со значением false. В
самом конце требуется добиться всплывания
окна при помощи команды show(). Например:

public void onClick(View v) {
    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
    builder.setTitle("Важное сообщение!")
            .setMessage("Закройте окно!")
            .setIcon(R.drawable.ic_android_cat)
            .setCancelable(false)
            .setNegativeButton("ОК, иду на балкон",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            dialog.cancel();
                        }
                    });
    AlertDialog alert = builder.create();
    alert.show();
}

Особенности создания и пример с 2 клавишами

На основе кода видно пример формирования диалогового окна с наличием 2 клавиш для использования:

package ru.alexanderklimov.alertdialogdemo;

import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity {

    AlertDialog.Builder ad;
    Context context;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        context = MainActivity.this;
        String title = "Выбор есть всегда";
        String message = "Выберите одежду";
        String button1String = "Удобная одежда";
        String button2String = "Красивая одежда";
        
        ad = new AlertDialog.Builder(context);
        ad.setTitle(title);  // заголовок
        ad.setMessage(message); // сообщение
        ad.setPositiveButton(button1String, new OnClickListener() {
            public void onClick(DialogInterface dialog, int arg1) {
                Toast.makeText(context, "Вы сделали правильный выбор",
                        Toast.LENGTH_LONG).show();
            }
        });
        ad.setNegativeButton(button2String, new OnClickListener() {
            public void onClick(DialogInterface dialog, int arg1) {
                Toast.makeText(context, "Возможно вы правы", Toast.LENGTH_LONG)
                        .show();
            }
        });
        ad.setCancelable(true);
        ad.setOnCancelListener(new OnCancelListener() {
            public void onCancel(DialogInterface dialog) {
                Toast.makeText(context, "Вы ничего не выбрали",
                        Toast.LENGTH_LONG).show();
            }
        });
    }

    public void onClick(View v) {
        ad.show();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
}

Общие параметры кода не меняются, прежними будут настройки, клавиши и обработка информации. Доступно добавлять в AlertDialog только по 1 клавише любого вида, поэтому в окне будет максимум 3 кнопки для использования.

android studio alertdialog

Для каждого показателя применяются методы со вставкой set…Button, принимающие за основу подпись и внешний вид DialogInterface.OnClickListener, характеризующий операцию при касании. Чтобы исключить закрытие с помощью клавиатуры смартфона, в коде прописывается setCancelable() со значением false или true. Чтобы результат работы отобразился на экране, применяется способ show().

AlertDialog – гибкая программа для настроек. Всплывающее окно бывает самым простым с классическим выбором «Да» и «Нет», но при помощи перечня, флажков или переключателей, конструкция будет усложняться.

Метод onCreateDialog в AlertDialog

Чтобы при помощи android studio alertdialog сохранило состояние, потребуется применять способ активности onCreateDialog(). Для начала выполняются описанные этапы, а для показа работы указывается builder.create(). Пример кода:

package ru.alexanderklimov.alertdialogdemo;

import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity {

    AlertDialog.Builder ad;
    Context context;
    
    // идентификатор диалогового окна AlertDialog с кнопками
    private final int IDD_THREE_BUTTONS = 0;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

       ...
    }

    public void onClick(View v) {
        //ad.show();
        showDialog(IDD_THREE_BUTTONS); 
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {
        case IDD_THREE_BUTTONS:
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setMessage("Выберите правильный ответ")
                    .setCancelable(false)
                    .setPositiveButton("Да",
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog,
                                        int id) {
                                    dialog.cancel();
                                }
                            })
                    .setNeutralButton("Не знаю",
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog,
                                        int id) {
                                    dialog.cancel();
                                }
                            })
                    .setNegativeButton("Нет",
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog,
                                        int id) {
                                    dialog.cancel();
                                }
                            });
            
            return builder.create();
        default:
            return null;
        }
    }
}

Поскольку в одном приложении применяется сразу несколько типов диалоговых окон, потребуется сделать отдельный идентификатор, который поможет вызывать конкретный диалог. Работая на новой ОС Android видно, что метод показа всплывающего окна перечеркнут, поскольку он устаревший. С версии 3.0 пользуются техникой DialogFragment. Для проекта идентификатором выступает IDD_THREE_BUTTONS.

android studio dialog

AlertDialog с перечнем

Некоторым пользователям важно использовать окна, в которых будет список с несколькими строками на выбор. Они заменяют клавиши, и для этого в коде применяют способ setItems(). В нем указывается часть информации для вывода на экран и dialogInterface.OnClickListener, позволяющий выбрать действие, во время выбора конкретной части из перечня. Для этого готовый код дополняется еще одной клавишей:

private final int IDD_LIST_CATS = 1;

public void onClick(View v) {
    switch (v.getId()) {
    ...
    case R.id.button2:
        showDialog(IDD_LIST_CATS);
        break;
    ...
}

@Override
protected Dialog onCreateDialog(int id) {
    switch (id) {
    ...

    case IDD_LIST_CATS:
        
        final String[] mCatsName ={"Тимка", "Пушок", "Кузя"};

        builder = new AlertDialog.Builder(this);
        builder.setTitle("Выбираем кота"); // заголовок для диалога

        builder.setItems(mCatsName, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int item) {
                // TODO Auto-generated method stub
                Toast.makeText(getApplicationContext(),
                        "Выбранный кот: " + mCatsName[item],
                        Toast.LENGTH_SHORT).show();
            }
        });
        builder.setCancelable(false);
        return builder.create();
        
    default:
        return null;
    }
}

После выполнения проекта android studio alertdialog со списком, проводится запуск для проверки. Во время контакта с клавишей должно быть окно AlertDialog, в котором содержится перечень из 3 наименований, помогающий выбрать имя питомца. После касания одного выплывает сообщение, демонстрирующее выбранного питомца.

android studio диалоговое окно

AlertDialog с переключателями

Всплывающее меню можно сделать с переключателями RadioButton. Для этого применяется техника setSingleChoiceitems() взамен способу setItems(). Если при помощи android studio диалоговое окно делается внутри onCreateDialog(), тогда операционная система Андроид будет управлять состоянием перечня при помощи переключателей. На момент активной работы, меню при дальнейших вызовах сохранит в памяти, ранее выбранные строки.

private final int IDD_RADIO_CATS = 2;

// часть кода из onCreateDialog()
case IDD_RADIO_CATS:
    
    final String[] mChooseCats = { "Тимка", "Пушок", "Кузя" };
    builder = new AlertDialog.Builder(this);
    builder.setTitle("Выберите любимое имя кота")
            .setCancelable(false)

            // добавляем одну кнопку для закрытия диалога
            .setNeutralButton("Назад",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog,
                                int id) {
                            dialog.cancel();
                        }
                    })

            // добавляем переключатели
            .setSingleChoiceItems(mChooseCats, -1,
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog,
                                int item) {
                            Toast.makeText(
                                    getApplicationContext(),
                                    "Любимое имя кота: "
                                            + mChooseCats[item],
                                    Toast.LENGTH_SHORT).show();
                        }
                    });
    return builder.create();

Создавая проект нужно обратить внимание на детали. Когда выбирается переключатель, всплывающее окно не будет закрываться, нужно заранее продумать этот момент и технику закрытия. К примеру, возможно добавить клавишу. Вторым фактором при использовании способа setSingleChoiceitems выступает то, что для первого значения применяется полный код и настройки, а для второго нужно применить целочисленный показатель индекса, оставляя его включенным всегда при всплывании окна. Значение «-1» применяется для отключения переключателей во время старта окна.

android studio alertdialog со списком

AlertDialog с флажками

Описанные переключатели возможно заменить флажками, которые называются CheckBox. Чтобы получить доступ к выбору параметров, необходимо применить код setMultiChoiceItems(). Визуально изменений почти нет, а детали можно просмотреть в самом коде:

private final int IDD_CHECK_CATS = 3;

// часть кода из onCreateDialog()
case IDD_CHECK_CATS:
    final boolean[] mCheckedItems = { false, true, false };
    final String[] checkCatsName = { "Тимка", "Пушок", "Кузя" };
    builder = new AlertDialog.Builder(this);
    builder.setTitle("Выберите котов")
            .setCancelable(false)

            .setMultiChoiceItems(checkCatsName, mCheckedItems,
                    new DialogInterface.OnMultiChoiceClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog,
                                int which, boolean isChecked) {
                            mCheckedItems[which] = isChecked;
                        }
                    })

            // Добавляем кнопки
            .setPositiveButton("Готово",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog,
                                int id) {
                            StringBuilder state = new StringBuilder();
                            for (int i = 0; i < checkCatsName.length; i++) {
                                state.append("" + checkCatsName[i]);
                                if (mCheckedItems[i])
                                    state.append(" выбранn");
                                else
                                    state.append(" не выбранn");
                            }
                            Toast.makeText(getApplicationContext(),
                                    state.toString(), Toast.LENGTH_LONG)
                                    .show();
                        }
                    })

            .setNegativeButton("Отмена",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog,
                                int id) {
                            dialog.cancel();

                        }
                    });
    return builder.create();

Первое значение в способе setMultiChoiceItems() выступает массивом настроек для перечня с флажками.

Android Studio: всплывающее диалоговое окно AlertDialog

Второе считается булевым массивом состояний, заданных по стандартным настройкам при вызове окна. К примеру, чтобы отметить флажком вторую строку, а другие оставить без изменений, используется код:

final boolean[] mCheckedItems = {false, true, false};

По аналогии с переключателями для всплывающего меню с флажками потребуется применять клавиши для закрытия меню. В запущенном приложении сохраняется предыдущий параметр состояния.

Автоматическое закрытие окна

Обычные сообщения класса Toast закрываются через 1-2 секунды, но диалоговые окна не будут самостоятельно закрываться, пока пользователь не сделает манипуляцию.

Android Studio: всплывающее диалоговое окно AlertDialog

При использовании таймера можно убрать ограничение, добавляя клавишу автоматического закрытия. Для этого используется специальный код.

public void onClick(View v) {
    AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());
    builder.setTitle("Автоматическое закрытие окна");
    builder.setMessage("Через пять секунд это окно закроется автоматически!");
    builder.setCancelable(true);

    final AlertDialog dlg = builder.create();

    dlg.show();

    final Timer timer = new Timer();
    timer.schedule(new TimerTask() {
        public void run() {
            dlg.dismiss(); // when the task active then close the dialog
            timer.cancel(); // also just top the timer thread, otherwise,
                            // you may receive a crash report
        }
    }, 5000); // через 5 секунд (5000 миллисекунд), the task will be active.
}

AlertDialog с рейтингом (проблемный пример)

Применение метода RatingBar для диалогового окна приводит к некорректной работе кода. На дисплее смартфона всегда всплывает 6 звездочек, невзирая на заданные параметры. Если перевернуть приложение в альбомную ориентацию, то будет показано от 7 звездочек, исходя из диагонали.

Android Studio: всплывающее диалоговое окно AlertDialog

public TextView txtView;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_test);

    txtView = (TextView) findViewById(R.id.textView1);

}

public void onClick(View v) {
    showRatingDialog();
}

public void showRatingDialog() {
    final AlertDialog.Builder ratingdialog = new AlertDialog.Builder(this);
    final RatingBar rating = new RatingBar(this);
    
    ratingdialog.setIcon(android.R.drawable.btn_star_big_on);
    ratingdialog.setTitle("Голосуем за любимое имя!");
    ratingdialog.setView(rating);
    rating.setMax(5);
    rating.setNumStars(5);
    rating.setStepSize((float) 1.0);

    ratingdialog.setPositiveButton("Готово",
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    txtView.setText(String.valueOf(rating.getRating()));
                    dialog.dismiss();
                }
            })

            .setNegativeButton("Отмена",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            dialog.cancel();
                        }
                    });

    ratingdialog.create();
    ratingdialog.show();
}

Для решения проблемы нужно элемент RatingBar поместить в макете wrap_content. Рекомендуется сделать отдельную разметку, с подключением ее к всплывающему окну. Для открытия доступа к настройкам элемента используется метод View.findViewById().

Следует избегать ProgressDialog

Android studio dialog – стандартный класс для всех всплывающих окон. ProgressDialog – это расширение, но оно тоже имеет специальные клавиши, а также индикатор выполненных задач. Но если потребуется показать процесс загрузки или любой другой информации, тогда используется отдельная инструкция по дизайну, что позволяет применять расширение в созданном макете.

Android Studio: всплывающее диалоговое окно AlertDialog

Все классы позволяют установить стиль, структуру диалогового окна, но для этого применяется DialogFragment, как отдельный элемент. Эта группа дает возможность работы со всеми функциями, которые требуются для формирования всплывающих окон, их дизайном, вместо вызова способов к объекту Dialog.

Применение в работе для управления DialogFragment позволяет добиться корректной обработки жизненных событий в определенное время, поскольку можно задать дополнительные клавиши «Назад» или повернуть экран. Еще класс позволяет повторно использовать интерфейс в виде встраиваемого элемента высшего уровня, по аналогии с классом Fragment. Это требуется при необходимости разного отображения окон на экранах больших и малых устройств.

В результате того, что описанный класс первоначально есть в Android 3.0, в нем будет описано применение класса DialogFragment, которое есть в Библиотеке поддержки. После ее добавления можно воспользоваться самим классом и другими API на гаджетах под управлением ОС Android 1.6 и выше. Если применяются вспомогательные библиотеки, рекомендуется провести импорт класса android.support.v4.app.DialogFragment, но не использовать android.app.DialogFragment.

На видео детально представлены диалоговые окна и программирование Андроид:

Ошибки в Android приложениях — неотъемлемая часть любой разработки, то насколько быстро разработчик находит баг влияет на скорость создания мобильного приложения, а то, насколько точно получается локализовать проблему — на качество конечного продукта. Давайте рассмотрим подходы и инструменты, которые помогают при дебаге.

ADB = Android Debug Bridge

Все общение с подключенным устройством или эмулятором происходит через утилиту командной строки ADB (Android Debug Bridge) — данный инструмент входит в Android SDK и скачать его можно на официальной странице.

Debugger в Android Studio

Посмотреть как программа себя ведет по шагам, какие значения принимают переменные и т.д. позволяет debugger, встроенный в среду разработки Android Studio.

Что такое Stacktrace

Stacktrace — это последовательность вызовов, которая привела до определенного момента в коде. Когда приложение крэшится, то, чтобы понять почему это произошло, зачастую, достаточно открыть Logcat и посмотреть stacktrace. В нем будет информация, что, где и почему упало.

StackTrace в Android StudioВ данном примере видно, что на 63 строке в классе SingleBankConnectedFragment произошел IllegalStateException.

StackTrace и Proguard

Важное замечание — если вы обфусцировали ваше приложение и оно упало уже после этого, то логи читать чуть чуть сложнее. Есть и хорошая новость — при сборке приложения создается mapping файл, в котором указывается какие классы как стали называться. В Google play developer console например можно этот файл даже загрузить, чтобы расшифровка логов происходила автоматически.

Breakpoint

Breakpoint, или по-русски «Точка останова» — флаг, устанавливающийся на определенную строчку-инструкцию в программе. Она говорит, что в этом месте исполнение приложения надо поставить на паузу. После этого разработчик сможет посмотреть значения переменных в данный момент для поиска багов. Далее надо решить — пойти ли дальше по шагам, зайти ли внутрь очередной функции или просто возобновить исполнение.

Для того, чтобы установить Breakpoint достаточно нажать на область рядом с номером строки

Debug ошибок в андроид приложениях

Чтобы запустить программу в debug режиме, есть специальная кнопка в панели Android studio

Debug ошибок в андроид приложениях

Также можно подключиться к уже выполняющемуся процессу

Debug ошибок в андроид приложениях

Когда процесс остановится в указанной точке можно перейти к следующей инструкции (строчке в программе). Также можно зайти внутрь функции, если в данный момент времени находимся на строчке ее вызова.

Debug ошибок в андроид приложениях

Вычисление значений на лету

В режиме дебага, находясь на определенной строке можно посмотреть состояние программы в данный момент. То, какие переменные какие значения принимают.

Debug ошибок в андроид приложениях

Также можно произвести любые вычисления в данном контексте

Debug ошибок в андроид приложениях

Подмена значений переменных на лету

Иногда полезно подменить значение переменной прямо на лету. Например, когда отображение в интерфейсе зависит от переменной. Тогда удобно, не перекомпилируя приложение или изменяя значения в базе данных, посмотреть как будет выглядеть UI при разных значениях. Это можно сделать прямо из окна мониторинга переменных

Debug ошибок в андроид приложениях

Условный Breakpoint

Не всегда необходимо всегда останавливать выполнение программы на определенной строке. К примеру, если хотим продебажить тело цикла, в котором много итераций и нам интересна только та, на которой выполняется определенное условие. Для таких целей точке останова можно задать условие:

Debug ошибок в андроид приложениях

программа остановится, только если выполнится условие для данного Breakpoint.

Layout inspector в Android Studio для дебага View

В Android Studio есть одна очень полезная вещь для дебага — Layout inspector. Он позволяет просмотреть UI открытой активности к разрезе отдельных View. Это бывает удобно, особенно если

  • Необходимо отдебажить код, связанный с определенным интерфейсом — можно быстро найти нужные id view и перейти в IDE в нужный участок кода,
  • Проблема связана с отображением интерфейса — можно посмотреть где какие элементы располагаются, что мешают друг другу и тд.

Layout inspector вызывается из меню Tools -> Layout inspector

Debug ошибок в андроид приложениях

Инструмент позволяет прямо в Android studio видеть элементы интерфейса запущенного Android приложения, посмотреть свойства отдельно взятого View и увидеть целиком иерархию конкретно взятого интерфейса

Debug ошибок в андроид приложениях

Логи как средство для дебага

Когда дело касается порядка вызова методов, особенно когда методы асинхронные, бегать по коду в режиме дебага не удобно. Тогда на помощь приходят логи и android logcat. Инструмент, позволяющий получить логи из android приложения.

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

Hint: для удобства и ускорения работы с логами, можно использовать Live template в Android Studio

Мой шаблон для расстановки логов с именем logs выглядит так

Log.e("!@#", "$package$.$method$:$line$");

Вывод в канал ошибок лога с тэгом !@#, что позволяет легко его отфильтровать и сообщением, которое содержит имя пакета, класс и строку.

Находясь на нужной строчке остается нажать Ctrl + J (вызов диалога добавления шаблона), написать logs и нажать Enter

Debug ошибок в андроид приложениях

И IDE сама добавит строку, вида

Log.e("!@#", "com.package.test.MyActivity:64");

Сетевой мониторинг

Когда дело доходит до взаимодействия с сервером, не всегда ошибка на стороне клиента. В процессе разработки всегда стоит включать логирование сетевый запросов и ответов в Logcat.

Okhttp

Okhttp — популярный HTTP клиент, который позволяет включить логирование сетевых запросов практически из коробки.

Добавляем в проект библиотеку logging-interceptor

implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'

и при конфигурировании Okhttp клиента добавляем нужный interceptor, а для того, чтобы логи не попали в релизную версию наверняка, условием добавления логирования сетевых запросов можно определить как сборка Debug версии приложения

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (BuildConfig.DEBUG) {
  builder.addInterceptor(logging);
}
OkHttpClient client = builder.build();

Retrofit

Retrofit часто используется при создании клиент-серверных приложений. Для того, чтобы включить логирование сетевых запросов, достаточно лишь указать клиентом в Retrofit Okhttp, настроенный как описано выше

builder.client(okHttpClient);

Fiddler, Charles и другие прокси

Отследить сетевой траффик также можно с помощью специализированных программ, проксирующие через себя траффик мобильного приложения, например такие как Fiddler, Charles и другие.

Debug обфусцированного кода

При дебаге кода после обфускации надо помнить, что номера строк и имена методов не совпадают с тем, что вы видите в исходниках. При сборке будет создан map file, который поможет соотнести stracktrace в продакшене с вашим кодом.

Вы теперь в курсе как отладить приложение. Время узнать какие полезные инструменты есть для его создания.

Вступление

Тост обеспечивает простую обратную связь о операции в небольшом всплывающем окне и автоматически исчезает после таймаута. Он заполняет объем пространства, необходимый для сообщения, и текущая активность остается видимой и интерактивной.

Синтаксис

  • Toast makeText (контекст контекста, текст CharSequence, int duration)
  • Toast makeText (контекст контекста, int resId, int duration)
  • void setGravity (int gravity, int xOffset, int yOffset)
  • void show ()

параметры

параметр подробности
контекст Контекст для отображения вашего Toast in. this обычно используется в Activity, а getActivity() обычно используется в фрагменте
текст CharSequence, который указывает, какой текст будет показан в Toast. Любой объект, реализующий CharSequence, может использоваться, включая String
RESID Идентификатор ресурса, который может использоваться для предоставления ресурса Строка для отображения в Toast
продолжительность Целочисленный флаг, показывающий, как долго будет отображаться тост. Параметры: Toast.LENGTH_SHORT и Toast.LENGTH_LONG
сила тяжести Целое число, определяющее позицию или «гравитацию» Тоста. См. Параметры здесь
xOffset Задает горизонтальное смещение для позиции Toast
YOffset Определяет вертикальное смещение для позиции Toast

замечания

Тост обеспечивает простую обратную связь об операции в небольшом всплывающем окне. Он заполняет объем пространства, необходимый для сообщения, и текущая активность остается видимой и интерактивной.

Более поздняя альтернатива Toast — SnackBar. SnackBar предлагает обновленный визуальный стиль и позволяет пользователю отклонить сообщение или предпринять дальнейшие действия. Подробности см. В документации SnackBar .

Официальная документация:

https://developer.android.com/reference/android/widget/Toast.html

Установить положение тоста

Стандартное уведомление тоста появляется в нижней части экрана, выровненного в горизонтальном центре. Вы можете изменить эту позицию с помощью setGravity(int, int, int) . Он принимает три параметра: константу силы тяжести, смещение по оси x и смещение позиции y.

Например, если вы решите, что тост должен появиться в верхнем левом углу, вы можете установить гравитацию следующим образом:

toast.setGravity(Gravity.TOP|Gravity.LEFT, 0, 0);

Отображение сообщения о Toast

В Android, Toast — это простой элемент пользовательского интерфейса, который может использоваться для предоставления контекстной обратной связи пользователю.

Чтобы отобразить простое сообщение Toast, мы можем сделать следующее.

// Declare the parameters to use for the Toast

Context context = getApplicationContext(); 
// in an Activity, you may also use "this"
// in a fragment, you can use getActivity()

CharSequence message = "I'm an Android Toast!";
int duration = Toast.LENGTH_LONG; // Toast.LENGTH_SHORT is the other option

// Create the Toast object, and show it!
Toast myToast = Toast.makeText(context, message, duration);
myToast.show();

Или, чтобы показать Toast inline, не удерживая объект Toast, вы можете:

Toast.makeText(context, "Ding! Your Toast is ready.", Toast.LENGTH_SHORT).show();

ВАЖНО: Убедитесь, что метод show() вызывается из потока пользовательского интерфейса. Если вы пытаетесь показать Toast из другого потока, вы можете, например, использовать метод runOnUiThread для Activity .

В противном случае, имея в виду попытку изменить пользовательский интерфейс, создав Toast, вы получите RuntimeException которое будет выглядеть следующим образом:

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

Самый простой способ обработки этого исключения — просто использовать runOnUiThread: синтаксис показан ниже.

   runOnUiThread(new Runnable() {
        @Override
        public void run() {
            // Your code here
        }
    });

Создание пользовательского тоста

Если вы не хотите использовать представление Toast по умолчанию, вы можете предоставить свой собственный, используя метод setView(View) на объекте Toast .

Во-первых, создайте XML-макет, который вы хотели бы использовать в своем Toast.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/toast_layout_root"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="8dp"
    android:background="#111">

    <TextView android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#FFF"/>

    <TextView android:id="@+id/description"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#FFF"/>

</LinearLayout>

Затем, создавая свой тост, надуйте свой собственный вид из XML и вызовите setView

// Inflate the custom view from XML
LayoutInflater inflater = getLayoutInflater();
View layout = inflater.inflate(R.layout.custom_toast_layout,
                               (ViewGroup) findViewById(R.id.toast_layout_root));

// Set the title and description TextViews from our custom layout
TextView title = (TextView) layout.findViewById(R.id.title);
title.setText("Toast Title");

TextView description = (TextView) layout.findViewById(R.id.description);
description.setText("Toast Description");

// Create and show the Toast object

Toast toast = new Toast(getApplicationContext());
toast.setGravity(Gravity.CENTER, 0, 0);
toast.setDuration(Toast.LENGTH_LONG);
toast.setView(layout);
toast.show();

Реальный безопасный способ отображения Toast (Application Wide)

public class MainApplication extends Application {
    
    private static Context context; //application context

    private Handler mainThreadHandler;
    private Toast toast;

    public Handler getMainThreadHandler() {
        if (mainThreadHandler == null) {
            mainThreadHandler = new Handler(Looper.getMainLooper());
        }
        return mainThreadHandler;
    }

    @Override public void onCreate() {
        super.onCreate();
        context = this;
    }
       
    public static MainApplication getApp(){
        return (MainApplication) context;
    }

    /**
     * Thread safe way of displaying toast.
     * @param message
     * @param duration
     */
    public void showToast(final String message, final int duration) {
        getMainThreadHandler().post(new Runnable() {
            @Override
            public void run() {
                if (!TextUtils.isEmpty(message)) {
                    if (toast != null) {
                        toast.cancel(); //dismiss current toast if visible
                        toast.setText(message);
                    } else {
                        toast = Toast.makeText(App.this, message, duration);
                    }
                    toast.show();
                }
            }
        });
    }

Не забудьте добавить MainApplication в manifest .

Теперь вызовите его из любого потока, чтобы отобразить тост-сообщение.

MainApplication.getApp().showToast("Some message", Toast.LENGTH_LONG);

Показать сообщение с тостами над мягкой клавиатурой

По умолчанию Android отображает сообщения Toast в нижней части экрана, даже если клавиатура отображается. Это покажет сообщение Toast чуть выше клавиатуры.

public void showMessage(final String message, final int length) {
    View root = findViewById(android.R.id.content);
    Toast toast = Toast.makeText(this, message, length);
    int yOffset = Math.max(0, root.getHeight() - toast.getYOffset());
    toast.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, yOffset);
    toast.show();
}

Thread безопасный способ отображения сообщения Toast (для AsyncTask)

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

public class MyAsyncTask extends AsyncTask <Void, Void, Void> {

    @Override
    protected Void doInBackground(Void... params) {
        // Do your background work here
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        // Show toast messages here
        Toast.makeText(context, "Ding! Your Toast is ready.",   Toast.LENGTH_SHORT).show();
    }
    
}

There could be many ways of handling API responses coming from servers in android but do you use a good way of handling it? In this article, we’ll see API responses handled with the help of Kotlin Sealed Class while using the Retrofit library for API calls. This sealed class approach fits perfectly in this case: If the user is expecting data in UI, then we need to send the errors all the way to our UI to notify the user & to make sure the user won’t just see a blank screen or experience unexpected UI.

Make Sealed Class

Note: We are following MVVM Architecture and using Retrofit with Kotlin Coroutines for api calls in background.

Just create a generic sealed class named Resource in a separate file in your data package or utils/others package. We have named it Resource & created it generic because we’ll use this class to wrap our different types of API responses. Basically, we need to update our UI on these three events i.e. Success, Error, Loading. So, we have created these as child classes of Resources to represent different states of UI. Now, in case of success, we’ll get data so we’ll wrap it with Resource. Success and in case of error, we’ll wrap the error message with Resource. Error & in case of loading we’ll just return Resource.Loading object (you can also alter it to wrap your loading data according to your needs).

Kotlin

sealed class Resource<T>(

    val data: T? = null,

    val message: String? = null

) {

    class Success<T>(data: T) : Resource<T>(data = data)

    class Error<T>(errorMessage: String) : Resource<T>(message = errorMessage)

    class Loading<T> : Resource<T>()

}

Let’s also have a look at our ApiService Interface (see just below), here in every suspended API call function we are wrapping our API call response with Retrofit’s Response class because it provides us some extra info about API calls. For example: whether calls getting successful or not, error code, etc. We’ll call these suspended functions from our repositories… we’ll see that in while. Don’t get confused in our custom Resource class and Retrofit’s Response class. Resource class just represents different states of UI while Retrofit’s Response class gives us extra info about API calls.

Kotlin

interface ExampleApiService {

    @GET("example/popular_articles")

    suspend fun fetchPopularArticles(): Response<PopularArticlesResponse>

    @GET("example/new_articles")

    suspend fun fetchNewArticles(): Response<NewArticlesResponse>

}

Now let’s jump on to the main part of API success/error handling

You must be having different repositories in your project according to your needs and all your api calls must be happening through these repositories we need to do error handling of each & every API call. So, we need to wrap each API call inside the try-catch block. But wait… writing a try-catch block for every api call isn’t a good idea. So, let’s create a BaseRepository & write a common suspend function there named safeApiCall  (any name which you like) which will be responsible to handle api responses of each & every api call.

Kotlin

abstract class BaseRepo() {

    suspend fun <T> safeApiCall(apiToBeCalled: suspend () -> Response<T>): Resource<T> {

        return withContext(Dispatchers.IO) {

            try {

                val response: Response<T> = apiToBeCalled()

                if (response.isSuccessful) {

                    Resource.Success(data = response.body()!!)

                } else {

                    val errorResponse: ExampleErrorResponse? = convertErrorBody(response.errorBody())

                    Resource.Error(errorMessage = errorResponse?.failureMessage ?: "Something went wrong")

                }

            } catch (e: HttpException) {

                Resource.Error(errorMessage = e.message ?: "Something went wrong")

            } catch (e: IOException) {

                Resource.Error("Please check your network connection")

            } catch (e: Exception) {

                Resource.Error(errorMessage = "Something went wrong")

            

        }

    }

    private fun convertErrorBody(errorBody: ResponseBody?): ExampleErrorResponse? {

        return try {

            errorBody?.source()?.let {

                val moshiAdapter = Moshi.Builder().build().adapter(ExampleErrorResponse::class.java)

                moshiAdapter.fromJson(it)

            }

        } catch (exception: Exception) {

            null

        }

    }

}

safeApiCall is having suspended lambda function named ‘api’  that returns data wrapped in Resource so that safeApiCall could be able to receive our every api call function. As safeApiCall is a suspend function so we are using withContext coroutine scope with Dispatchers.IO, this way all network calls will run on the Input/Output background thread. Whenever a network call fails it throws an exception so we need to call our lambda function ‘apiToBeCalled’ inside the try-catch block and here if api call gets successful then we’ll wrap our success response data in Resource. Success object & we’ll return it through safeApiCall and if api call gets failed then we’ll catch that particular exception in one of the following catch blocks:

  • When something will went wrong on the server when processing an HTTP request then it’ll throw an HTTP Exception.
  • When the user won’t be having valid internet/wifi connection then it’ll throw a Java IO Exception.
  • If any other exception will occur then it’ll simply come in general Exception block (put that block in last). You can also add other exceptions catch block according to your specific case before that last one general exception catch block.

Now in catch blocks, we can simply send our own customize error messages or error messages getting from exceptions in Resource.Error object. 

Note: In case if network call doesn’t fail & doesn’t throw an exception instead if it is sending it’s own custom error json response (sometimes happens in case of Authentication failure/Token expires/Invalid api key/etc) then we won’t get an exception instead Retrofit’s Response class will help us determine by returning true/false on response.is Successful. In the above code also we are handling that inside try block, if it returns false then inside else case we’ll parse that api’s own custom error json response (see example below) into a pojo class created by us i.e. ExampleErrorResponse. For parsing this json response to our ExampleErrorResponse pojo, we are using Moshi library in our convertErrorBody function that’ll return ExampleErrorResponse object & then we can get API’s custom error response.

{
   “status”: ”UnSuccessful”,
   “failure_message” : ”Invalid api key or api key expires”
}

So, ultimately our safeApiCall function will return our response wrapped in Resource class. it could be either Success or Error. If you have understood up till this much then shoutout to you. You have won most of the battle.

Now let’s change the way of calling Apis in your current repositories

We’ll extend our all repositories from BaseRepo so that we can access safeApiCall function there. And inside our repo’s functions like getPopularArticles we’ll pass our ApiService’s function ( for ex: apiService.fetchPopularArticles() ) as a lambda argument in safeApiCall and then safeApiCall will simply handle its success/error part then ultimately it’ll return Resource<T> that’ll go all the way top to UI through ViewModel.

Note: Remember when we’ll call getPopularArticles function in viewmodel (see example below) then first we’ll post Resource.Loading object in mutable live data such that our fragment/activity can observe this loading state and can update the UI to show loading state and then as we’ll get our api response ready, it’ll be posted in mutable live data again so that UI can get this response (success/error) update again and can show data in UI or update itself accordingly.

Kotlin

class ExampleRepo(private val apiService: ExampleApiService) : BaseRepo() {

    suspend fun getPopularArticles() : Resource<PopularArticlesResponse> {

        return safeApiCall { apiService.fetchPopularArticles() }

    }

    suspend fun getPublishedArticles() : Resource<NewlyPublishedArticlesResponse> = safeApiCall { apiService.fetchPublishedArticles() }

}

ViewModel

Kotlin

class ExampleViewModel (private val exampleRepo: ExampleRepo) {

    private val _popularArticles = MutableLiveData<Resource<PopularArticlesResponse>>()

    val popularArticles: LiveData<Resource<PopularArticlesResponse>> = _popularArticles

    init {

        getPopularArticles()

    }

    private fun getPopularArticles() = viewModelScope.launch {

        _popularArticles.postValue(Resource.Loading())

        _popularArticles.postValue(exampleRepo.getPopularArticles())

    }

}

That’s it, now we can observe all the states i.e. Success, Error, Loading in our UI easily. That was about api error handling or api response handling in a better way.

Last Updated :
10 Jan, 2023

Like Article

Save Article

Добавляем картинку
Toast.Callback

Вступление

Что такое тост? Представьте себе картину. За столом собралась большая куча народа и весело отмечает день рождения кота. Стоит шум и гам. Соседи громко разговаривают между собой и не обращают внимания на других. И тут из-за стола поднимается всеми уважаемый человек со стаканом вина и вилочкой стучит по стеклу стакана, чтобы привлечь внимание присутствующих. Шум смолкает и человек произносит тост. Также и в телефоне, когда вы увлечены какой-то задачей, вдруг всплывает сообщение, привлекая ваше внимание. Это и есть Toast. Второй пример — когда вы заряжаете специальный хлеб (тосты) в тостер, то они через определённое время подпрыгивают, сигнализируя о своей готовности. Посмотрим, как это работает в Android.

Теория

Всплывающее уведомление (Toast Notification) является сообщением, которое появляется на поверхности окна приложения, заполняя необходимое ему количество пространства, требуемого для сообщения. При этом текущая деятельность приложения остаётся работоспособной для пользователя. В течение нескольких секунд сообщение плавно закрывается. Всплывающее уведомление также может быть создано службой, работающей в фоновом режиме. Как правило, всплывающее уведомление используется для показа коротких текстовых сообщений.

Практика

Для создания всплывающего уведомления необходимо инициализировать объект Toast при помощи метода Toast.makeText(), а затем вызвать метод show() для отображения сообщения на экране:


// Kotlin
val text = "Пора покормить кота!"
val duration = Toast.LENGTH_SHORT

val toast = Toast.makeText(applicationContext, text, duration)
toast.show()

// Java Toast toast = Toast.makeText(getApplicationContext(), "Пора покормить кота!", Toast.LENGTH_SHORT); toast.show();

Обычно пишут в одну строчку, соединяя вызов методов в цепочку .


// Kotlin
Toast.makeText(applicationContext, text, duration).show()

У метода makeText() есть три параметра:

  • Контекст приложения
  • Текстовое сообщение
  • Продолжительность времени показа уведомления. Можно использовать только две константы

Константы для указания продолжительности показа сообщения

  • LENGTH_SHORT — (По умолчанию) показывает текстовое уведомление на короткий промежуток времени;
  • LENGTH_LONG — показывает текстовое уведомление в течение длительного периода времени.

Если покопаться в исходниках Android, то можно найти такие строчки:


private static final int LONG_DELAY = 3500; // 3.5 seconds
private static final int SHORT_DELAY = 2000; // 2 seconds

Как видите, уведомления выводятся на 3 с половиной секунды или на 2 секунды. Других вариантов нет, не пытайтесь использовать другие значения — у вас ничего не получится.

Настройка позиции на экране

По умолчанию стандартное всплывающее уведомление появляется в нижней части экрана. Изменить место появления уведомления можно с помощью метода setGravity(int, int, int). Метод принимает три параметра:

  • стандартная константа для размещения объекта в пределах большего контейнера (например, GRAVITY.CENTER, GRAVITY.TOP и др.);
  • смещение по оси X
  • смещение по оси Y

Например, если вы хотите, чтобы уведомление появилось в центре экрана, то используйте следующий код (до вызова метода show()):

 
toast.setGravity(Gravity.CENTER, 0, 0); 

Для вывода в левом верхнем углу.


toast.setGravity(Gravity.TOP or Gravity.LEFT, 0, 0)

Если нужно сместить уведомление направо, то просто увеличьте значение второго параметра. Для смещения вниз нужно увеличить значение последнего параметра. Соответственно, для смещения вверх и влево используйте отрицательные значения.

Не забывайте про метод show()

Типичная ошибка начинающих программистов — забывают добавить вызов метода show() для отображения сообщения на экране. К счастью, в студии, если вы пропустите метод show(), то строка будет подсвечена, а при подведении указателя мыши к строке увидите:

Метод show()

Kotlin

Метод show()

Java

Пример

Создайте новый проект или используйте любой старый проект из предыдущих занятий. Добавьте на экран активности кнопку и присвойте ей текст Показать Toast. Теперь напишем код:


// Kotlin
// Если этот код работает, его написал Александр Климов,
// а если нет, то не знаю, кто его писал.

package ru.alexanderklimov.hellokot

import android.os.Bundle
import android.view.Gravity
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_main)

        val button: Button = findViewById(R.id.button)
        button.setOnClickListener {
            val text = "Пора покормить кота!"
            val duration = Toast.LENGTH_SHORT

            val toast = Toast.makeText(applicationContext, text, duration)
            toast.setGravity(Gravity.CENTER, 0, 0)
        }
    }
}

// Java public void showToast(View view) { //создаём и отображаем текстовое уведомление Toast toast = Toast.makeText(getApplicationContext(), "Пора покормить кота!", Toast.LENGTH_SHORT); toast.setGravity(Gravity.CENTER, 0, 0); toast.show(); }

Запустите приложение и нажмите кнопку. В центре экрана появится на короткое время текстовое сообщение, которое само исчезнет. Очень похоже на поведение чеширского кота.

Начиная с Android 4.4, внешний вид всплывающего сообщения изменился, раньше был прямоугольник без закруглений.

Toast

Для закрепления материала напишем ещё один пример. Удалим предыдущий код для щелчка кнопки и напишем такой код:


// Kotlin
val duration = Toast.LENGTH_LONG

val toast = Toast.makeText(applicationContext, R.string.cat_food, duration)
toast.setGravity(Gravity.TOP, 0, 0)
toast.show()

// Java int duration = Toast.LENGTH_LONG; Toast toast = Toast.makeText(getApplicationContext(), R.string.catfood, duration); toast.setGravity(Gravity.TOP, 0, 0); toast.show();

Я подумал, что вы можете не заметить сообщение, которое показывается слишком мало времени. Поэтому на этот раз я использовал константу LENGTH_LONG, чтобы вы успели обратить внимание на сообщение и покормить наконец несчастного голодного кота. Помимо этого, я поместил текст сообщения в XML-ресурсы, как это рекомендуется всегда делать. Кроме того, сообщение будет выводиться в верхней части экрана.

Добавляем картинку

Как правило, для Toast используются короткие текстовые сообщения. При необходимости вы можете добавить к сообщению и картинку. Используя метод setView(), принадлежащий объекту Toast, вы можете задать любое представление (включая разметку) для отображения.

Начнем с приготовлений. Подготовьте картинку и разместите её в папке res/drawable, как мы делали в уроке с «Hello Kitty». Картинка будет доступна приложению как ресурс через название файла без расширения. Например, я добавил в папку файл с изображением кота hungrycat.jpg и могу получить к нему доступ через выражение R.drawable.hungrycat. Чтобы изображение появилось в стандартном Toast-сообщении, нам потребуется программно создать объект класса ImageView и задать для него изображение из ресурсов с помощью метода setImageResource. Сам по себе стандартный внешний вид Toast состоит из контейнера LinearLayout, в который нужно добавить созданный объект ImageView. Можно задать также позицию, в которую следует вывести изображение. Если указать значение 0, то изображение будет показано выше текста. Код для создания Toast с изображением выглядит следующим образом:


// Kotlin
button.setOnClickListener {
    val toast = Toast.makeText(applicationContext, R.string.cat_food, Toast.LENGTH_LONG)
    toast.setGravity(Gravity.CENTER, 0, 0)

    val toastContainer = toast.view as LinearLayout
    val catImage = ImageView(this)
    catImage.setImageResource(R.drawable.hungrycat)
    toastContainer.addView(catImage, 0)
    toast.show()
}

// Java public void showToast(View view) { Toast toast3 = Toast.makeText(getApplicationContext(), R.string.catfood, Toast.LENGTH_LONG); toast3.setGravity(Gravity.CENTER, 0, 0); LinearLayout toastContainer = (LinearLayout) toast3.getView(); ImageView catImageView = new ImageView(getApplicationContext()); catImageView.setImageResource(R.drawable.hungrycat); toastContainer.addView(catImageView, 0); toast3.show(); }

Toast с картинкой

Вообще, получив доступ к контейнеру, вы можете делать с ним что угодно. Например, сделать его прозрачным. Смотрится интересно.


// Kotlin
val toast = Toast.makeText(applicationContext, "Чеширский кот", Toast.LENGTH_LONG)
val toastContainer = toast.view as LinearLayout
val catImage = ImageView(this)
catImage.setImageResource(R.drawable.hungrycat)
toastContainer.addView(catImage, 0)
// Устанавливаем прозрачность у контейнера
toastContainer.setBackgroundColor(Color.TRANSPARENT)
toast.show()

// Java public void showToast(View view) { Toast toast = Toast.makeText(getApplicationContext(), "Чеширский кот", Toast.LENGTH_LONG); toast.setGravity(Gravity.CENTER, 0, 0); LinearLayout toastContainer = (LinearLayout) toast.getView(); // Устанавливаем прозрачность у контейнера toastContainer.setBackgroundColor(Color.TRANSPARENT); toast.show(); }

Создание собственных всплывающих уведомлений

В Android 11 (R) метод setView() объявлен устаревшим.

В предыдущем примере мы получили доступ к контейнеру через метод getView(). Можно пойти от обратного — подготовить свой контейнер и внедрить его в объект Toast через метод setView().

Создадим собственный дизайн разметки для сообщения.

Вам нужно создать разметку в файле res/layout/custom_toast.xml.

Определите два дочерних элемента ImageView и TextView:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/custom_toast_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#DAAA"
    android:orientation="vertical"
    android:padding="8dp">

    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:scaleType="centerCrop"
        android:src="@drawable/hungrycat" />

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="@string/cat_food"
        android:textColor="#FFF777" />
</LinearLayout>

Для получения разметки из ХМL-файла и работы с ней в программе используется класс LayoutInflater и его метод getLayoutInflater(), которые возвращает объект LayoutInflater. Затем вызовом метода inflate() получают корневой объект View этой разметки. Например, для файла разметки уведомления с именем custom_toast.xml и его корневого элемента c идентификатором android:id=»@+id/custom_toast_container» код будет таким:


// Kotlin
button.setOnClickListener {
    val inflater = layoutInflater
    val container = findViewById<ViewGroup>(R.id.custom_toast_container)
    val layout: View = inflater.inflate(R.layout.custom_toast, container)
    val text: TextView = layout.findViewById(R.id.text)
    text.text = "Пора покормить кота!"
    with (Toast(applicationContext)) {
        setGravity(Gravity.CENTER_VERTICAL, 0, 0)
        duration = Toast.LENGTH_LONG
        view = layout
        show()
    }
}

// Java // Упрощённо LayoutInflater inflater = getLayoutInflater(); View layout = inflater.inflate(R.layout.custom_layout, (ViewGroup) findViewById(R.id.toast_layout)); Toast toast = new Toast(getApplicationContext()); toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0); toast.setDuration(Toast.LENGTH_LONG); toast.setView(layout); toast.show();

Параметры, передаваемые в метод inflate():

  • идентификатор ресурса макета (custom_toast.xml);
  • идентификатор ресурса корневого элемента (custom_toast_container).

После получения корневого элемента из него можно получить все дочерние элементы методом findViewByid() и определить информационное наполнение для этих элементов.

Затем создаётся объект Toast и устанавливаются нужные свойства, например, Gravity и продолжительность времени показа уведомления.

После этого вызывается свойство view() (Kotlin) или метод setView() (Java), которому передаётся разметка уведомления, и метод show(), чтобы отобразить уведомление с собственной разметкой.

Запустите проект на выполнение. При нажатии кнопки вызова должно появиться на несколько секунд окно уведомления с текстовым сообщением и значком.

Ради интереса можете посмотреть, как выглядит разметка в исходных кода Android.

Toast.Callback

В Android 11 R (API 30) добавили возможность отслеживания момента, когда сообщение появляется и скрывается при помощи Toast.Callback.


button.setOnClickListener {
    val alertToast = Toast.makeText(this, "Пора покормить кота", Toast.LENGTH_SHORT)
    alertToast.addCallback(object: Toast.Callback() {
        override fun onToastShown() {
            super.onToastShown()
            Log.d("Toast", "shown")
        }

        override fun onToastHidden() {
            super.onToastHidden()
            Log.d("Toast", "hidden")
        }
    })
    alertToast.show()
}

Ещё раз напомню, что метод setView() в Android 11 признан устаревшим. А также вообще рекомендуют не использовать собственные виды всплывающих сообщений, а ограничиться простыми текстовыми сообщениями. Иначе можно нарваться на системные ограничения.

Использование уведомлений Toast в рабочих потоках

Как элемент графического интерфейса Toast должен быть вызван в потоке GUI, иначе существует риск выброса межпотокового исключения. В листинге объект Handler используется для гарантии того, что уведомление Toast было вызвано в потоке GUI.


// Java
private void mainProcessing() {
    Thread thread = new Thread(null, doBackgroundThreadProcessing,
            "Background");
	thread.start();
}

private Runnable doBackgroundThreadProcessing = new Runnable() {
    public void run() {
        backgroundThreadProcessing();
    }
};

private void backgroundThreadProcessing() {
    handler.post(doUpdateGUI);
}

// Объект Runnable, который вызывает метод из потока GUI
private Runnable doUpdateGUI = new Runnable() {
    public void run() {
        Context context = getApplicationContext();
        String msg = "To open mobile development!";
        int duration = Toast.LENGTH_SHORT;
        Toast.makeText(context, msg, duration).show();
    }
};						 

Дополнительные сведения

Напоследок хочу предупредить об одной потенциальной проблеме. При вызове сообщения нужно указывать контекст в первом параметре метода makeText(). В интернете и, возможно и у меня на сайте будет попадаться пример makeText(MainActivity.this, …). Ошибки в этом нет, так как класс Activity является потомком Context и в большинстве случаев пример будет работать. Но иногда я получаю письма от пользователей, которые жалуются на непонятное поведение сообщения, когда текст не выравнивается, обрезается и т.д. Это связано с тем, что активность может использовать определённую тему или стиль, которые вызывают такой побочный эффект. Поэтому я рекомендую вам использовать метод getApplicationContext().

Второй момент — фрагменты, которые будете изучать позже, не являются потомками контекста. Если вы захотите вызвать всплывающее сообщение в фрагменте, то проблема может поставить вас в тупик. Вам нужно добавить новую переменную класса Activity через метод getActivity():


Activity activity = getActivity();
Toast.makeText(activity, "Кота покормили?", Toast.LENGTH_SHORT).show();

Такое же может случиться при вызове всплывающих сообщений из диалоговых окон, которые тоже не относятся к классу Context. Вместо getApplicationContext() также можно вызывать метод getBaseContext().

Заключение

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

Дополнительные материалы

Обсуждение урока на форуме

Пример частично цветного текста в Toast через Spannable

GrenderG/Toasty: The usual Toast, but with steroids — библиотека, позволяющая создавать продвинутые сообщения

Реклама

Понравилась статья? Поделить с друзьями:
  • Apc back ups pro 1200 ошибка f06
  • Anomalydx11avx exe системная ошибка
  • Android studio ошибка установки haxm
  • Apb ошибка нет соединения
  • Anomaly zone ошибка 16 сервер не готов 2