Android Eclipse MATでメモリーリークの可能性がある画像が何かをつきとめる

Android
Eclipse

Android Eclipse MATでメモリーリークの可能性がある画像が何かをつきとめる

MATと言えば、マット・デーモンでもなく、マット・ボマーでもなく、Eclipseのプラグイン、Memory Analyzer Toolですね。

MAT自体のインストールや使い方は、下記のブログさんが大変参考になりました。m(_ _)m

http://tlync.hateblo.jp/entry/20111220/1324372308

で、じゃあ色々わかった時に、Leak Suspects(メモリーリークの疑いがあるやつら)の中に、Bitmap画像が入っていた時に、多少テクニックが必要だったので、書いておきます。

↓の記事が大変参考になりました。

MAT (Eclipse Memory Analyzer) – how to view bitmaps from memory dump
http://stackoverflow.com/questions/12709603/mat-eclipse-memory-analyzer-how-to-view-bitmaps-from-memory-dump

下記は、とりあえずの上記サイトの和訳です。

  • GIMPをインストールする
  • BitmapオブジェクトのmBufferフィールドを右クリックし、 “Copy” -> “Save Value To File” を選択、 どこかに保存する
  • GIMPで上記で保存したファイルを開く
  • “Load Image from Raw Data”を選択
  • RGBかRGBアルファなどの形式を選択するダイアログになりますが、おそらくRGBアルファでOK
  • 画像の縦と横を入力

私が止まってしまったのは、この最後の 画像の縦と横を入力しなければいけないところです。
上記の人は、さらっとMATで見れるよ~ 的なことを書いてあります。

縦と横?どこにあるの??

それは次の手順で見れます。

  • EclipseのWindow→Show View→Other→Memory Analyzer Views→Inspectorを開きます。
  • Inspectorのビューは、MATのオブジェクトを選択すると、連動して色々な情報を表示してくれます。
  • MATのメインのビューでLeak Suspectsから、怪しいオブジェクトを選択し、mBitmapを選択します。
  • すると、InspectorにAttributesという画面に、画像の縦幅と横幅が表示されます。

mat_inspector.png

Android CustomeViewの作り方 サンプルコード

Android

Android CustomeViewの作り方 サンプルコード

Androidではいろんなビューの作り方がありますが、複雑な図形や動的な図形を出したいときは、CustomeViewというので作ると便利です。
実戦では使わなかったのですが、勉強したことをまとめておこうと思います。
私の場合はとある画像を配置したいというだけだったのですが、グラフや規則性のある図形などはCustomeViewがもっと活躍するでしょう。

実のところ、何が難しかったかというと、レイアウトファイル(xml)のほうですね。

 res/layout/main_activity.xmlファイル内
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:custom="http://schemas.android.com/apk/res/my.application" //ここで、アプリケーションの名前を指定します 
 
     android:id="@+id/overlay_dialog"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_centerInParent="true"
     android:orientation="vertical" >
 
 	<my.application.view.BaloonUpward //CustomViewを呼び出すのは、この宣言だけで呼び出せます
    		android:id="@+id/baloon_1"
    		android:layout_width="300dp"
 	        android:layout_height="300dp"
                android:drawableLeft="@drawable/baloon_upward"
                custom:showText="true" //このcustomのパラメーターは、最初のxmlnsで宣言します
 		            />
                     
 </LinearLayout> 

次に、アトリビュートを指定します。attrs.xmlというファイルを/res/values/の中に作り、次のように宣言します。

 /res/values/attrs.xml
 <resources>
    <declare-styleable name="BaloonUpward">
       <!--  <attr name="android:baloonUpward" /> -->
        <attr name="android:drawableLeft" />
        <attr name="showText" format="boolean" />        
    </declare-styleable>
 </resources>

