‘解決’ カテゴリーのアーカイブ

Android 5.0 LollipopでImageViewがButtonの下に隠れる

4系では問題なく表示されていたToggleButtonにかぶせたImageViewが、Lollipopで表示されないという問題がありました。

image.png
4系

image.png
Lollipop

ちなみにレイアウト構成はこんな感じ。FrameLayoutで単純に2枚のViewを重ねているだけです。

image.png

ImageViewの背景色を変更して確認してみたところ、Viewの重なり順(Z-Order)が逆になってしまっていて、ToggleButtonの下にImageViewが入ってしまっているようでした。

マテリアルデザインの影響で、ボタンは影が入るようになったため、前面に移動してしまっているようです。

Android – Buttonのelevationを設定する方法 – Qiita

で、奥行きを修正するために、ImageViewの方をtranslationZで2単位ほど手前に出せば良いらしい。

Android 5.0 – ProgressBar cannot be displayed over a Button – Stack Overflow

<ImageView
android:id=”@+id/image”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:contentDescription=”@null”
android:scaleType=”fitCenter”
android:translationZ=”2dp”
tools:ignore=”UnusedAttribute” />

で、解決しました。

あ、translationZはAPI Level 21からのアトリビュートなので、プロジェクトの方も設定が必要です。

image.png

試してませんが、stateListAnimatorでやる方が正しいかもしれません。

あと、ToggleButtonに限らず、Button系はこの現象が起きるようです。ボタンの上に何かを重ねている人は注意。


仮想マシンのdebianをHyper-VからVirtualBoxに移行したら起動しなかった話

ゲストの環境は32ビットでjessie/sidです。
ホストはWindows 8.1 x64。

Windows 7でVirtual PCを使って動かしていたイメージですが、Windows 8.1に乗り換えるにあたって、Hyper-Vに移行していました。
こっちはそんなに問題なかったのですが、Hyper-Vのネットワーク設定がやりたかったことをすべて満たせない&なぜかゲストでhg pushするとホストのインターフェースが死ぬという現象に見舞われたので、VirtualBoxに移行することにしました。

ちなみに移行はVHDファイルを持ちまわるだけです。

色々問題噴出だったのですが、最終的にはVirtualBoxの設定でどうにかなりました。

エラー内容覚えていないので、検索履歴から箇条書きで。

・VERR_REM_VIRTUAL_CPU_ERROR
・VBOX_E_INVALID_VM_STATE
・fatal error in recompiler cpu 中略 VERR_DEADLOCKのエラーでVirtual Boxが落ちる
・VirtualBox自体は落ちなくなったものの、loading please waitで止まる
・smbus base address uninitialized upgrade bios or use

やったこと。
・設定→システム→マザーボードの「メインメモリー」を512MBから1024MBにした
・設定→システム→マザーボードの「チップセット」をICH9にした
・設定→システム→マザーボードの「I/O APICを有効化」にチェック
・設定→システム→プロセッサーの「PAE/NXを有効化」にチェック
・GRUB2起動時にeを押して編集モードに入り、linuxから始まる行の末尾にsingleを追加してシングルユーザーモードで起動できるか確認
・起動時に画面に表示されない何かの処理が裏で動いているらしいのを、10分以上待った

カーソルが点滅しているなら、気長に待ってみるのも良いかと。

squeezeのときのイメージが残っていたので、そっちも試したのですが、そっちは大丈夫でした。
Hyper-V上でkernelとディストリビューションをアップデートして、686-paeになったのが問題だったかも。

とりあえず復旧できたので良かったです。


PhalconのコマンドラインでError: This command should be invoked inside a Phalcon project directory

phalcon create-modelをしようとして、上記エラーが発生しました。

プロジェクトディレクトリで実行しろということなのですが、プロジェクトディレクトリには既にいるはず…

Error: This command should be invoked inside a Phalcon project directory – Discussion – Phalcon Framework

上記サイトでは.phalconファイルを作成すれば良いという話。が、正解は.phalconディレクトリを作る必要があります。

結局のところ、プロジェクトを自分で作った人ではなく、リポジトリからダウンロードしてきた場合に多く発生します。

というのも、自分のところはMercurialですが、中身が空のディレクトリがリポジトリに登録できないという仕様なので、.phalconディレクトリをリポジトリにコミットし損ねていたということですね。

$ mkdir ./.phalcon
$ touch ./.phalcon/empty

などとして、ファイルを追加してコミットしておけば解決です。


Volleyが勝手にリダイレクトするのを禁止する方法

