Вызов элементов activity в подключаемом классе

Интерфейс, диалоги, темы, стили, меню
Ответить
tolik777
Сообщения: 37
Зарегистрирован: 06 июл 2012, 14:25

Вызов элементов activity в подключаемом классе

Сообщение tolik777 » 12 ноя 2012, 14:40

В общем сделал машинку с управлением от акселерометра по Bluetooth. Все работает, но теперь хочу сделать также с управлением от кнопок. Я сделал второе активити и тут встал вопрос повторного использования кода для Bluetooth (создание соединения, передача данных и т.п.). Я решил все, что касается Bluetooth вынести в отдельный класс - файл. Но у меня там в коде используются Toast.makeText(), а также запрос на включение блютуза при его отсутствии: startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); И Eclipse ругается на эти строки
Если прописать public class Bluetooth extends Activity {... то Eclipse не ругается, но приложение крашиться. Да и как я понимаю это неправильно. Как тут быть? Почитал немного про intent думал туда может надо копать, но вроде не то.

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Вызов элементов activity в подключаемом классе

Сообщение rezak90 » 12 ноя 2012, 15:03

Toast'y нужен будет контекст, так что просто в свой класс передавайте текущий контекст. startActivityForResult это метод который относится к классу Activity, соответственно оно и будет крешится потому что это велосипед, зачем вам возвращать что то из вашего простого класса? есть сеты и геты вот геты пускай и возвращают вам то что нужно.
Например:
MyBluetooth.isConnect() - возвращает текущее подключение true или false.
R.id.team
Политика на форуме запрещена

tolik777
Сообщения: 37
Зарегистрирован: 06 июл 2012, 14:25

Re: Вызов элементов activity в подключаемом классе

Сообщение tolik777 » 12 ноя 2012, 17:12

Я в принципе тоже так думал сделать, но в связи с тем, что плохо понимаю принципы ООП (прграммирую микроконтроллеры и PHP без ООП), то не могу понять как тогда реализовать вызов функций в подключаемом классе, из основного класса.
Т.е. можно ли так сделать: класс А - основной с активити, а класс Б - вспомогательный без активити с Bluetooth функциями. Из класса А я вызываю методы и функции класса Б. А вот можно ли мне из класса Б вызывать методы класса A? И как тогда import тоже прописывать в начале файла?
Еще раз сорри за мою тупизну, книгу Java раздел про ООП прочитал, половину не понял, видимо выросшим на бейсике и паскале в начале 90-х не суждено уже допетрить в полной мере принципы ООП :) мне условные и безусловные переходы как-то ближе :)

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Вызов элементов activity в подключаемом классе

Сообщение rezak90 » 12 ноя 2012, 17:51

Из класса А я вызываю методы и функции класса Б
вот так правильно
А вот можно ли мне из класса Б вызывать методы класса A?
можно, но это не правильно, а не правильно потому что архитектурно вы не правильно проектируете приложение. Язык так построен что есть активити и вокруг неё всё крутится, не может так что бы какой то класс крутил активностю. Но мне больше интересно какие методы вы собрались вызывать, если эти методы используют компоненты экрана то это сразу креш приложения, если же обычные переменные то в любом случае придётся их делать статическими, и опять таки зачем если эти все данные можно передать в ваш класс Б и там уже их юзать.
R.id.team
Политика на форуме запрещена

Аватара пользователя
neoksi
Сообщения: 712
Зарегистрирован: 26 июл 2012, 10:42
Контактная информация:

Re: Вызов элементов activity в подключаемом классе

Сообщение neoksi » 12 ноя 2012, 22:05

rezak90 писал(а):
А вот можно ли мне из класса Б вызывать методы класса A?
можно, но это не правильно, а не правильно потому что архитектурно вы не правильно проектируете приложение. Язык так построен что есть активити и вокруг неё всё крутится, не может так что бы какой то класс крутил активностю. Но мне больше интересно какие методы вы собрались вызывать, если эти методы используют компоненты экрана то это сразу креш приложения, если же обычные переменные то в любом случае придётся их делать статическими, и опять таки зачем если эти все данные можно передать в ваш класс Б и там уже их юзать.
Ну сам вызов возможен, через Броадкасты. У меня к примеру сервис может посылать моим активити броадкасты, чтоб они закрылись и вызвали активити логина.

