пятница, декабря 21, 2012

Как обновить содержимое ViewPager, работающего с FragmentStatePagerAdapter

Потратил несколько часов, пытаясь сделать простую вещь. Есть:
1. ViewPager
2. адаптер, полученный на базе FragmentPagerAdapter
3. какой-то набор данных в виде списка.

Адаптер из этого списка умеет создавать объекты-фрагменты, а viewPager их показывает.

Интересность в том, что набор данных может меняться в то время, когда viewPager активен - следовательно, нужно изменять и отображаемые в нём данные.

Тут началось самое интересное. После изменения набора данных я пытался:
1. создавать новый адаптер на основании нового набора данных и присваивать его viewPager посредством вызова setAdapter
2. использовать существующей адаптер и вызывать его метод notifyDataSetChanged()

Результат в каждом из вариантов не радовал - либо viewPager начинал дублировать существующие страницы, либо отображать те, данные по которым уже были удалены.

Оказалось, что всё проще - в случае, если набор данных может меняться, правильно использовать FragmentStatePagerAdapter. Этот адаптер не создаёт все элементы сразу, а делает это по необходимости. При этом нормально решается проблема с динамически меняющимся содержимым. 

вторник, декабря 11, 2012

Декомпилятор Java

Как-то не доводилось до этого, а тут понадобилось попользоваться декомпилятором Java. Понравился проект Java Decompiler - удобно и красиво получается. Есть отдельное GUI-приложение, а есть плагин для Eclipse.


среда, ноября 28, 2012

Преобразование java-объекта, списка java-объектов в JSON и из JSON

Пусть есть такой простой класс


class Book {
private String name;
private List authors;
        ...
}

Мне нужно отображать экземпляры этого класса либо список таких экземпляров в JSON и получать их из JSON обратно.

Попалась и понравилась библиотека Gson от гугла, с ней такие вещи делаются легко и удобно. К проекту нужно добавить одну jar-ку размером 185KB.

Отображение одного объекта 

Book book = new Book();

book.setName("Test Book");
book.addAuthor("A");
book.addAuthor("Б");

Gson gson = new Gson();
String result = gson.toJson(book);

В результате получаем:
{"name":"Test Book","authors":["A","Б"]}

Восстановление объекта из JSON

book = gson.fromJson(result, Book.class);


Отображение списка объектов

Book book2 = new Book();
book2.setName("Test Book 2");
book2.addAuthor("A2");
book2.addAuthor("Б2");

List books = new ArrayList();
books.add(book);
books.add(book2);
String booksStr = gson.toJson(books);

Получаем:
[{"name":"Test Book","authors":["A","Б"]},{"name":"Test Book 2","authors":["A2","Б2"]}]

Восстановление списка объектов

Type collectionType = new TypeToken>(){}.getType();
List gBooks = gson.fromJson(booksStr, collectionType);

Готово!



четверг, октября 25, 2012

Размер шрифта на Galaxy Note

Пользователи жалуются на то, что на данном устройстве шрифт отображается очень уж маленького размера. Что надо сделать - понятно: определить специальный набор ресурсов. Осталось понять, как этот набор ресурсов специфицировать, чтобы Андроид смог бы использовать именно его и именно для этого устройства (или для аналогичных, хотя таких вроде и нет).

Погуглив, нашёл статью Android UI design tips for Samsung Galaxy Note

Подробности в статье, вывод: ресурсы складывать в каталоги вида drawable-large-hdpi


среда, сентября 26, 2012

Как убрать мерцание в конце анимации

Искал способ побороть мерцание в конце анимации, нашёл случайно на stackoverflow.

Суть такая:
у меня есть view, который мне нужно сдвинуть вниз на величину height. Для отображения такого сдвига я использую TranslateAnimation.
После окончания работы animation я устанавливаю значение marginTop для сдвинутого view - чтобы "закрепить" его в новом положении.

Проблема: после окончания движения view происходит "мерцание" - или перерисовка - сдвигаемого объекта.

Как решить: в методе слушателя onAnimationEnd принудительно остановить выполнение анимации вызовом метода view.clearAnimation.

Вот как это выглядит:


private void animateMoveDown(final View view, final int height) {
Animation animation = new TranslateAnimation(
Animation.ABSOLUTE, 0,
Animation.ABSOLUTE, 0,
Animation.ABSOLUTE, 0,
Animation.ABSOLUTE, height);

animation.setDuration(500);
animation.setInterpolator(new LinearInterpolator());
animation.setAnimationListener(new AnimationListener() {

@Override
public void onAnimationStart(Animation animation) { }

@Override
public void onAnimationRepeat(Animation animation) { }

@Override
public void onAnimationEnd(Animation animation) {
view.clearAnimation();

MarginLayoutParams mparams = (MarginLayoutParams) view.getLayoutParams();
mparams.setMargins(0, height, 0, 0);
view.setLayoutParams(mparams);
}
});
view.startAnimation(animation);
}


пятница, августа 03, 2012

Как сгенерировать SHA-1 дайджест по строке (в том числе и в Android)



public class SecurityUtils {
public static String getSHA1Digest(String str) throws NoSuchAlgorithmException {
if (str == null || str.trim().length() == 0) {
throw new InvalidParameterException("Не указано значение  строки");
}
MessageDigest sha = MessageDigest.getInstance("SHA-1");
byte[] bytes = str.getBytes();
sha.update(bytes);
byte[] digest = sha.digest();

StringBuilder sb = new StringBuilder(40);
for (int i = 0; i < digest.length; i++) {
String hexVal = String.format("%02x", Integer.valueOf((digest[i] + 256) & 0xFF));
sb.append(hexVal);
}

return sb.toString();
}
}

Проверяем:


public class SHA1Test extends TestCase {

public void testSHA1() {
   String sourceString = "12345";
   String expectedResult = "8cb2237d0679ca88db6464eac60da96345513964";
   String result = "";
 
   try {
result = SecurityUtils.getSHA1Digest(sourceString);
} catch (NoSuchAlgorithmException e) {
assertTrue(e.getMessage(), false);
}
 
   assertEquals(expectedResult, result);  
}




четверг, мая 03, 2012

create database link и ошибка SQL Error: ORA-00933: SQL command not properly ended

Понадобилось создать линк к удалённой БД.
Смотрю пример в документации:


CREATE DATABASE LINK local 
   CONNECT TO hr IDENTIFIED BY hr
   USING 'local';


и выполняю
create database link mylink connect to schema_name identified by 123456 using 'orcl'

В результате получаю сообщение об ошибке:

SQL Error: ORA-00933: SQL command not properly ended
00933. 00000 -  "SQL command not properly ended"

Разницы от того, выполняется ли запрос из SQL Developer или из sqlplus, нет никакой.

Как оказалось, значение пароля (123456) нужно указать в двойных кавычках - да и другие параметры тоже лучше в них, т. е. вот так:

create database link "mylink" connect to "schema_name" identified by "123456" using 'orcl'


При этом orcl - именно в одинарых.

среда, апреля 18, 2012

TextView, ellipsize, maxLines и странности

Есть у меня такой TextView:

    [TextView
        android:id="@+id/news_item_text"
        style="@style/text_plain_embossed"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:ellipsize="end"
        android:maxLines="4"
        android:text="Здесь текст новости, который может быть очень очень очень длинным и не помещаться на одну строку. Шла Маша по шоссе и сосала сушку. Чем дальше в лес, тем толще партизаны. Странный аттрактор не имеет выхода."/]

Всё, что я от него хочу, это:

