Когда я работал над своим проектом управляемой лампочки, я решил, что нужно как в лучших домах Парижу и Лондону сделать приложение под Android которое бы задавало цвета для светодиодов, но то с чем я столкнулся просто сбило меня столку. Те тонны приложений, доступные в Андроид Маркете, как бы намекают, что разработка под Android дело простое и не хитрое, однако у меня разработка приложения для того, чтобы банально отправить строчку с цветами для светодиодов, затянулось на недели. Вот оно:
Нужно просто убиться, чтобы добиться такого результата, если ты этого раньше не делал… Но обо всём по порядку.
Итак, Задача. Есть некий сервис, который сидит и ждёт команду… строчку. Известен IP и порт. Клиент например на perl-е тривиален:
use strict; use IO::Socket::INET; my $sock = new IO::Socket::INET(PeerAddr => '192.168.1.48', PeerPort => '6969', Proto => 'tcp') || die "Can't bind $@\n"; $sock->send(shift."\n");
вопросов нет, он работает. Если запихнуть это дело в цикл то в примере с RGB светодиодной лампой можно наблюдать нечто вроде этого:
Итак, с чем же я столкнулся? Казалось бы что тут сложного, открываем google и ищем что-нить типа How to send tcp packet in Android. Первая же ссылка выглядит вполне прилично. Читаем внимательно. Ок, делаем простое приложение, не забывая о правах для этого самого приложения
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
и… оно крашится. Googl-им сообщение об ошибке и оказывается, сетевой код не может выполняться в основном треде и для него нужен AsyncTask, что в общем-то логично, но какой-нить Warning что ли не помешал бы.
Идём дальше. Скомпиляли, запустили на эмуляторе… ни хера не происходит. Кнопка жмякается, а серверная часть молчит… Толи этот AsyncTask ещё не выполнился, толи сервак не доступен толи хер знает чего.
Окей, сделал простой сервер на perl-е и запустил локально
use strict; use IO::Socket::INET; $| = 1; my $soc = new IO::Socket::INET(LocalHost => '0.0.0.0', LocalPort => '6969', Proto => 'tcp', Listen => 5, Reuse => 1,); die " Failed $!!" unless $soc; while (1) { my $client = $soc->accept(); warn "accept: " .$client->peerhost(); my $Data = ""; $client->recv($Data, 1024); warn "$Data"; shutdown($client,1); } $soc->close();
пробую подключится с эмулятора уже на perl-овый сервер, который работает на той же машине… и опять ничего. Что за… Опять гуглю и тут начинается: и Windows говно и не хватает прав и эмулятор говно… ладно… беру старый свой HTC телефон, опять начинают ставится Driver-а, вылезать HTC Sync Manager-ы, падать ADB, Android Studio то видит, то не видит телефон, то не может подключиться…
Через какое-то время, не знаю как, мне таки удалось запустить мое приложение на телефоне, и о чудо! Оно подключается к перловому серваку, но… ни хера не шлёт. В итоге, уже не помню как я к этому пришёл, заменил код, который отсылает строчку на отсылку байтов и вуаля – оно заработало как на видео в самом верху поста.
Итак, вот моя реализация. Делаем кнопку, OnClick которой собирает данные из разных текстовых полей (например IP-адресс), создает экземпляр AsyncTask и запускает его передавая туда IP и данные о цветах
public void onClick(View v) { EditText etip = (EditText) findViewById(R.id.editText); EditText strData = (EditText) findViewById(R.id.testEditText); String ip = etip.getText().toString(); String data = strData.getText().toString(); ASColorSender asColorSender = new ASColorSender(); asColorSender.execute(ip, data); final TextView tv = (TextView) findViewById(R.id.textView); tv.setText("done"); }
и у нас имеется класс ASColorSender, который унаследован от AsyncTask и реализует один метод – doInBackground, который собственно и принимает переданные ему данные, устанавливает соединения с сервером и отсылает туда строчку с цветами:
public class ASColorSender extends AsyncTask<String,Void,Long> { @Override protected Long doInBackground(String... params) { String ip = params[0]; String data = params[1]; Socket socket = null; try { socket = new Socket(params[0].toString(), 6969); OutputStream out = socket.getOutputStream(); out.write(params[1].getBytes()); //PrintWriter output = new PrintWriter(out); //output.println("25;25;25;25;");//params[1]); socket.close(); } catch (IOException e) { e.printStackTrace(); } return new Long(1); }
отдельное “спасибо” авторам за extends AsyncTask<String,Void,Long>. Мало нам стандартных типов, давайте сделаем такие же только с блек джеком и шлюхами…
Резюмируя, видимо я не совместим с Java-ой или с разработкой под Android в принципе. Пока занимался этим проектом – пробовал некий Appcelerator, который должен сделать всё ещё проще и универсальнее, но это такой кусок говна, который ещё поискать надо. Смотришь в хелп, где написано, нажмите сюда и у вас появится пример приложения. Жмякаешь… и ничего не происходит. Там вообще много где кликаешь и ничего не происходит… Хоть бы какое сообщение типа чего не хватает или чего надо установить… но нет, просто грёбаное ничего…
Так к чему это я всё? Какой смысл в этом посте?
Если вдруг ты, случайный читатель, Java/Android девелопер и тебе вдруг нужен код, который отсылает TCP пакет, то пользуйся на здоровье. Вот.