カテゴリーアーカイブ Java

asaba 著者:asaba

【androidJava】clientオブジェクトの呼び出しで躓く

OkHttpClient()を使ってeditTextで書いた文章を送信する機能を作ったのですが、callオブジェクトがうまく呼べなくて

通信の際にクラッシュしてしまいました。

okhttpの関数群をいったん消して適当に作った他の関数では動いたのでレイアウトとかmanifestら辺は異常なしと判断。

という訳でokHttp周りを調査。

logを辿っても具体的な原因は分かりませんでしたが、粘ってトレースした結果どうやらcallオブジェクトのenqueueでコールバックを設定

することが良くなかったためかと思われます。

ここはOkHttpClient client = new OkHttpClient();で定義したclientオブジェクトでclient.newCall(request).enqueue(new Callback() {})と

定義し直すことで無事解決。

 

失敗例↓


Call call = client.newCall(request);
call.enqueue(new Callback() {

])

 

成功例↓


client.newCall(request).enqueue(new Callback() {})

 

  • この記事いいね! (0)
村上 著者:村上

【Android】Uriから画像のファイルパスを取得する方法

果たして需要があるかは分かりませんが、私はあったので備忘録としてまとめ。
Anrdoidアプリで、Uriから画像のファイルパスを取得する方法です。
参考にさせていただいたサイトは確かこちら。

ギャラリーからの画像読み込みでエラーが出るときの修正方法|Workpiles
http://workpiles.com/2014/07/android-gallary-intent/

 

実装方法は下記のとおりです。
関数になっているので、このままコピー&ペーストしていただければ動くかと思います。

private String getPictPath(Uri uri) {
    String id = DocumentsContract.getDocumentId(uri);
    String selection = "_id=?";
    String[] selectionArgs = new String[]{id.split(":")[1]};
    File file = null;

    Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.MediaColumns.DATA}, selection, selectionArgs, null);

    if (cursor != null && cursor.moveToFirst()) {
        file = new File(cursor.getString(0));
    }
    cursor.close();

    if(file != null){
        return file.getAbsolutePath();
    }
    return null;
}

getPictPath() の引数に、変換したい画像のUriを渡せばOKです。

 

以上、簡単ですが画像のUriからファイルパスを取得する方法でした。
実際に使う機会は多くはないと思いますが、参考にしていただければと思います。

  • この記事いいね! (0)
村上 著者:村上

【Android】端末の戻るボタンが押されたときに処理を実行する

Android アプリを開発中、端末の戻るボタンが押下されたかどうかを検知したいことがあると思います。
例えば、EditText エリアに何かを入力中に、うっかりボタンを押してしまっても、前のページに戻る前に確認のアラートを出すような機能を追加するときや、そもそも戻るボタン自体を無効にしたい、などです。
私も極たまにしか使わないので、備忘録としてまとめます。

 

といっても実装はとっても簡単で、下記のように onBackPressed をオーバーライドするだけです。

@Override
public void onBackPressed(){
    // 行いたい処理
}

あとは、この関数内で、戻るボタンが押されたときに実行したい処理を書くだけです。

私の場合、下記のような実装を行いました。

@Override
public void onBackPressed(){
    // EditTextに入力された文字列を取得
    EditText editText = findViewById([ID名]);
    if (editText.getText().equal("")) {
        finish();
    } else {
        // ダイアログ表示
        new AlertDialog.Builder(this)
                .setTitle([タイトル])
                .setMessage([メッセージ])
                .setPositiveButton("OK", (dialog, which) -> {
                    // OKが押された場合、Activity を終了し、前のページへ
                    finish();
                })
                .setNegativeButton("キャンセル", null)
                .show();
    }
}

上のコードでは、戻るボタンが押されたときに、EditText に入力された文字列を取得しています。
この時、EditText に何か文字が入力されていた場合、まだ編集中とみなし、警告のダイアログが表示されるようにしています。
EditText が空だった場合や、ダイアログでOKが押された場合は、finish() を実行し、現在表示されているアクティビティを終了して、前のページに戻ります。

 

