Все технические форумы на одном сайте Удобный поиск информации с популярных форумов в одном месте
Вопрос: Потоки. Доступ к переменным

Помогите с вопросом о видимости переменных. Я создал поток внутри класса Activity. Теперь не могу обратиться из потока к объявленым переменным во внешнем классе(Activity). Вот код:

Код Java(TM) 2 Platform Standard Edition 5.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
       public class MainActivity extends Activity {
 
 
       public boolean FORM_OPEN = false;
 
       protected void onStart() {
 
        FORM_OPEN = true;
        getMesFromServices threadMesClass = new getMesFromServices();
        threadMes = new Thread(threadMesClass);
        threadMes.start();
        
        super.onStart();
        
    }
 
        class getMesFromServices implements Runnable {
 
        @Override
        public void run() {
            
 
            if (FORM_OPEN) { // эту переменную поток не понимает. я присваиваю ей true перед вызовом потока, а в потоке она false
                           // тут код
            }
 
        }
    }
}
До этого я ссылался на правило что ВНУТРЕННИЙ КЛАСС ИМЕЕТ ДОСТУП К ПЕРЕМЕННЫМ ВНЕШНЕГО. но походу к потокам это не относится. Спасибо за помощь!
Ответ: Попробую! завтра отпишусь о результате. Спасибо Mikalai!

Добавлено через 20 часов 17 минут
Этот код сработал на ура. теперь поток видит переменные.
Код Java(TM) 2 Platform Standard Edition 5.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class MainActivity extends Activity implements Runnable {
 
 
public boolean FORM_OPEN = false;
 
protected void onStart() {
 
FORM_OPEN = true;
threadMes = new Thread(this);
threadMes.start();
 
super.onStart();
 
}
 
 
@Override
public void run() {
 
 
if (FORM_OPEN) { // эту переменную поток не понимает. я присваиваю ей true перед вызовом потока, а в потоке она false
// тут код
}
 
}
 
}
Еще раз спасибо Mikalai!
Вопрос: MediaPlayer и новый поток для воспроизведения

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

Что я точно понял,что новый поток нужно создавать перед воспроизведением файла. И делает это метод prepareAsync() . Но, если я правильно понимаю, это поток только для подготовки(буферизация и т.д.). К тому же,если воспроизводить файлы в "правильном формате" папки raw проекта, подготовка не требуется. Немного сумбурно,но надеюсь суть вопроса ясна)
Ответ: okunetsky, поток не нужен если вы просто даёте плееру трек. Ваш код помог бы ответить точнее
Вопрос: Не удается остановить воспроизведение потока после закрытия и открытия приложения

Написал приложение для воспроизведения аудио-потока. Кнопки Старт и Стоп работают нормально. Если закрыть приложение не выключая поток, воспроизведение продолжится. Но после повторного запуска приложения кнопка Стоп не работает.
Два вопроса:
1) Почему поток продолжает играть?
2) Как его остановить после повторного запуска приложения?
Ответ: В onDestroy надо убивать потоки.
Вопрос: Запустить сервис в другом потоке

Как правильно запустить сервис в другом потоке?

Сервис должен работать всегда (даже когда приложение закрыто)
Ответ: Когда-то разобрался с этим (правда уже пол года за андроид не брался - подзабыл немножко)...

Есть понятие аппликэйшн. Все активити работают "из него". Сервис тоже запускается "от аппликэйшн". При полном закрытии программы (нажать хоум и слвайпом удалить программу) иногда убиваются и сервисы.
Можно обнадежить выведя нотиф. (как указано выше). Где-то встречал как сделать "невидимый нотиф" (типа вызывается, но не выводится). Где-то встречал как вызвать сервис "с повышенными правами" (без рута - хакерский прием - типа как "системную" помечаем).
А можно вызвать из глобального ресивера. Но если он создан И в активити, то он все еще привязан к основному аппликэйшн. Можно его вызвать сразу из ресивера (отправив из активити "запрос"). Тогда сервис создаст "копию" аппликэйшн (я долго это разбирал - хранил глобальные переменные в классе аппликэшн и они то были доступны, то пропадали).
Если ресивер "общий" (например на изменение заряда), то сервис будет часто "перезапускаться" - так можно его "обнадежить" даже на случай зависания/перезагрузки. (ресивер "при запуске устройства" иногда не вызывается).

запуск из потока не пробовал! Но подозреваю что все потоки запущенные из активити привязаны к одному аппликэйшн, а он убивается вместе с программой (удалением ее из памяти)

...вроде все! удачи...
Вопрос: Изменения массива не "замечает" поток