  • чтобы длинный текст отображался бы в 4 строки (android:maxLines="4" )
  • чтобы в конце текста, если он не помещается целиком, добавлялось бы многоточие ( android:ellipsize="end")
И вот тут начинается самое интересное. В разных версиях (я тут вначале опечатался и набрал слово "весрия", но иногда хочется именно так и оставить) Андроида результат отображения этого представления получается весьма разный. Изображения сняты из эмулятора, но на устройствах они получаются такими же (проверялось на HTC Desire (2.3), Samsung Galaxy Tab 7.7 (3.2) и на Samsung Galaxy S II (4.0)).

Android 2.2

Android 3.2


Android 4.0

Видно, что:
Android 2.2 - количество строк - плохо, многоточие - хорошо.
Android 3.2 - количество строк - хорошо, многоточие - плохо
Android 4.0 - количество строк - хорошо, многоточие - хорошо.

При этом, в если убрать android:ellipsize="end", то в 2.2 получается вот так:
Android 2.2, без ellipsize

И как с этим бороться?!



пятница, апреля 06, 2012

Отформатировать копейки в рубли с разделителями групп и с точкой

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


private static DecimalFormat currencyFormat;
static {
     currencyFormat = new DecimalFormat();
     DecimalFormatSymbols dfs = currencyFormat.getDecimalFormatSymbols(); 
     dfs.setDecimalSeparator('.'); 
     currencyFormat.setDecimalFormatSymbols(dfs);
     currencyFormat.setMinimumFractionDigits(2); 
     currencyFormat.setMaximumFractionDigits(2); 
     currencyFormat.setGroupingSize(3);
     currencyFormat.setGroupingUsed(true);
}

int amount = ...
double roubles = (double) amount / 100;
return currencyFormat.format( roubles );

среда, марта 21, 2012

Как программно добавить строки с колонками одинаковой ширины в TableLayout

Если коротко - для каждой колонки (т. е. для содержимого TableRow) нужно задать
layout_width="0dp"
layout_weight="1"

Вот пример кода
// Важно импортировать именно этот класс LayoutParams - иначе
// строки просто не покажутся
import android.widget.TableRow.LayoutParams;

import static android.view.ViewGroup.LayoutParams.FILL_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;



@ViewById(R.id.datatable)
TableLayout datatable;
...   ...   ...


for (ParamValue param : params) {
TableRow row = new TableRow(this);
row.setLayoutParams(new LayoutParams(FILL_PARENT, WRAP_CONTENT));

TextView paramName = new TextView(this);
paramName.setText(param.parameter);
paramName.setLayoutParams(new LayoutParams(0, WRAP_CONTENT, 1));

TextView paramValue = new TextView(this);
paramValue.setText(param.value);
paramValue.setLayoutParams(new LayoutParams(0, WRAP_CONTENT, 1));

row.addView(paramName);
row.addView(paramValue);

datatable.addView(row, new LayoutParams(FILL_PARENT, WRAP_CONTENT));
}





пятница, марта 09, 2012

FrameLayout и layout_marginTop

Не знаю, баг это или фича, но в случае, если view находится внутри frameLayout, то установка этому view свойства layout_marginTop ни на что не влияет - view по-прежнему располагается без отступа сверху.

Чтобы этот отступ сверху появился бы, нужно дополнительно задать этому view значение layout_gravity="top".

пятница, февраля 10, 2012

Пользователи phpbb3 не могут отправлять личные сообщения

Установил phpbb 3.0.10, создал пользователя и обнаружил, что ему не доступна возможность отправки личных сообщений:
Вам не разрешено использовать данную возможность. Возможно, вы недавно зарегистрировались на конференции или вам необходимо проявить больше активности на ней, чтобы получить такое право.
Обнаружил, что, начиная с 3.0.x (не помню с какой именно), появилась группа "Новые пользователи". Регистрируемые пользователи форума автоматически включаются в состав этой группы до тех пор, пока они не отправят заданное количество сообщений. Члены этой группы ограничены в возможностях отправки личных сообщений.

Количество сообщений задаётся в настройках: "Общие - Регистрация пользователей", пункт "Лимит сообщений для новых пользователей". По-умолчанию это значение установлено в 3. Если изменить его на 0, то новые пользователи в эту группу включаться не будут.



phpbb - Как настроить cookies для компьютера без имени домена

Понадобилось поставить phpbb3 на комп, для которого отсутствует доменное имя.
В общем случае phpbb в настройках кук такое не ожидает увидеть и в результате использует для отслеживания сессий не куки, а SID. Автоматический вход на форум в таком случае не работает. 

Вот здесь нашёл такое решение:
Пусть адрес форума имеет вид: http://mycomp/phpbb

В файле /includes/session.php нужно найти метод set_cookie и заменить в этом методе строку 'localhost' на имя компьютера 'mycomp'.

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