なお、戻るボタンを検知する方法としては下記の記述方法もあります。

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if(keyCode == KeyEvent.KEYCODE_BACK) {
        // 戻るボタンの処理
        
    }
}

この書き方を用いると、戻るボタン以外の検知にも使えます。
複数のボタンの検知の処理を書きたい場合には、こちらのほうが便利ですね。
ですが、今回は戻るボタンの検知のみが行えればOKだったので、私は前者を使いました。
なんといっても、関数名が分かりやすいですし。
このあたりは、好みと実装内容によって使い分けてください。

 

以上、Androidアプリで戻るボタンが押されたことを検知する方法でした。

  • この記事いいね! (0)
村上 著者:村上

【Android】カスタムデザインのListViewを表示する

Android の ListView は、昔作成したことがあるのですが、いかんせん昔過ぎてほとんど忘れていたので備忘録もかねてまとめ。
ちなみに、すでに用意されているレイアウトを使うのではなく、リストアイテムのレイアウトからカスタムする方法です。

今回参考にさせていただいたサイトはこちら。

Androidでリストビュー(ListView)をカスタムして表示する – Qiita
https://qiita.com/ksugawara61/items/2d63f0be279a94b74550

 

早速実装!
まず、作成するファイルの一覧は下記のとおりです。
・MainActivity.java
・activity_main.xml
・list_item.xml
・ListItem.java
・ListAdapter.java

MainActivity.java に追加するコードは下記のとおり。

ListItem item = new ListItem();
// item にデータ追加処理を行う

ListView listView = findViewById([ListViewのID]);
ListAdapter adapter = new ListAdapter(this, R.layout.list_item, item);
listView.setAdapter(adapter);
listView.setOnItemClickListener((adapterView, view, position, l) -> {
    // ListViewのアイテムクリック時の処理
});

activity_main.xml ファイルには、ListView を追加します。

<ListView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/[ListViewのID]" />

ListItem.java には、ListView で使う値を扱えるクラスを定義します。

public class ListItem {
    private String entry_title;
    private String adate;
    private String url;

    public EntryListItem() {};

    public EntryListItem(String e_entry_title, String e_adate, String e_url) {
        entry_title = e_entry_title;
        adate = e_adate;
        url = e_url;
    }

    public void setEntryTitle(String title) {
        entry_title = title;
    }

    public void setAdate(String e_adate) {
        adate = e_adate;
    }

    public void setUrl(String e_url) {
        url = e_url;
    }

    public String getEntryTitle() {
        return entry_title;
    }

    public String getAdate() {
        return adate;
    }

    public String getUrl() {
        return url;
    }
}

ブログ記事を扱うことを想定しているので、それらの値が格納されるようになっています。
値の格納と取得を行うための関数も定義しています。

ListAdapter.java は、ArrayAdapter を継承していて、上の ListItem.java クラスを利用するためのクラスです。

public class ListAdapter extends ArrayAdapter<ListItem> {

    private int mResource;
    private List<ListItem> mItems;
    private LayoutInflater mInflater;

    public EntryListAdapter(Context context, int resource, List<ListItem> items) {
        super(context, resource, items);

        mResource = resource;
        mItems = items;
        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view;

        if (convertView != null) {
            view = convertView;
        }
        else {
            view = mInflater.inflate(mResource, null);
        }

        // リストビューに表示する要素を取得
        ListItem item = mItems.get(position);

        // タイトル、投稿日時を設定
        TextView title = view.findViewById(R.id.title);
        title.setText(item.getEntryTitle());
        TextView adate = view.findViewById(R.id.adate);
        adate.setText(item.getAdate());

        return view;
    }
}

ListView にセットする Adapter がこのクラスです。

 