Здравствуйте! Пишу программу под андроид, и в коде наблюдалась странная проблема - при изменении значений переменной, отдельный поток просто не замечал этого. Переписал код на чистый java, та же проблема. Помогите пожалуйста, из-за чего данная проблема?
Например, если сначала ввести set test, а потом start - выведет а.

Буду очень благодарен за помощь!
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import java.util.*;
 
public class TestBug
{
    String[] test = {"a"};
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (true) {
            String[] inData = sc.nextLine().split(" ");
 
            switch (inData[0]) {
                case "start":
                    new TestBug().run();
                    break;
                case "set":
                    new TestBug().setMsg(inData[1]);
                    break;
            }
        }
        
    }
    
    public void setMsg(String data) {
        test[0] = data;
        System.out.println("Succ");
        System.out.println(Arrays.deepToString(test));
    }
 
    public void run() {
        new Thread(new Runnable() {
                @Override
                public void run()
                {
                    while (true) {
                        try {
                            Thread.sleep(5000L);
                            System.out.println(Arrays.deepToString(test));
                        }
                        catch (InterruptedException e)
                        {}
                    }
                }
            }).start();
        }
}
Добавлено через 6 минут
Как выяснилось - поток вообще ни на что ни влияет. Оно в любом случае выдает не тот ответ
Ответ: Правильно - ни потоки, ни ОС здесь роли не играют... Обычное ООП... Класс TestBug, поле test не статическое... А, вы каждый раз создаете новый экземпляр, меняете поле в одном экземпляре, а, используете в другом, поэтому оно и теряется.

Сделайте так, и будет работать:

Java
1
2
3
TestBug testBug = new TestBug();
testBug.setMsg(inData[1]);
testBug.run();
Вопрос: Как заставить поток ждать

Есть программа, в которую пользователь может залогиниться, за залогинивание отвечает отдельный поток, который обращается к серверу и получает от него ответ. Мне необходимо, чтобы поток выполнял код внутри цикла лишь раз, после чего засыпал, пока его не разбудит пользователь повторным нажатием кнопки войти. К сожалению, приведенный ниже код выдает ошибку "java.lang.IllegalMonitorStateException: object not locked by thread before wait()".
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package ru.utccom.utc;
 
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
 
 
public class MainActvt extends AppCompatActivity {
    String response = "";
    EditText LoginEdit;
    EditText PasswordEdit;
    DBTalker dbTalker = new DBTalker();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_actvt);
        LoginEdit = findViewById(R.id.MALoginText);//magic
        PasswordEdit = findViewById(R.id.MAPasswordText);
   }
    Thread getRequest = new Thread() {
        String request;
        @Override
        public void run() {
                request = dbTalker.doesUserExists(MainActvt.this.LoginEdit.getText().toString(),
                        MainActvt.this.PasswordEdit.getText().toString());
                while (!interrupted()) {
                    MainActvt.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            if (request.equals("1")) {
                                Toast.makeText(MainActvt.this, "Вы успешно вошли.", Toast.LENGTH_SHORT).show();
                                getRequest.interrupt();
                            } else if (request.equals("0")) {
                                Toast.makeText(MainActvt.this, "Неверное имя пользователя или пароль.", Toast.LENGTH_SHORT).show();
                            }
                            else {
                                Toast.makeText(MainActvt.this, "Произошла ошибка.", Toast.LENGTH_SHORT).show();
                            }
                        }
                    });
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
    public void OnMALoginButtonClick(View v) {
        if (LoginEdit.getText().toString().equals("") || PasswordEdit.getText().toString().equals("")) {
            Toast.makeText(MainActvt.this, "Заполните все поля.", Toast.LENGTH_SHORT).show();
        } else {
            if (getRequest.getState() == Thread.State.NEW) {
                getRequest.start();
            }
            else {
                getRequest.notify();
                }
            }
        }
    }
Подскажите пожалуйста. каким все же образом я могу реализовать задуманное? На код попрошу не ргуаться, так как новичок, хотя, если конструктивно, то я только за)
Ответ: Повесить на главный поток прогрессБар и не городить всякую фигню.
Про асинк таск гуглить надо было много лет назад.
Вопрос: Вылетает при создании потока

При выключенном Bluetooth, запуская приложение у меня включается блютуз, но выдаёт ошибку создания потока:
XML
1
2
3
02-15 13:31:26.111 30855-31205/com.alexru18.bluetoothchat E/AndroidRuntime: FATAL EXCEPTION: Thread-2439
                                                                            java.lang.NullPointerException
                                                                                at com.alexru18.bluetoothchat.ServerThread.run(ServerThread.java:36)