サーバから302が返ってきたときに、Volleyが自動的にリダイレクトするのですが、開発用のAPIなどでBasic認証ヘッダを追加している場合など、リダイレクト先にも認証ヘッダを付けたままリクエストしてしまいます。

これが原因でAWS S3からデータが取れないということがありました。

とりあえず勝手にリダイレクトしないようになれば良いので、HttpURLConnectionのsetInstanceFollowRedirectsをfalseにすることで対応しました。

public class MyHurlStack extends HurlStack {

    @Override
    protected HttpURLConnection createConnection(URL url) throws IOException {
        HttpURLConnection connection = super.createConnection(url);

        // 自動リダイレクトを禁止する
        connection.setInstanceFollowRedirects(false);
        connection.setRequestProperty("Accept-Encoding", "");

        return connection;
    }

    @Override
    public HttpResponse performRequest(Request<?> request,
            Map<String, String> additionalHeaders) throws IOException,
            AuthFailureError {
        URL url = new URL(request.getUrl());
        if (url.getHost().equals("開発環境のホスト名")) {
            // Basic認証ヘッダの追加
            additionalHeaders
                    .put("Authorization", "Basic ********************");
        }

        return super.performRequest(request, additionalHeaders);
    }

}

setInstanceFollowRedirectsは

HTTP リダイレクト (応答コード 3xx の要求) を、この HttpURLConnection インスタンスで自動に従うかどうかを設定します。

とのこと。

HttpURLConnection (Java Platform SE 6)


FragmentTabHost+SupportMapFragmentで画面が真っ白になる

Android Support Library v4を使っていますが、FragmentTabHostのタブのひとつにSupportMapFragmentを継承したFragmentを配置、その地図上のマーカーから同じタブ内に詳細情報表示用のFragmentを表示させるようにしていました。

詳細情報表示用のFragmentを開いたまま、他のタブに行く際に、Fragmentスタックを全部クリアしてから移動するのですが、そうするとこのタブに戻ってきたときにSupportMapFragmentがまったく反応しなくなってしまいます。

対策としては、一度detach/removeしておいて、再度SupportMapFragmentのインスタンス化をして、Transactionにaddという流れでした。

    @Override
    public void onTabChanged(String tabId) {
        FragmentManager fm = getSupportFragmentManager();
        // 移動前に既存のFragmentスタックをクリアする
        for (int i = 0; i < fm.getBackStackEntryCount(); ++i) {
            fm.popBackStack();
        }

        // 地図タブから移動する場合は、再アクティブ化のために一度Fragmentをデタッチする
        if (lastTabId != null && lastTabId.equals("map_section")) {
            MapSectionFragment fragment = (MapSectionFragment) fm
                    .findFragmentByTag(lastTabId);
            if (fragment != null) {
                FragmentTransaction ft = fm.beginTransaction();
                ft.detach(fragment);
                ft.remove(fragment);
                ft.commit();
            }
        }
        // 地図タブを開くときは、removeされていれば再インスタンス化する
        if (tabId.equals("map_section")) {
            // FragmentTabHost.onTabChangedでcommitされたスタックを先に反映させないとfindできない
            fm.executePendingTransactions();

            MapSectionFragment fragment = (MapSectionFragment) fm
                    .findFragmentByTag(tabId);
            FragmentTransaction ft = fm.beginTransaction();
            if (fragment == null) {
                // インスタンス化
                fragment = (MapSectionFragment) Fragment.instantiate(this,
                        MapSectionFragment.class.getName(), null);
                // Fragmentを追加
                ft.add(R.id.content, fragment, "map_section");
            }
            ft.commit();
        }

        // 最後に開いたタブのタグを保持する
        lastTabId = tabId;
    }

今回キモだったのはexecutePendingTransactions()です。

v4/java/android/support/v4/app/FragmentTabHost.java – platform/frameworks/support – Git at Google

FragmentTabHostのソースを見ると、doTabChangedメソッドで同様の処理を実行してFragmentのインスタンス化、追加を実行、コミットしているにも関わらず、findFragmentByTagがnullを返す現象が発生しました。

これはコミットが実際にはすぐには実行されず、メインスレッドにスケジューリングされるためだそうです。

android – Can’t find fragment by tag – Stack Overflow

ドキュメントに書いてありました。

FragmentTransaction | Android Developers

executePendingTransactionsを実行しておけば、地図が二重に表示されるなどの現象はなくなります。


Windows版PHP 5.4.0でAPCを使う

まずはAPCをダウンロードします。

downloads.php.net/pierre/

php_apc-3.1.10-5.4-vc9-x86.zip (2012-04-11 23:46 -0700)
をダウンロードしました。