以上のコードとファイルを作成すると、カスタマイズされた ListView を実装することができます。
覚え書きのため、かなり簡単なまとめになっているので、もっと詳しく知りたい方は、最初に紹介した参考サイトを読んでください。

  • この記事いいね! (0)
村上 著者:村上

【Android】アプリ画面のスクリーンショットを禁止する方法

当初は最近使用している家計簿アプリのご紹介を使用と思っていたのですが、アプリがスクリーンショットを撮影できない設定になっていることが判明しました。
そのため、急遽予定を変更しまして、今回はアプリのスクリーンショット操作を禁止する方法についてご紹介!
というか、あまりスクリーンショット自体を撮らないし、アプリにも組み込んだことがなかったので、そもそもそんな機能があったことを知りませんでした…。

ちなみに、その撮影禁止のアプリでスクリーンショットを撮影しようとしたところ、下記の画像のようなメッセージが通知エリアに表示されました。

初めてみましたが、こんなことができたんですね!

 

今回参考にさせていただいたサイトはこちらから。

[Android]アプリでスクリーンショットを無効にする|DevelopersIO
https://dev.classmethod.jp/smartphone/android/prevent-screenshot/

実装方法は案外シンプルで、Activity の場合は、下記のコードを追加します。

Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE);

Fragment で実装したい場合は、下記のように記述するとのこと。

WindowManager mWindowManager; 
FrameLayout mOverlapView;
WindowManager.LayoutParams mParams;
 
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mParams = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
            WindowManager.LayoutParams.FLAG_SECURE,
            PixelFormat.TRANSLUCENT);
    mWindowManager = (WindowManager)getActivity().
        getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
    mOverlapView = new FrameLayout(getActivity());
    mWindowManager.addView(mOverlapView, mParams);
}
@Override
public void onHiddenChanged(boolean hidden) {
    super.onHiddenChanged(hidden);
    if (hidden) {
        mWindowManager.removeView(mOverlapView);
    } else {
        mWindowManager.addView(mOverlapView, mParams);
    }
}

なお、実際に無効化を操作しているのは、8行目からの mParams の記述になります。
そして、その操作を反映するために、onHiddenChanged() でその変更反映の処理を行っています。

Activity もしくは Fragment でのスクリーンショット禁止の記述は以上です。

 

以上、Androidアプリでスクリーンショット操作を禁止にする方法でした。
もし開発中のアプリでスクリーンショットを制御したい場合は、是非参考にしてください。

  • この記事いいね! (0)
村上 著者:村上

【Android】XMLデータから特定のタグの値を取得する方法

もしかしたらもっとスマートなやり方があるのかもしれませんが…問題なく動作しますので、XMLの扱いでお悩みの方は是非。
XMLデータから、特定のタグの値を取得する方法です。
なお、参考にしたサイトをうっかり失念してしまったので、今回はリンクはありません。

 

では早速、コードはこちら。

private void getXmlData(String xml) throws XmlPullParserException, IOException {
    XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
    XmlPullParser parser = factory.newPullParser();
    parser.setInput(new StringReader(xml));
    int eventType = parser.getEventType();

    String data;
    List<String> arrData = new ArrayList<>();

    while (eventType != XmlPullParser.END_DOCUMENT) {
        if (eventType == XmlPullParser.START_TAG) {
            switch (parser.getName()) {
                // データを取得したいタグが一つ
                case "[データを取得したいタグ名]":
                    parser.next();
                    data = parser.getText();
                    break;
                // データを取得したいタグが複数
                case "[データを取得したいタグ名]":
                    parser.next();
                    arrData.add(parser.getText());
                    break;
            }
        }
        eventType = parser.next();
    }
}

こんな感じです。
関数にしているので、そのままコピー&ペーストしてもらえば動作するかと思います。
なお、渡すXMLでデータは 文字列 に変換しています。

