Ответы пользователя по тегу Java
  • Как получать push-уведомления, когда приложение закрыто?

    enq3
    @enq3
    Android engineer at #ITX5
    Никак.

    RTFM https://firebase.google.com/docs/cloud-messaging/a...

    When your app is in the background, Android directs notification messages to the system tray. A user tap on the notification opens the app launcher by default.

    This includes messages that contain both notification and data payload (and all messages sent from the Notifications console). In these cases, the notification is delivered to the device's system tray, and the data payload is delivered in the extras of the intent of your launcher Activity.
    Ответ написан
  • Почему приложение лагает после создания нескольких фрагментов?

    enq3
    @enq3
    Android engineer at #ITX5
    Евгений Низамиев: Тормозить конечно будет при добавлении такого количества фрагментов в одну активность.
    Большие списки с повторяющимися элементами лучше делать через адаптеры.
    В данном случае лучше взять ViewPager и FragmentPagerAdapter (FragmentStatePagerAdapter).
    Ответ написан
  • Retrofit как авторизоваться?

    enq3
    @enq3
    Android engineer at #ITX5
    Документация нам говорит так:
    A request Header can be updated dynamically using the @Header annotation. A corresponding parameter must be provided to the @Header. If the value is null, the header will be omitted. Otherwise, toString will be called on the value, and the result used.
    @GET("/user")
    Call<User> getUser(@Header("Authorization") String authorization)

    Вообщем берем случай, когда апи нет как такового, и надо залогиниться на сайт отправив запрос, как будто мы веб-клиент.
    Подопытный kotomatrix.ru.

    При парсинге запросов выяснилось, что авторизация происходит через отправку формы.
    KotomatrixService.java
    public interface KotomatrixService {
        @FormUrlEncoded
        @POST("http://kotomatrix.ru")
        Call<String> login(@Field("login") String login, @Field("password") String pass, @Field("act") String act, @Field("remember") String remember);
    }


    ApiFactory.java
    public class ApiFactory {
        private static final int CONNECT_TIMEOUT = 15;
        private static final int WRITE_TIMEOUT = 60;
        private static final int TIMEOUT = 60;
        private static final OkHttpClient CLIENT = new OkHttpClient();
    
        static {
            CLIENT.setConnectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);
            CLIENT.setWriteTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS);
            CLIENT.setReadTimeout(TIMEOUT, TimeUnit.SECONDS);
        }
    
        @NonNull
        public static KotomatrixService getKotomatrixService() {
            return getRetrofit().create(KotomatrixService.class);
        }
    
        @NonNull
        private static Retrofit getRetrofit() {
            return new Retrofit.Builder()
                    .baseUrl("http://kotomatrix.ru")
                    .addConverter(String.class, new StringConverter())
                    .client(CLIENT)
                    .build();
        }
    }


    StringConverter.java
    public final class StringConverter implements Converter<String> {
        @Override
        public String fromBody(ResponseBody body) throws IOException {
            return body.string();
        }
    
        @Override
        public RequestBody toBody(String value) {
            return RequestBody.create(MediaType.parse("text/plain"), value);
        }
    }


    MainActivity.java
    public class MainActivity extends AppCompatActivity implements Callback<String> {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            KotomatrixService service = ApiFactory.getKotomatrixService();
            Call<String> call = service.login("testUser", "testUser", "login", "true");
            call.enqueue(MainActivity.this);
        }
    
        @Override
        public void onResponse(Response<String> response) {
            if (response.isSuccess()) {
                // ищем куку и сохраняем
            }
        }
    
        @Override
        public void onFailure(Throwable t) {
        }
    }


    В данном примере при успешной авторизации сервер отдаст kotomatrixCOOK, ищем значение тут response.rawResponse.headers и сохраняем в SharedPreferences.
    Ответ написан
  • Как быстро сравнить два списка?

    enq3
    @enq3
    Android engineer at #ITX5
    Если я все правильно понял, то клиент должен периодически запрашивать данные с сервера.
    Предлагаю такой вариант:
    Заведем еще два поля в таблице на сервере: Version и Deleted.
    При каждом изменении записи ее версия = максимальная версия в текущей таблице + 1.
    UID|HASH|Version|Deleted
    1|c4ca4238a0b923820dcc509a6f75849b|1|0
    2|c81e728d9d4c2f636f067f89cc14862c|2|0
    3|eccbc87e4b5ce2fe28308fd9f2a7baf3|4|0
    4|a87ff679a2f3e71d9181a67b7542122c|8|1
    5|e4da3b7fbbce2345d7772b0674a318d5|6|0

    Клиент запрашивает данные старше 3-ей версии.
    Вернется:
    {
        "version": 8,
        "changed": [
            {
                "UID": 3,
                "HASH": "eccbc87e4b5ce2fe28308fd9f2a7baf3"
            },
            {
                "UID": 5,
                "HASH": "e4da3b7fbbce2345d7772b0674a318d5"
            }
        ],
        "deleted": [
            {
                "UID": 4
            }
        ]
    }
    Не надо бегать по спискам и сравнивать хэши.
    Таким образом реализуется гибкий подход к клиентам с разной степенью актуальности данных. Это экономия трафика и экономия ресурсов устройства.
    Ответ написан
  • Как написать цикл с разной временной паузой для каждой команды - Android?

    enq3
    @enq3
    Android engineer at #ITX5
    Как такой вариант? В коде могут быть ошибки - пишу с планшета.
    byte[] mls = new byte[11];
    mls[0] = addCRC(new byte[]{1, 0x5, 11, 5 ,0, 0});    //10 сек
    mls[1] = addCRC(new byte[]{1, 0x5, 11, 1 ,0, 0});    //0 сек
    mls[2] = addCRC(new byte[]{1, 0x5, 0, 5 ,0, 0});      //30 сек
    mls[3] = addCRC(new byte[]{1, 0x5, 1, 5 ,0, 0});      //5 сек
    mls[4] = addCRC(new byte[]{1, 0x5, 2, 5 ,0, 0});      //5 сек
    mls[5] = addCRC(new byte[]{1, 0x5, 3, 5 ,0, 0});      //5 сек
    mls[6] = addCRC(new byte[]{1, 0x5, 4, 5 ,0, 0});      //5 сек
    mls[7] = addCRC(new byte[]{1, 0x5, 5, 5 ,0, 0});      //5 сек
    mls[8] = addCRC(new byte[]{1, 0x5, 6, 5 ,0, 0});      //5 сек
    mls[9] = addCRC(new byte[]{1, 0x5, 7, 5 ,0, 0});      //5 сек
    mls[10] = addCRC(new byte[]{1, 0x5, 8, 5 ,0, 0});      //5 сек
    
    public int[] delays = new int[11]{10,0,30,5,5,5,5,5,5,5,5};
    int shift;
    public void onClickWrite(View v) { 
        int len = mls.length;
        for (int i = 0; i < len;  i++) {
            shift += delays[i];
            new Handler(Looper.getMainLooper()).postDelayed( new Runnable() {
                public void run(){
                    byte b = mls[i];
                    mPhysicaloid.write(b, b.length);
                }
            }, shift);
        }
    }
    Ответ написан
  • Как посмотреть поставил ли я like на фото в Instagram?

    enq3
    @enq3
    Android engineer at #ITX5
    Используйте точку доступа Мои лайки.
    Там есть пагинация.
    Кэшируете всю коллекцию лайкнутых фоток в фоновом потоке в БД.
    Когда надо ищете в БД по id интересующей фотки. Если нашлось совпадение, значит лайкал.
    Да, кэшировать долго и придется переодически обновлять, но по-другому похоже никак.
    Ответ написан
  • Отправка POST запроса на сервер в АНДРОИДЕ(штатными методами из коробки)?

    enq3
    @enq3
    Android engineer at #ITX5
    HttpURLConnection
    URL url = new URL("http://backend.com/api.php");
    HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
       try {
         urlConnection.setDoOutput(true);
         urlConnection.setChunkedStreamingMode(0);
    
         OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
         writeStream(out);
    
         InputStream in = new BufferedInputStream(urlConnection.getInputStream());
         readStream(in);
        finally {
         urlConnection.disconnect();
       }
    Ответ написан
  • Чем обоснован экспоненциальный рост времени выполнения куска кода при увеличении размера массива в 10 раз?

    enq3
    @enq3
    Android engineer at #ITX5
    Скорее всего все упирается в кэш процессора, второй способ в 10 раз быстрее первого. В случае (int)(Math.random() * k) прирост по скорости будет в 2 раза:
    class Test {
    	public static void main(String[] args) {
     
    		int k = 10000;
    		long st, en;
    		int[] A;
    		int length = 100000;
     
    		A = new int[length];
    		st = System.nanoTime();
    		for (int i = 0; i < length; i++)
    		{
    			A[i] = k;
    		}
    		en = System.nanoTime();
    		System.out.println("\nOne time=" + (en - st) / 1000000.d + " msc");
     
    		int cache = 10000;
    		A = new int[length];
    		int[] temp = new int[cache];
    		st = System.nanoTime();
    		for (int N = 0; N < length; N+=cache) {
    			for (int i = 0; i < cache; i++) {
    				temp[i] = k;
    			}
    			System.arraycopy(temp, 0, A, N, temp.length);
    		}
    		en = System.nanoTime();
    		System.out.println("\nTwo time=" + (en - st) / 1000000.d + " msc");
     
    	}
    }

    Попробовать тут: ideone.com/Py6A4S

    Статья: rus-linux.net/MyLDP/hard/memory/memory-03-11.html
    Цитата:
    Более удивительной по сравнению с производительностью при чтении является производительность при записи и копировании. Производительность при записи даже для рабочих наборов с небольшими размерами, никогда не поднимается выше 4 байтов за цикл. Это указывает на то, что в таких процессорах Netburst, Intel решила использовать в кэш-памяти L1d режим с прямой записью (Write-Through), при котором скорость, очевидно, ограничена скорость работы кэш-памяти L2. Это также означает, что производительность теста копирования, в котором данные копируются из одной области памяти в другую непересекающуюся области памяти, не намного хуже. Следовательно, требуемые операций чтения выполняются намного быстрее и могут частично перекрываться с операциями записи. Самым интересными деталями измерения записи и копирования является низкая производительность в случае, как только становится мало кэш-памяти L2. Производительность падает до 0,5 байта за цикл! Это значит, что операции записи в десять раз медленнее, чем операции чтения. Это означает, что оптимизация этих операций еще более важна для выполнения программы.
    Ответ написан
  • Как вызвать Toast с другого класса?

    enq3
    @enq3
    Android engineer at #ITX5
    Это сейчас надо показывать только toast, а потом понадобится состояние контролов в активности менять или вернуть результат работы класса, и одной передачей контекста уже не обойдешься.

    MyClass.java
    public class MyClass {
        MyClassCallback callback;
    
        public MyClass() {
            if(callback != null)
                callback.done();
        }
    
        public void setCallback(MyClassCallback callback) {
            this.callback = callback;
        }
    
        public void perform() {
            if(callback != null)
                callback.done();
        }
    
        interface MyClassCallback {
            void done();
        }
    }


    MainActivity.java
    public class MainActivity extends AppCompatActivity {
        private MyClass myClass;
        private MyClass.MyClassCallback myClassCallback;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            myClass = new MyClass();
            myClassCallback = new MyClass.MyClassCallback() {
                @Override
                public void done() {
                    Toast.makeText(MainActivity.this, "Мое сообщение", Toast.LENGTH_LONG).show();
                }
            };
            myClass.setCallback(myClassCallback);
            myClass.perform();
        }
    }
    Ответ написан
  • Как мне это реализовать?

    enq3
    @enq3
    Android engineer at #ITX5
    А если вот так?
    activity_main.xml
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <ListView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:listSelector="@color/item_color_test"
            android:id="@+id/listView"/>
    
    </RelativeLayout>


    MainActivity.java
    public class MainActivity extends AppCompatActivity {
        private final static String KEY = "selectedRow";
    
        private MyAdapter adapter;
        private int selectedItem = 1;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            ListView listView = (ListView) findViewById(R.id.listView);
            final String[] data = {
                    "a","v","c"
            };
            if(savedInstanceState != null && savedInstanceState.containsKey(KEY))
            {
                selectedItem = savedInstanceState.getInt(KEY);
            }
            adapter = new MyAdapter(this, R.layout.item, data, selectedItem);
            listView.setAdapter(adapter);
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    String selected = data[position];
                    selectedItem = position;
                    adapter.setSelectedRow(selectedItem);
                }
            });
        }
    
        @Override
        protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            outState.putInt(KEY, selectedItem);
        }    
    
        private class MyAdapter extends ArrayAdapter<String> {
            final int resId;
            int selectedRow;
    
            public MyAdapter(Context context, int resId, String[] data, int selectedRow) {
                super(context, resId, data);
                this.resId = resId;
                this.selectedRow = selectedRow;
                selectedColor = getResources().getColor(R.color.item_color_test);
            }
    
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                String string = getItem(position);
    
                if (convertView == null) {
                    convertView = LayoutInflater.from(getContext()).inflate(resId, null);
                }
                TextView textView = (TextView) convertView;
                textView.setText(string);
                textView.setBackgroundColor(position == selectedRow ? selectedColor : 0x00000000);
                return convertView;
            }
    
            public void setSelectedRow(int row)
            {
                selectedRow = row;
                notifyDataSetInvalidated();
            }
        }
    }


    item.xml
    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:paddingTop="20dp"
        android:paddingBottom="20dp"
        android:paddingLeft="10dp"/>


    В собственной реализации адаптера с шаблоном строки списка можно делать что угодно.
    Ответ написан
  • Можно ли создать два AsyncTask'a в одном классе?

    enq3
    @enq3
    Android engineer at #ITX5
    Можно. Начиная с версии 1.6 по умолчанию таски выполнялись в пуле потоков, что позволяло запускать несколько тасков параллельно. А вот начиная с версии 3.0 это поведение по умолчанию убрали, чтобы исключить ошибки с параллельным выполнением кода. Если действительно требуется выполнять несколько тасков одновременно, то используем метод executeOnExecutor. Но держим в уме, что при повороте устройства AsyncTask будет пересоздан.
    if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
        new MyTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    } else {
        new MyTask().execute();
    }

    Не рекомендую использовать IntentService для данной задачи, т.к. IntentService помещает все запросы в очередь и выполняет их по-одному, пока очередь не опустеет.

    Посмотрите в сторону Bound Service.
    Ответ написан