AndreyI
Сообщения: 372
Зарегистрирован: 14 май 2012, 16:18

Re: Вызов элементов activity в подключаемом классе

Сообщение AndreyI » 13 ноя 2012, 10:42

tolik777 писал(а):Я в принципе тоже так думал сделать, но в связи с тем, что плохо понимаю принципы ООП (прграммирую микроконтроллеры и PHP без ООП), то не могу понять как тогда реализовать вызов функций в подключаемом классе, из основного класса.
Т.е. можно ли так сделать: класс А - основной с активити, а класс Б - вспомогательный без активити с Bluetooth функциями. Из класса А я вызываю методы и функции класса Б. А вот можно ли мне из класса Б вызывать методы класса A? И как тогда import тоже прописывать в начале файла?
Еще раз сорри за мою тупизну, книгу Java раздел про ООП прочитал, половину не понял, видимо выросшим на бейсике и паскале в начале 90-х не суждено уже допетрить в полной мере принципы ООП :) мне условные и безусловные переходы как-то ближе :)
Ну с ООП полюбому нужно подружиться, если работаешь с JAVA без этого никуда.
Тут не нужно, что-то выдумывать, все уже придумано до нас.
Если мы хотим в объекте класса Б созданном объектом класса A вызывать методы своего родителя (класса А), то здесь обычно поступают следующим образом.
1. Передают ссылку объекта класса A в класс Б и вызывают методы класса A через эту ссылку. Чаще всего это делают при создании класса Б т.е. передают ссылку прямо в конструктор класса Б. В объекте Б сохраняют ссылку на объект A во внутреннем поле и используют его по мере необходимости.
2. Делают класс Б встроенным в класс A тогда класс Б будет иметь доступ ко всем методам класса A, а также ко всем его полям. Но это не ваш случай т.к. класс Б у вас должен быть отдельным и использоваться для разных Activity.

Так что первый вариант вам больше всего подходит.
Добавьте в конструктор класса дополнительный параметр класса Activity и сохраняйте ссылку во внутреннем поле класса.

class MyBluetooth {

private Activity mActivity; //Поле в котором храним ссылку на родительское Activity

MyBluetooth (Activity activity){ //В конструкторе класса принимаем ссылку на объект родительского класса
mActivity = activity; //Сохраняем ссылку
}


}

В классе ваших Activity вы должны создавать объекты класса MyBluetooth следующим образом:

MyBluetooth myBluetooth = new MyBluetooth (this);

Теперь в классе MyBluetooth вы можете вызывать любые методы класса Activity
mActivity.methodActivity();

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

((MyActivity)mActivity).methodMyActivity();

Но здесь нужно быть осторожным т.к., если вы объект класса MyBluetooth создаете в разных Activity , то вызываемый метод должен быть определен во всех этих Activity иначе будет брошено исключение. Либо в коде MyBluetooth предусмотреть проверку к какому именно классу принадлежит ваша ссылка mActivity

if (mActivity instanceof MyActivity){
((MyActivity)mActivity).methodMyActivity();
}

тогда этот метод будет вызываться только, если класс объекта mActivity будет являться классом MyActivity


Еще что необходимо помнить, что если вы в разных Activity создаете объекты класса MyBluetooth то это будут разные объекты, у них будут свои поля со своими значениями. Если необходимо иметь что-то общее между этими объектами, то используются статические поля (помеченные ключевым словом static) эти поля будут общими для всех объектов MyBluetooth, еще говорят что они принадлежат не объектам класса, а самому классу. Они создаются один раз при первом вызове класса и гарантированно не уничтожаются, пока будет жив хотябы один объект этого класса.

tolik777
Сообщения: 37
Зарегистрирован: 06 июл 2012, 14:25

Re: Вызов элементов activity в подключаемом классе

Сообщение tolik777 » 13 ноя 2012, 11:15