展開すると、ntsとtsのフォルダが作成されます。使っているPHPがNon Thread Safe版かThread Safe版かによって使う方を決めてください。

それぞれのフォルダの中に、php_apc.dllがあるので、phpがインストールされているフォルダのextフォルダにコピーします。

その後、php.iniを開いて
extension=php_apc.dll
を追加し、Apacheを再起動すればOKです。

ちなみに、dllのバージョンを見ると、5.4.1RC1-devと書かれていました。

phpinfo()ではこのようになります。特に問題なく使えているようです。

WS000000


Mouse without Bordersでルータを超える

Microsoft The Garageから提供されたMouse without Bordersは、Synergyのような、一台のキーボードとマウスで、他のPCを操作できるソフトウェアです。

Microsoft download from The Garage: Mouse without Borders – Next at Microsoft – Site Home – TechNet Blogs

これがかなり便利で、複数のPCを使う人にはぜひおすすめしたいところです。

Synergyと比べて、優れている点はこんなところです。

  • 人に勧められるレベルの簡単さ
  • UAC対応
  • ファイルのコピーがスクリーン間でドラッグアンドドロップでできる
  • 2台のPCのどちらのマウス(キーボードでも可)を使っても、双方向に操作できる
  • 1台のマウス(キーボードでも可)で複数のPCに、同時に同じ操作をさせられる
  • スクリーンの位置設定なども自動的に同期してくれる
  • ログイン前でも操作可能

Windowsキー+Lでのロックは、SynergyでもMouse without Bordersでも同じように両画面ロックしてしまうみたいですね。

インストール方法はこちらを参考にしてください。

窓の杜 – 【NEWS】Microsoft、複数PCでマウス・キーボードをLAN共有する「Mouse Without Borders」

で、今使っているLANの中に、もう一台ルータがいて、その中でまた別のネットワークを構築しているのですが、そのネットワーク内にあるPCと、外側のPCとでMouse without Bordersを使ってみました。

ちなみにWINSはない環境です。

image

Mouse without Bordersはコンピュータ名で接続先PCを特定するため、コンピュータ名からIPが特定できないといけません。

まず、それぞれのPCのhostsファイルに相手のIPを記述します。

PC1 C:\Windows\System32\drivers\etc\hosts
192.168.0.10 PC2

PC2 C:\Windows\System32\drivers\etc\hosts
172.16.10.1 PC1

ルータにはファイアウォールなどは入れていないので、これだけの設定でPC2からPC1への接続はできます。もしPC2からPC1を操作するだけなら、これで十分です。

双方向操作や、PC1からPC2を操作する場合はもう少し設定が必要です。

Mouse without BordersはデフォルトではTCPで接続するようになっています。使われるポート番号は15100と15101です。これをルータでアドレス変換してあげる必要があります。

AirStationでの設定はこんな感じです。

image

ちなみに15101だけでも接続できました。15100は何に使っているのか謎です。

これでルータは通るようになりましたが、192.168.0.10がどこを指すのか、PC1にはわかりません。

ですので、静的ルーティングを設定します。

管理者権限でコマンドプロンプトを開いて、
> route -p add 192.168.0.0 mask 255.255.255.0 172.16.10.2
とすればOKです。-pオプションは永続化です。

これで快適に2台のPCを操作できるようになりました。


WindowsにISC BIND9をNSISでインストールする

WindowsでDNSサーバを立てるにあたってBINDを使ったのですが、標準のBINDInstall.exeが使いにくいのと、サイレントインストールしたかったので、NSISを使ってインストーラーを作る方向にしました。

基本的には全部展開して設置したあと、VC2005再頒布可能パッケージをインストールして、named.exeをサービス登録するだけです。

ファイアウォールの許可もしています。

プラグインを3つ使っています。
Nsisunz plug-in – NSIS Zipの展開
NSIS Simple Service Plugin – NSIS サービス登録
NSIS Simple Firewall Plugin – NSIS ファイアウォール登録
Zipを二重にするのももったいないので、あらかじめ展開しておくのが妥当かとは思います。

設定ファイルは適当に作ってください。

あと肝心のBINDはこちら。
BIND | Internet Systems Consortium

!include "MUI.nsh"
!include "Sections.nsh"

!define TEMP $R0
!define TEMP2 $R1
!define VAL1 $R2
!define VAL2 $R3

Name "BIND9 Installer"
OutFile "setup.exe"

InstallDir "C:\dns"

!define BIND9_FILENAME "BIND9.8.1-P1.zip"

