среда, декабря 09, 2015

First launch of Activity with Google Maps is very slow / Существенная задержка при запуске activity с google map

I have a "main" activity - and an activity with mapView. When that activity-with-mapView starts for a first time, it is really slow.

clocksmith's post gave me an idea to start initialization from main activity in a separate thread. And it really solves the problem.

Here is my code from "main" activity:

    public void onCreate(Bundle savedInstanceState) {
        ...

        Runnable initMap = () -> {
            BaseApplication.d("Start init mapView");
            MapView mapView = new MapView(Home.this);
            mapView.onCreate(null);
            BaseApplication.d("... done");
        };
        new Thread(initMap).start();
    }

mapView is never used - it's only for initialization purpose.

And here is a stack trace - just for info:

    12-09 19:31:54.442 17172-17341/my.app D/XXX: Start init mapView
    12-09 19:31:54.525 17172-17341/my.app I/zzy: Making Creator dynamically
    12-09 19:31:55.007 17172-17341/my.app D/ChimeraCfgMgr: Reading stored module config
    12-09 19:31:55.153 17172-17341/my.app D/ChimeraCfgMgr: Loading module com.google.android.gms.maps from APK /data/user/0/com.google.android.gms/app_chimera/chimera-module-root/module-71c764a6f3cb92bdc5525a965b589e7c5ed304f3/MapsModule.apk
   
12-09 19:31:55.154 17172-17341/my.app D/ChimeraModuleLdr: Loading module APK /data/user/0/com.google.android.gms/app_chimera/chimera-module-root/module-71c764a6f3cb92bdc5525a965b589e7c5ed304f3/MapsModule.apk
    12-09 19:31:55.262 17172-17341/my.app D/ChimeraFileApk: Primary ABI of requesting process is armeabi-v7a
    12-09 19:31:55.271 17172-17341/my.app D/ChimeraFileApk: Classloading successful. Optimized code found.
    12-09 19:31:55.316 17172-17341/my.app W/System: ClassLoader referenced unknown path: /data/user/0/com.google.android.gms/app_chimera/chimera-module-root/module-71c764a6f3cb92bdc5525a965b589e7c5ed304f3/native-libs/armeabi-v7a
   
12-09 19:31:55.317 17172-17341/my.app W/System: ClassLoader referenced unknown path: /data/user/0/com.google.android.gms/app_chimera/chimera-module-root/module-71c764a6f3cb92bdc5525a965b589e7c5ed304f3/native-libs/armeabi
    12-09 19:31:55.618 17172-17341/my.app I/Google Maps Android API: Google Play services client version: 7571000
    12-09 19:31:55.630 17172-17341/my.app I/Google Maps Android API: Google Play services package version: 8489438
    12-09 19:31:55.969 17172-17341/my.app I/e: Token loaded from file. Expires in: 423267993 ms.
    12-09 19:31:55.969 17172-17341/my.app I/e: Scheduling next attempt in 422967 seconds.
    12-09 19:31:56.338 17172-17341/my.app D/XXX: ... done

As we can see, it realy takes a lot of time...

вторник, декабря 01, 2015

Установить английский язык в Photoshop CC 2015 / How to switch to English in Photoshop 2015

1. Перейти в / go to
C:\Program Files\Adobe\Adobe Photoshop CC 2015

2. Перейти в / go to
Locales\ru_RU\Support Files

3. Переименовать  / rename
tw10428.dat -> tw10428.dat_

4. Перезапустить / restart

четверг, мая 07, 2015

Custom isResumed method crashes application at start with java.lang.LinkageError exception

I have found an interesting case producing the java.lang.LinkageError exception.

In my base activity there is an isResumed field, I set it to true in onResume - and to false in onPause.
It's protected field.

Today I decided to add a method to get that value from a fragment, so I have added isResumed() method

public class BaseActoinBarActivity extends ActionBarActivity {

    protected boolean isResumed;

    @Override
    protected void onResume() {
        super.onResume();
        isResumed = true;
        ...
    }

    ...


    public boolean isResumed() {
        return isResumed;
    }
    
    ...
}

public class StartActivity extends BaseActionBarActivity {
...
}

Ok, after I have started my application I have got an exception:

05-07 18:45:21.020  14466-14466/? I/art﹕ Rejecting re-init on previously-failed class java.lang.Class<ru.xxxxxx.ui.base.BaseActionBarActivity>
05-07 18:45:21.020  14466-14466/? I/art﹕ Rejecting re-init on previously-failed class java.lang.Class<ru.xxxxxx.ui.base.BaseActionBarActivity>
05-07 18:45:21.020  14466-14466/? I/art﹕ Rejecting re-init on previously-failed class java.lang.Class<ru.xxxxxx.ui.StartActivity>
05-07 18:45:21.021  14466-14466/? I/art﹕ Rejecting re-init on previously-failed class java.lang.Class<ru.xxxxxx.ui.StartActivity>
05-07 18:45:21.021  14466-14466/? D/AndroidRuntime﹕ Shutting down VM
05-07 18:45:21.274  14466-14466/? E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: ru.xxxxxx.ui, PID: 14466
    java.lang.LinkageError: ru.simpls.mtsbank2.ui.StartActivity
            at dalvik.system.DexFile.defineClassNative(Native Method)
            at dalvik.system.DexFile.defineClass(DexFile.java:226)
            at dalvik.system.DexFile.loadClassBinaryName(DexFile.java:219)
            at dalvik.system.DexPathList.findClass(DexPathList.java:321)
            at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:54)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
            at ru.simpls.mtsbank2.ui.SplashScreen$1.handleMessage(SplashScreen.java:42)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5254)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

It's really funny :)

(SplashScreen is a splash screen activity, it starts StartActivity)

вторник, марта 10, 2015

Как обработать pdf в WebView / How to handle pdf in WebView

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

Удобно использовать API от Гугла:

private static final String GOOGLE_DOC_VIEW_URL = "https://docs.google.com/viewer?embedded=true&url=";

...

WebViewClient viewClient = new WebViewClient() {
   ...
    @Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.endsWith("pdf")) {
String googleDocsLink = GOOGLE_DOC_VIEW_URL + url;
Uri uri = Uri.parse(googleDocsLink);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
return true;
}
return super.shouldOverrideUrlLoading(view, url);
}
}

...

webView.setWebViewClient(viewClient);

среда, февраля 11, 2015

AnimatonDrawble - handle animation end / обработать окончание анимации


AnimationDrawble после запуска постоянно возвращает true в результате вызова isRunning, что особенно удивляет в случае onShot = true.

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


After animationDrawbale was started, isRunning method always returns true regardless the onShot value.
On way to handle animation's end is to calculate the total animation's duration and to send an event after that duration is expired.

private AnimationDrawable timerAnimation;

...

private void startTimerAnimation() {
int timerAnimationDuration = calcTimerAnimationDuration();
timerAnimation.start();
timerAnimationEndHandler.sendEmptyMessageDelayed(0, timerAnimationDuration);
}
   

private int calcTimerAnimationDuration() {
    int total = 0;
    for (int i = 0; i < timerAnimation.getNumberOfFrames(); i++) {
        total += timerAnimation.getDuration(i);
    }
    return total;
}


private Handler timerAnimationEndHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
onTimerAnimatonFinished();
};