Начал делать так, чтобы с класса bluetooth все методы возвращали в основной активити переменные, и уже в активити их обрабатывать. С каждого метода мне нужно возвратить минимум 2 переменные: одну boolean и одну String. Погуглив нашел что можно определить класс и возвращать обьекты.
Набросал такой код. Часть кода активити:

Код: Выделить всё

package com.example.bl_4wd;

import com.example.bl_4wd.Bluetooth;
import com.example.bl_4wd.R;

import android.os.Bundle;
....
....
class Error_Text  {
	public boolean eError;
	public String eText_Error;
}


public class ActivityAccelerometer extends Activity implements SensorEventListener  {
...
...
private Bluetooth bl;
....
....
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_accelerometer);

        ......
        ......

        bl = new Bluetooth();
        
        if(!bl.checkBTState().eError){
         	BluetoothAdapter.getDefaultAdapter();
		//final int REQUEST_ENABLE_BT = 1;
        	Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableBtIntent, 1);
        }
        else Toast.makeText(getBaseContext(), bl.checkBTState().eText_Error, Toast.LENGTH_SHORT).show();
    }
Вот код файла Bluetooth.java:

Код: Выделить всё

package com.example.bl_4wd;
...
...
public class Bluetooth{
    ...
    public Error_Text err = null;
    ...
    
    Bluetooth(){
    	btAdapter = BluetoothAdapter.getDefaultAdapter();
    	Error_Text err = new Error_Text();
    }

     public Error_Text checkBTState() {

    	if(btAdapter==null) { 
    		//errorExit("Fatal Error", "Bluetooth not support");
        } else {
        	if (btAdapter.isEnabled()) {
        		Log.d(TAG, "...Bluetooth ON...");
        		//return true;
        	} else {
        		err.eError = false;
        		err.eText_Error = "Bluetooth не найден";
        		return err;
        		//return false;
          	}
        }
        return err;
     }
}

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

AndreyI
Сообщения: 372
Зарегистрирован: 14 май 2012, 16:18

Re: Вызов элементов activity в подключаемом классе

Сообщение AndreyI » 13 ноя 2012, 11:44