重要そうな部分だけを説明すると、10行目から XMLデータを while で、タグやデータなど 1つずつ見ていって、それが開始タグで、かつそれがデータを取得したいタグだった場合はそのタグの値を取得しています。
また、14行目からの case句は、タグが一つしかない場合のデータの取得方法で、対して 19行目からの case句は、タグが複数あった場合のデータの取得方法です。
といっても、データを格納する変数が StringList かの違いしかないのですけどね。

これでデータの取得ができますので、あとはこのデータを行いたい処理などに使ってください。

 

以上、XMLデータから特定のタグのデータを取得する方法でした。
やり方を変えれば、全タグのデータも取得できるかと思いますので、是非ご活用ください。

  • この記事いいね! (0)
村上 著者:村上

【Android】アプリ内にデータを保存できる「SharedPreferences」

Androidでアプリを開発する際、ちょっとしたデータを保存したいときがあるかと思います。
Webであれば、Cookie や LocalStorage が使えますが、Android の場合でもよく似た仕組みがあります。
それがこちらの「SharedPreferences」です。

参考にさせていただいたサイトはこちら。

[Android] データを保存し Android Studio で確認 SharedPreferences
https://akira-watson.com/android/sharedpreferences.html

 

早速使い方はこちら。

SharedPreferences dataStore = getSharedPreferences("DataStore", MODE_PRIVATE);
Editor editor = dataStore.edit();
// 保存するデータを追加
editor.putString("input", "abcdefg");
editor.apply();

なお、getSharedPreferences() の第2引数で指定している MODE_PRIVATE とは「このアプリからのみ読み書き可能」という意味になります。
基本的には、これでOKだと思います。

また、データはほかにも下記の型を保存できます。

editor.putInt("DataInt", 123);
editor.putBoolean("DataBoolean", true);
editor.putLong("DataLong", 12345678909876L);
editor.putFloat("DataFloat", 12.345f);

そして、読み出しは下記のようになります。

String dataString = dataStore.getString("input", null);

読み出しについてはいたってシンプルですね。
なお、第二引数には、データを取得できなかった場合の代用値を指定します。

他の型の取得については下記のとおりです。

int dataInt = dataStore.getInt("DataInt", 0);
boolean dataBoolean = dataStore.getBoolean("DataBoolean", false);
long dataLong = dataStore.getLong("DataLong", 0);
float dataFloat = dataStore.getFloat("DataFloat", 0);

 

以上、アプリ内にデータを保存できる SharedPreferences の使い方でした。
データベースに保存するまでもないような、小さなデータなどでしたらこれで事足りるかと思います。
是非、便利に使ってください。

  • この記事いいね! (0)
村上 著者:村上

【Android】XMLをJSONに変更できるライブラリ「JSONIC」

結論から言うと、私の環境ではうまく使えなかったので、実際の使用は見合わせました。
が、かなり便利そうだったので、いつか使うとき用に備忘録としてまとめます。

今回紹介するのは、「JSONIC」というJava用のシンプルかつ高機能なJSONエンコーダー・デコーダーライブラリです。
GitHubはこちらから。

GitHub – hidekatsu-izuno/jsonic: simple json encoder/decoder for java
https://github.com/hidekatsu-izuno/jsonic

…しかし、よく見たら、今後機能強化が行われることがないメンテナンスモードに移行するとのこと。
もし利用する場合は、jackson への移行をおすすめしているとのことでした。

 

使い方のサンプルコードはこちら。

import net.arnx.jsonic.JSON;

// POJOをJSONに変換します
String text = JSON.encode(new Hoge());

// JSONをPOJOに変換します
Hoge hoge = JSON.decode(text, Hoge.class);

いたってシンプルです。

また、XMLをJSONに変換したい場合は、下記のようにします。

Document doc = builder.parse(new File([変換したいXMLファイル]));
String xmljson = JSON.encode(doc);

例えば、下記のようなXMLファイルを変換すると、

<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Feed Title</title>
  <entry>
    <title>Entry Title</title>
  </entry>
</feed>