Думал дело в том, что блютуз запускается не сразу, а через несколько мгновений и поставил delay, но не помогло:
Java(TM) 2 Platform Standard Edition 5.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public void run() {
 
        BluetoothSocket socket = null;
 
        Log.d("ServerThread", "Started");
 
        while (true) {
            try {
                socket = bluetoothServerSocket.accept();  //(ServerThread.java:36)
            } catch (IOException e) {
                Log.d("ServerThread", "Stop: " + e.getLocalizedMessage());
                break;
            }
            try {
                sleep(5000);
                if (socket != null) {
                    communicatorService.createCommunicatorThread(socket).startCommunication();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
 
        }
    }
В чём может быть проблема?
Ответ: лично я бы создал BroadcastReceiver который реагировал бы на вкл/выкл блютуза, а уже из того ресивера либо интентами через активити либо еще как-то включал-останавливал поток который слушает сокет
Java(TM) 2 Platform Standard Edition 5.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    private final BroadcastReceiver btWatcher = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
                switch (state) {
                    case BluetoothAdapter.STATE_OFF:
                        break;
                    case BluetoothAdapter.STATE_TURNING_OFF:
                        break;
                    case BluetoothAdapter.STATE_ON:
                        break;
                    case BluetoothAdapter.STATE_TURNING_ON:
                        break;
                }
            }
        }
    };
Вопрос: Возврат данных из потока

День добрый. Скажите пожалуйста: имеется функция которая возвращает Vector<String>. Ее нужно выполнить в отдельном потоке, но так чтобы потом я мог использовать возвращаеое значение в MainActivity. Как это реализовать?
Ответ: Baron Rojo, привет. Обратные вызовы. Или внутри потока по окончании его работы напишите что-то типа runOnUiThread(new Runnable(...){ ... }); а уже внутри пропишите действия, которые должны выполниться после заполнения Vector<String>.
Вопрос: Потоки не работают параллельно

Написал я такой кусок кода (все это внутри класса MainActivity):

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    class CalcFiveSecClass extends AsyncTask<Void, Void, String> {
 
        @Override
        protected String doInBackground(Void... noargs) {
            return CalcFiveSecFunc();
        }
 
        @Override
        protected void onPostExecute(String result) {
            CalcFiveSecComplete();
        }
    }
 
    public String CalcFiveSecFunc() {
        Log.i(LOG_TAG, "CalcFiveSecFunc - Begin");
        SystemClock.sleep(5000);
        Log.i(LOG_TAG, "CalcFiveSecFunc - End");
        return "";
    }
 
    public void CalcFiveSecStart() {
        Log.i(LOG_TAG, "CalcFiveSecStart");
        TimeThreadNumber++;
        CalcFiveSecClass FiveSecTask = new CalcFiveSecClass();
        FiveSecTask.execute();
    }
Пусть CalcFiveSecStart вызывается по нажатию какой-нибудь кнопки и пусть ее нажимают быстро 3 раза подряд. Я ожидал, что три функции CalcFiveSecFunc отработают параллельно в разных потоках, на деле же они работают последовательно, и в логах я вижу примерно следующее:

Java
1
2
3
4
5
6
7
8
9
CalcFiveSecStart
CalcFiveSecStart
CalcFiveSecStart
CalcFiveSecFunc - Begin
CalcFiveSecFunc - End
CalcFiveSecFunc - Begin
CalcFiveSecFunc - End
CalcFiveSecFunc - Begin
CalcFiveSecFunc - End
Почему оно так?)
Ответ: LetoLetoD, замените дефолтное поведение потоков на
Java
1
FiveSecTask.execute();
на
Java
1
FiveSecTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
и будет вам счастье
Вопрос: Как вытащить данные из потока. Cant create handler inside thread that has not called Looper.prepare()

В общем столкнулся со следующей неприятной проблемой.
Есть клиент. Он запрашивает у сервера некоторые данные. Сервер эти данные посылает клиенту. Клиент эти данные принимает и продолжает слушать входящие сообщения. Но проблемы начинаются когда я пытаюсь эти данные вытащить из потока в другой класс.
Ошибка при попытке передать данные из потока в datahandler: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

Вот код клиента
Кликните здесь для просмотра всего текста

Код Java(TM) 2 Platform Standard Edition 5.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package com.noldorknight.waiterapp;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
 
public class SocketServer {
 
    private Socket socket;
    private static final int SERVERPORT = 11000;
    private static String SERVER_IP = "192.168.2.222";
    String answer;
    private static String cmdtext;
    private static int callerid;
 