Судя по всему вы пытаетесь получить значение поля eText_Error которое не определено.
Дело в том, что по умолчанию (если явно не определить значение) полю примитивных типов (int, long, boolean и т.п.) присваиваются значения 0 или для boolean - false. Для всех других объектов присваивается значение null , а String не является примитивным типом в JAVA поэтому, если явно не присвоить ему значение, то его значение по умолчанию будет null.
Теперь смотрим в ваш код, там идет проверка btAdapter.isEnabled(), если проверка дает ошибку, то полю eText_Error присваивается значение "Bluetooth не найден", а если проверка прошла удачно, то какое значение получит eText_Error? Правильно, null. И при последующей попытке считать данные из этого поля будет брошено исключение.
Поэтому либо присвойте какой-нибудь значение этому полю в ветви
if (btAdapter.isEnabled()) {
Log.d(TAG, "...Bluetooth ON...");
//return true;
err.eText_Error = "Bluetooth найден";

либо в его определении присвойте ему значение с пустой строкой
class Error_Text {
public boolean eError;
public String eText_Error="";
}

tolik777
Сообщения: 37
Зарегистрирован: 06 июл 2012, 14:25

Re: Вызов элементов activity в подключаемом классе

Сообщение tolik777 » 13 ноя 2012, 11:52

Попробовал оба варианта, все равно крашится.
И еще настораживает вот что: Eclipse на строку Error_Text err = new Error_Text(); пишет варнинг, что переменная не используется нигде: The value of the local variable err is not used
Попробовал ее закомментировать, ничего не поменялось, все равно краш

AndreyI
Сообщения: 372
Зарегистрирован: 14 май 2012, 16:18

Re: Вызов элементов activity в подключаемом классе

Сообщение AndreyI » 13 ноя 2012, 12:06

Странно что так пишет, ведь вы возвращаете объект err (return err;) поэтому, вроде как, используете, может вы не во всех ветвях его возвращаете, то тогда бы выдало ошибку при компиляции.

Это может означать, только что объект err по какой-то причине оказался невидим внутри метода checkBTState()
Последний раз редактировалось AndreyI 13 ноя 2012, 12:14, всего редактировалось 2 раза.

AndreyI
Сообщения: 372
Зарегистрирован: 14 май 2012, 16:18

Re: Вызов элементов activity в подключаемом классе

Сообщение AndreyI » 13 ноя 2012, 12:09

Попробуйте перенести Error_Text err = new Error_Text(); внутрь метода
public Error_Text checkBTState() {
...
}

tolik777
Сообщения: 37
Зарегистрирован: 06 июл 2012, 14:25

Re: Вызов элементов activity в подключаемом классе

Сообщение tolik777 » 13 ноя 2012, 12:17

Вроде заработало! Спасибо! Буду разбираться дальше

AndreyI
Сообщения: 372
Зарегистрирован: 14 май 2012, 16:18

Re: Вызов элементов activity в подключаемом классе

Сообщение AndreyI » 13 ноя 2012, 12:53

Понял в чем изначально была ваша ошибка, вы в конструкторе написали
Bluetooth(){

Error_Text err = new Error_Text();
}
Эта запись означает, что вы создаете новый объект err внутри конструктора, который умрет сразу же после выхода из конструктора, поэтому Eclipse и показывает что объект не используется, то что имена их совпадают это не означает, что вы хотите инициализировать поле класса с таким же именем.
вам нужно было записать так
Bluetooth(){

err = new Error_Text();
}

Тогда все было бы нормально.

ЗЫ Не зря хорошим тоном является явное (с помощью this) указание на поле объекта класса, тогда точно путаницы не возникнет.
this.err = new Error_Text();

tolik777
Сообщения: 37
Зарегистрирован: 06 июл 2012, 14:25

Re: Вызов элементов activity в подключаемом классе

Сообщение tolik777 » 14 ноя 2012, 10:42

В общем решил делать через Handle. И напоролся на одну проблемку.
Итак кусок кода активити:

Код: Выделить всё

@Override
    public void onCreate(Bundle savedInstanceState) {
    .....
    bl = new Bluetooth(this, mHandler);
    ....
    ....
}
private final Handler mHandler =  new Handler() {
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case BL_NOT_AVAILABLE:
            	Log.d(TAG, "Bluetooth is not available. Exit");
            	Toast.makeText(getBaseContext(), "Bluetooth is not available", Toast.LENGTH_SHORT).show();
                finish();
                int t1 = bl.BL_INCORRECT_ADDRESS;                         // Так все нормально
                break;
            case bl.BL_INCORRECT_ADDRESS:                                 // А так ругается "case expressions must be constant expressions"
            	Log.d(TAG, "Incorrect Bluetooth address");
            	Toast.makeText(getBaseContext(), "Incorrect Bluetooth address", Toast.LENGTH_SHORT).show();
                break;   
            }
        };
    };
Во втором файле:

Код: Выделить всё

public class Bluetooth{
    public static final int BL_NOT_AVAILABLE = 1;        // Статус для Handler
    public static final int BL_INCORRECT_ADDRESS = 2;
    .....
    .....
2 раза одно и тоже прописывать в двух файлах не хочется. А CASE почему то ругается когда хочу использовать константы из второго класса bluetooth, т.е. когда пишу bl.BL_INCORRECT_ADDRESS

Пока что заюзал if else, но по switch интересно все же почему...

Аватара пользователя
damager82
Администратор
Сообщения: 1383
Зарегистрирован: 07 янв 2012, 11:32
Контактная информация:

Re: Вызов элементов activity в подключаемом классе

Сообщение damager82 » 14 ноя 2012, 12:50

tolik777 писал(а):А CASE почему то ругается когда хочу использовать константы из второго класса bluetooth, т.е. когда пишу bl.BL_INCORRECT_ADDRESS
Используйте класс, а не экземпляр:
Bluetooth.BL_INCORRECT_ADDRESS
Добро пожаловать на форум сайта StartAndroid
ИзображениеИзображение

tolik777
Сообщения: 37
Зарегистрирован: 06 июл 2012, 14:25

Re: Вызов элементов activity в подключаемом классе

Сообщение tolik777 » 14 ноя 2012, 13:58

Спасибо! Понял!

Ответить