変換後のJSONは下記のようになります。

["feed", {"xmlns": "http://www.w3.org/2005/Atom"},
    ["title", "Feed Title"],
    ["entry",
        ["title", "Entry Title"],
    ]
]

なお、この時、タグ間の空白文字も TextNodeとして出力されるらしいので、これが不要な場合は、DOM作成時に取り除く必要があるとのことでした。

 

以上、簡単ではありますが、JSONIC ライブラリの使い方でした。
もし、JSONのエンコード・デコードをシンプルに行えるライブラリをお探しでしたら、参考にしていただければと思います。
が、最初に書いたように、JSONIC は今後機能強化を行わないとのことでしたので、利用する場合は、jackson を使用するようにしてください。

  • この記事いいね! (0)
村上 著者:村上

【Cordova】初回起動時にcordova-plugin-ibeaconが表示するAlertを非表示にする方法

タイトル通り、cordova-plugin-ibeacon プラグインが表示しているアラートを非表示にする方法です。
実際に表示されるアラートはこちら。

表示されているメッセージ自体は「このアプリケーションがビーコンを検出できるようにアクセスを許可してください」なので、これ自体に問題はないのですが、文章はプラグインの中で指定されているものですし、このアラートとは別に、位置情報の取得許可を求めるダイアログが表示されるので、表示させないほうが綺麗かなと思います。
表示/非表示はお好みかもしれませんが、私の場合、現在開発中のアプリは日本語表記のみなので、英語のアラートは非表示にしようと思います。

 

さて、このアラートを表示させないようにする方法ですが、このプラグインを追加した時に追加される LocationManager.java というファイルの中を修正します。

で、このLocationManeger.java の302行目辺りに、AlertDialog の設定をしている記述がありますので、そこを確認します。
AlertDialog もしくは、アラートメッセージの「Please grant location access so this app can detect beacons.」で調べれば、すぐに見つかると思います。
そして、その記述の下の方に、builder.show(); という記述があり、ここで Alert を表示しています。
なので、これをコメントアウトします。

作業としては以上です!
あとは、一旦アプリを削除して再インストールするか、Android の設定 > アプリ からこのアプリの設定を開き、データを削除してから再度起動すれば、アラートが表示されないことを確認できるかと思います。

 

以上、cordova-plugin-ibeacon が表示しているアラートを非表示にする方法でした。
良かったら参考にしてください。

  • この記事いいね! (0)
村上 著者:村上

【Android】「The minSdk version should not be declared in the android manifest file. You can move the version from the manifest to the defaultConfig in the build.gradle file.」エラー【未解決】

タイトル通り未解決のAndroid Studioのエラーについてです。
いくつかヒットした解決策を試したのですが解消されず…。

エラーはこちら。

The minSdk version should not be declared in the android manifest file. You can move the version from the manifest to the defaultConfig in the build.gradle file.

minSdk の指定を AndroidManifest.xml ではなく build.gradle で指定するようにという内容です。
なので、この指示通りに minSdkVersion を build.gradle に書き直したのですが…それでも解消せず。

記述箇所はこのような感じです。

android {
  ...
  defaultConfig {
    ...
    minSdkVersion 14
    targetSdkVersion 24
  }
  productFlavors {
    main {
      ...
    }
    afterLollipop {
      ...
      minSdkVersion 21
    }
  }
}

ちなみに、この内容は Android Developers のページを参考にしました。

アプリのバージョニング|Android Developers
https://developer.android.com/studio/publish/versioning?hl=ja

Cordova で作成した環境だから、というのもありそうですが、まだわかってはいません。
また、このエラーがあっても別にビルドや実機での実行は試すことができるので、今のところ、一旦放置しています。
が、ずっとウィンドウ上部に「Try Again」が表示されているのもうっとおしいので、早めに解決したいところですね。

 

解決策が判明したら、改めてご紹介したいと思います!

  • この記事いいね! (1)