Section auto_setup
  
  SetOutPath "$TEMP"
  File "${BIND9_FILENAME}"
  
  SetOutPath "$INSTDIR\bin"
  nsisunz::Unzip "$TEMP\${BIND9_FILENAME}" "$INSTDIR\bin"
  
  ; VC++ 2005 redistインストール
  ExecWait '"$INSTDIR\bin\vcredist_x86.exe" /q:a /c:"VCREDI~1.EXE /q:a /c:""msiexec /i vcredist.msi /qb!"" "' 
  
  ; BINDのインストールディレクトリをレジストリに登録
  WriteRegStr HKLM "SOFTWARE\ISC\BIND" "InstallDir" "$INSTDIR"
  
  ; etcとconfに設定ファイルを配置する
  SetOutPath "$INSTDIR\conf"
  File /r "conf\*.txt"
  
  SetOutPath "$INSTDIR\etc"
  File "named.conf"
  ExecWait '"$INSTDIR\bin\rndc-confgen" -a -b 512'
  
  ; Firewall許可
  SimpleFC::AddApplication "ISC BIND" "$INSTDIR\bin\named.exe" 0 2 "" 1
  
  ; BINDをサービスに登録
  SimpleSC::InstallService "BIND" "ISC BIND" "16" "2" "$INSTDIR\bin\named.exe" "" "NT AUTHORITY\NetworkService" ""
  
  ; BINDサービス起動
  SimpleSC::StartService "BIND" "" 30

SectionEnd

Section "Uninstall"
  
  ; サービス停止と解除
  SimpleSC::StopService "BIND" 1 30
  SimpleSC::RemoveService "BIND"
  
  ; レジストリ削除
  DeleteRegKey HKLM "SOFTWARE\ISC\BIND"
  
  ; Firewall解除
  SimpleFC::RemoveApplication "$INSTDIR\bin\named.exe"
  
  ; ファイル削除
  RMDir /r "$INSTDIR"
  
SectionEnd


URLGrabberでFatal Python error: deallocating None

URLGrabberで数千件のURLをkeep-aliveで取得しようとすると、大体同じような回数でFatal Python error: deallocating Noneが出ることがあります。

どうやら、PycURLの参照カウントの問題らしいです。

パッケージでインストールされるものは古いので、PycURLを最新のソースからインストールしなおしましょう。以下、環境はDebian squeeze+python 2.6。

python-pycurlをすでにインストールしている場合はアンインストールしておく必要があります。

# aptitude install python-pycurl
でインストールしている場合は、
# aptitude purge python-pycurl
でアンインストールしておきましょう。

pycurlは最新のものをsourceforgeのCVSからダウンロードします。

SourceForge.net Repository – [pycurl] Index of /pycurl
下の方にある、「Download GNU tarball」のリンクからtarファイルをダウンロードできます。
ダウンロードしたファイルをpycurl.tar.gzなどに名前変更して、tar xvzf pycurl.tar.gzで展開できます。

ビルドにはcurl-configとPython.hなどが必要なので、必要なパッケージをインストールしておきます。

# aptitude install python2.6-dev libcurl4-gnutls-dev

pycurl.tar.gzを展開したら
# cd ./pycurl/
# python setup.py install
で、インストール完了です。

ちなみに、python2.6-devをインストールしていないと、
src/pycurl.c:42:20: error: Python.h
のようなエラーが大量に出ます。

とりあえずこれで、今のところ安定動作しています。


DoctrineMongoDBBundleでAbstractDoctrineExtensionのエラー

PHP Fatal error:  Class ‘Symfony\\Bridge\\Doctrine\\DependencyInjection\\AbstractDoctrineExtension’ not found in /home/path/to/Symfony/vendor/bundles/Symfony/Bundle/DoctrineMongoDBBundle/DependencyInjection/DoctrineMongoDBExtension.php on line 31

php – DoctrineMongoDBBundle getting a fatal error in Symfony2 – Stack Overflow

masterリポジトリが書き換えられていて、最新バージョンでは動かないのでdepsファイルにDoctrineMongoDBBundleのレポジトリを指定するときに、バージョン番号を指定する必要があるということでした。
DoctrineMongoDBBundleセクションにversion=v2.0.0を追加すればOKです。

[doctrine-mongodb]
    git=http://github.com/doctrine/mongodb.git

[doctrine-mongodb-odm]
    git=http://github.com/doctrine/mongodb-odm.git

[DoctrineMongoDBBundle]
    git=http://github.com/symfony/DoctrineMongoDBBundle.git
    target=/bundles/Symfony/Bundle/DoctrineMongoDBBundle
    version=v2.0.0