CustomView自体を作ります。

 public class BaloonUpward extends View {
 
    private Drawable mLeftDrawable;
 
   public BaloonUpward(Context context) {
        
        super(context);
    }
 
    public BaloonUpward(Context context, AttributeSet attrs) {
        super(context, attrs);
        
        try{
            
            TypedArray a = context.getTheme().obtainStyledAttributes(
                    attrs,
                    R.styleable.BaloonUpward,
                    0, 0
            );
 
            Drawable d = a.getDrawable(R.styleable.BaloonUpward_android_drawableLeft);
            if (d != null) {
                setLeftDrawable(d);
            }
 
            a.recycle();
        
        }catch(Exception e){
        
            Log.e("ばるーん", "エラー"+e);
        
        }
        
        
    }
 
    public void setLeftDrawable(Drawable left) {
        mLeftDrawable = left;
        updateContentBounds();
        invalidate();
    }
 
    private void updateContentBounds() {
 
        //ここで画像の表示ポジションなどを動的に変更できます。        
        int left_float = 0;
        int top_float = 0;
 
 
        if (mLeftDrawable != null) {
 
            mLeftDrawable.setBounds(left_float, top_float,
                    500, 500);
 
 
        }
 
    }    
 
    public void setLeftDrawableResource(int resId) {
        Drawable d = getResources().getDrawable(resId);
        setLeftDrawable(d);
    } 
 
    @Override
    protected void onDraw(Canvas canvas) {
           
            if (mLeftDrawable != null) {
                mLeftDrawable.draw(canvas);
            }else{
                Log.d("ばるーん","mLeftDrawableはnull");
            }
    }    
    
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        // TODO Auto-generated method stub
 
    }
    
 
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     //画面のサイズを測ってくれるので、画面サイズにあわせた何かをしたい場合
        //ここでやります
 
        int minw = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();
 
        int w = Math.max(minw, MeasureSpec.getSize(widthMeasureSpec));
 
        // Whatever the width ends up being, ask for a height that would let the pie
        // get as big as it can
        int minh = (w - (int) 120) + getPaddingBottom() + getPaddingTop();
        int h = Math.min(MeasureSpec.getSize(heightMeasureSpec), minh);
 
        setMeasuredDimension(w, h);
    }
 
 }

Googleが下記にてサンプルコードを配布しています。
こちらも大変参考になります。
http://developer.android.com/training/custom-views/create-view.html

TechBoosterさん
http://techbooster.jpn.org/andriod/application/3013/

一番参考になったサイト
https://thenewcircle.com/s/post/1663/tutorial_enhancing_android_ui_with_custom_views_dave_smith_video

Android Class File Editor Souce not found

Android

Android デバッグが途中でClass File Editor:Souce not foundというエラーで止まってしまう

Androidの開発途中、デバッグをしていると途中でActivity.classなどを呼び出すときに、画面に

 Class File Editor
 Souce not found
 The source attachment does not contain the source for the file...

となってしまってデバッグが進まないことがあります。
Change Attached Sourceというボタンがあって、ソースコードの場所を指定してみても、事態は解決しません。

下記のサイトに詳しく解決方法が書いてあります。
まだ試していませんが、取り急ぎ、メモとして書いておきます。
要は、EclipseがAndroidのソースの場所をうまく読み込めていないので、対象のプラットフォームのソースコードをsrcディレクトリの下に置こう、ということのようです。

http://android.opensourceror.org/2010/01/18/android-source/

 

Android Cannot resolve symbol GooglePlayServicesClient

Android
AndroidStudio2.1.2

ちょっとメンテナンスをさぼっていたあるソースコードを、久しぶりにAndroidStudioで開いたら

 Cannot resolve symbol GooglePlayServicesClient

というエラーが出てきて、どうにも解決できません。

なんとなんと、GooglePlayServicesClientは出てきてから、すぐDeprecateされたかわいそうな子ですが、AndroidStudioでは、もう存在すらしていないそうです。

http://stackoverflow.com/questions/29303427/cannot-resolve-symbol-googleplayservicesclient-on-new-android-studio-project

ってか、下記の記事で

Google Play Serviceを利用する新位置情報取得APIについて 実装方法

Google Play Serviceの位置情報取得を書いたのは、3年も前じゃないと思うのですが…。

次々にDeprecateするのは本当にやめていただきたい!!発狂しそうですわ!!(つД`)

と言っていても始まらないので、下記のページを参考に、新しい位置情報取得を作ります。

https://developer.android.com/training/location/receive-location-updates.html?hl=ja

ちょっとだけメモを書いておきます。
やり始めたばっかりなので、ちと間違っているかもしれません。

 public class HogeActivity implements
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        LocationListener {
  
   @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        mLocationClient = new GoogleApiClient.Builder(context)
                    .addApi(LocationServices.API)
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this)
                    .addApi(AppIndex.API).build();      
 
  @Override
    public void onConnected(Bundle connectionHint) {
        // Display the connection status
        Log.d(TAG, "Google APIに接続");
 
        setUpdateLocationRequest();
    }
 
 //位置情報を定期的に取得する
 public void setUpdateLocationRequest() {
        mLocationRequest = LocationRequest.create();
        // 高い精度の位置情報を取る
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        mLocationRequest.setInterval(PlacesConstants.MIN_TIME);
 
 
        LocationServices.FusedLocationApi.requestLocationUpdates(
                mLocationClient, mLocationRequest, this);
    }
 //Stopなどは省略します

Androidの開発者に、平和が訪れますように…。

Android Calling startActivity from outside of an Activity

Android

Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

Activityではないところから、Intentをスタートさせようとすると、上記のメッセージが出る例外が起こってしまいます。

Androidのエラーって親切ですね、書いてあるのを参考にやってみればOKです。

 Intent message_intent = new Intent(context, MessageReceivedActivity.class);
 message_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  //この行をつけたし
 startActivity(message_intent);