   class ClientThread implements Runnable  
   {
       public void run() {
 
            try {  //Здесь мы создаем сокет
               InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
               socket = new Socket(serverAddr, SERVERPORT);
            } catch (UnknownHostException e1) {
                e1.printStackTrace();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
           senddata(); //Здесь запускаем функцию для отправки запроса серверу
 
        }
    }
   //////////////////////////////////////// Эта функция вызывается из отдельного класса, 
   ////////////////////////////////////////того самого которому нужно вернуть ответ
   public void setserver (String command, int caller)
   {
       callerid = caller; //это просто чтобы знать из какого класса была вызвана функция(так как их будет много, и                    //////////////////////////каждый с разным запросом)
        cmdtext = command; //это текст запроса
        new Thread(new ClientThread()).start(); //запускаем поток, тот что сверху
   }
 
    private void handledata(String answer) ///эта функция отсылает целевому классу ответ
    {
        Login lgn = new Login();
        lgn.geturdata(answer);
    }
 
   private void senddata() //отсылаем запрос и слушаем ждем ответа
   {
        try {
            String str = cmdtext;
            PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
            out.println(str);
            out.flush();
            System.out.println("-------Начинаем прием данных");
            byte[] data = new byte[256];
            while (true) {
                InputStream inp = socket.getInputStream();
                inp.read(data);
                System.out.println("-------Byte data= " + data);
                answer = new String(data, "UTF-8");
                System.out.println("-------String data= " + answer);
              handledata(answer);  ///// ответ от сервера должен быть передан в другой класс 
 
            }
 
            }
        catch (UnknownHostException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}


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

И еще один вопрос. Как вы видите в отдельном потоке создается новый сокет и начинается обмен данными. Если я вызову передачу данных снова, то и сокет создастся новый, что не есть хорошо. мне нужно поместить создание сокета в отдельный поток? Вообще нужен ли отдельный поток для создания сокета?
Ответ: turbanoff, помогите мне, а то у меня тоже ошибка Can't create handler inside thread that has not called Looper.prepare() и не знаю как бороться...
Кликните здесь для просмотра всего текста
Код Java(TM) 2 Platform Standard Edition 5.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class NewThread implements Runnable {
    Thread thread;
 
    // konstruktor
    public NewThread() {
        // new potok
        thread = new Thread(this, "VKparser");
        thread.start();
    }
 
    public void run() {
        String httpString = "https://api.vk.com/method/users.get?user_id=205387401&v=5.32";
 
        HttpPost httppost = new HttpPost(httpString);
        HttpClient httpclient = new DefaultHttpClient();
 
        HttpResponse response;
 
        String responseBody;
 
        try {
 
            response = httpclient.execute(httppost);
            responseBody = EntityUtils.toString(response.getEntity());
            Log.d("!!!!!!!!!!!!!!!", responseBody);
            try {
                JSONObject jsonobject = new JSONObject(responseBody);
                JSONArray jsonarray = jsonobject.getJSONArray("response");
                jsonobject = jsonarray.getJSONObject(0);
                String name, famil;
                name = jsonobject.getString("first_name");
                famil = jsonobject.getString("last_name");
                Log.d("!!!", name);
                Log.d("!!!", famil);
                try {
                    MainActivity.getInstance().update();
                } catch (NullPointerException e) {
                    e.printStackTrace();
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
 
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

а вот код update() в MainActivity
Кликните здесь для просмотра всего текста
Код Java(TM) 2 Platform Standard Edition 5.0
1
2
3
public void update() {
        Toast.makeText(getBaseContext(), "YES ", Toast.LENGTH_LONG).show();
    }


кстати у меня вылетает приложение... и вот еще немного ошибок
05-31 00:15:40.998: E/AndroidRuntime(10441): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
05-31 00:15:40.998: E/AndroidRuntime(10441): at android.os.Handler.<init>(Handler.java:121)
05-31 00:15:40.998: E/AndroidRuntime(10441): at android.widget.Toast$TN.<init>(Toast.java:322)
05-31 00:15:40.998: E/AndroidRuntime(10441): at android.widget.Toast.<init>(Toast.java:91)
05-31 00:15:40.998: E/AndroidRuntime(10441): at android.widget.Toast.makeText(Toast.java:238)
05-31 00:15:40.998: E/AndroidRuntime(10441): at com.example.jsonparser.MainActivity.update(MainActivity.java:24)
05-31 00:15:40.998: E/AndroidRuntime(10441): at com.example.jsonparser.NewThread.run(NewThread.java:52)
05-31 00:15:40.998: E/AndroidRuntime(10441): at java.lang.Thread.run(Thread.java:856)