(祝)東京オリンピック!

(祝)北京オリンピック!

Android関係 その1

AndroidManifest



  

COPY

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AsyncSample"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>
    </application>

</manifest>

strings



  

COPY

<resources>
    <string name="app_name">お天気情報</string>
    <string name="tv_winfo_title">お天気詳細</string>
</resources>

activity_main



  

COPY

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/glLvCityList"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.5" />

    <ListView
        android:id="@+id/lvCityList"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/glLvCityList"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tvWinfoTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:text="@string/tv_winfo_title"
        android:textSize="24sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/glLvCityList" />

    <TextView
        android:id="@+id/tvWeatherTelop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:textSize="20sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tvWinfoTitle" />

    <TextView
        android:id="@+id/tvWeatherDesc"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tvWeatherTelop" />
</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity



  

COPY

package com.websarva.wings.android.asyncsample;

import androidx.annotation.UiThread;
import androidx.annotation.WorkerThread;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class MainActivity extends AppCompatActivity {

    private static final String DEBUG_TAG = "AsyncSample";

    private static final String WEATHERINFO_URL = "https://api.openweathermap.org/data/2.5/weather?lang=ja";

    private static final String APP_ID = "xxxxxxxxxxx";

    private List<Map<String, String>> _list;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        _list  = createList();

        ListView lvCityList = findViewById(R.id.lvCityList);
        String[] from = {"name"};
        int[] to = {android.R.id.text1};
        SimpleAdapter adapter = new SimpleAdapter(getApplicationContext(), _list, android.R.layout.simple_list_item_1, from, to);
        lvCityList.setAdapter(adapter);
        lvCityList.setOnItemClickListener(new ListItemClickListener());
    }

    private List<Map<String, String>> createList() {
        List<Map<String, String>> list = new ArrayList<>();

        Map<String, String> map = new HashMap<>();
        map.put("name", "大阪");
        map.put("q", "Osaka");
        list.add(map);
        map = new HashMap<>();
        map.put("name", "神戸");
        map.put("q", "Kobe");
        list.add(map);
        map = new HashMap<>();
        map.put("name", "京都");
        map.put("q", "Kyoto");
        list.add(map);
        map = new HashMap<>();
        map.put("name", "大津");
        map.put("q", "Otsu");
        list.add(map);
        map = new HashMap<>();
        map.put("name", "奈良");
        map.put("q", "Nara");
        list.add(map);
        map = new HashMap<>();
        map.put("name", "和歌山");
        map.put("q", "Wakayama");
        list.add(map);
        map = new HashMap<>();
        map.put("name", "姫路");
        map.put("q", "Himeji");
        list.add(map);

        return list;
    }

    @UiThread
    private void receiveWeatherInfo(final String urlFull) {
        WeatherInfoBackgroundReceiver backgroundReceiver = new WeatherInfoBackgroundReceiver(urlFull);
        ExecutorService executorService  = Executors.newSingleThreadExecutor();
        Future<String> future = executorService.submit(backgroundReceiver);
        String result = "";
        try {
            result = future.get();
        }
        catch(ExecutionException ex) {
            Log.w(DEBUG_TAG, "非同期処理結果の取得で例外発生: ", ex);
        }
        catch(InterruptedException ex) {
            Log.w(DEBUG_TAG, "非同期処理結果の取得で例外発生: ", ex);
        }
        showWeatherInfo(result);
    }

    @UiThread
    private void showWeatherInfo(String result) {
        // 都市名。
        String cityName = "";
        // 天気。
        String weather = "";
        // 緯度
        String latitude = "";
        // 経度。
        String longitude = "";
        try {
            // ルートJSONオブジェクトを生成。
            JSONObject rootJSON = new JSONObject(result);
            // 都市名文字列を取得。
            cityName = rootJSON.getString("name");
            // 緯度経度情報JSONオブジェクトを取得。
            JSONObject coordJSON = rootJSON.getJSONObject("coord");
            // 緯度情報文字列を取得。
            latitude = coordJSON.getString("lat");
            // 経度情報文字列を取得。
            longitude = coordJSON.getString("lon");
            // 天気情報JSON配列オブジェクトを取得。
            JSONArray weatherJSONArray = rootJSON.getJSONArray("weather");
            // 現在の天気情報JSONオブジェクトを取得。
            JSONObject weatherJSON = weatherJSONArray.getJSONObject(0);
            // 現在の天気情報文字列を取得。
            weather = weatherJSON.getString("description");
        }
        catch(JSONException ex) {
            Log.e(DEBUG_TAG, "JSON解析失敗", ex);
        }

        // 画面に表示する「〇〇の天気」文字列を生成。
        String telop = cityName + "の天気";
        // 天気の詳細情報を表示する文字列を生成。
        String desc = "現在は" + weather + "です。\n緯度は" + latitude + "度で経度は" + longitude + "度です。";
        // 天気情報を表示するTextViewを取得。
        TextView tvWeatherTelop = findViewById(R.id.tvWeatherTelop);
        TextView tvWeatherDesc = findViewById(R.id.tvWeatherDesc);
        // 天気情報を表示。
        tvWeatherTelop.setText(telop);
        tvWeatherDesc.setText(desc);
    }

    private class WeatherInfoBackgroundReceiver implements Callable<String> {
        /**
         * お天気情報を取得するURL。
         */
        private final String _urlFull;

        /**
         * コンストラクタ。
         * 非同期でお天気情報Web APIにアクセスするのに必要な情報を取得する。
         *
         * @param urlFull お天気情報を取得するURL。
         */
        public WeatherInfoBackgroundReceiver(String urlFull) {
            _urlFull = urlFull;
        }

        @WorkerThread
        @Override
        public String call() {
            // 天気情報サービスから取得したJSON文字列。天気情報が格納されている。
            String result = "";
            // HTTP接続を行うHttpURLConnectionオブジェクトを宣言。finallyで解放するためにtry外で宣言。
            HttpURLConnection con = null;
            // HTTP接続のレスポンスデータとして取得するInputStreamオブジェクトを宣言。同じくtry外で宣言。
            InputStream is = null;
            try {
                // URLオブジェクトを生成。
                URL url = new URL(_urlFull);
                // URLオブジェクトからHttpURLConnectionオブジェクトを取得。
                con = (HttpURLConnection) url.openConnection();
                // 接続に使ってもよい時間を設定。
                con.setConnectTimeout(1000);
                // データ取得に使ってもよい時間。
                con.setReadTimeout(1000);
                // HTTP接続メソッドをGETに設定。
                con.setRequestMethod("GET");
                // 接続。
                con.connect();
                // HttpURLConnectionオブジェクトからレスポンスデータを取得。
                is = con.getInputStream();
                // レスポンスデータであるInputStreamオブジェクトを文字列に変換。
                result = is2String(is);
            }
            catch(MalformedURLException ex) {
                Log.e(DEBUG_TAG, "URL変換失敗", ex);
            }
            // タイムアウトの場合の例外処理。
            catch(SocketTimeoutException ex) {
                Log.w(DEBUG_TAG, "通信タイムアウト", ex);
            }
            catch(IOException ex) {
                Log.e(DEBUG_TAG, "通信失敗", ex);
            }
            finally {
                // HttpURLConnectionオブジェクトがnullでないなら解放。
                if(con != null) {
                    con.disconnect();
                }
                // InputStreamオブジェクトがnullでないなら解放。
                if(is != null) {
                    try {
                        is.close();
                    }
                    catch(IOException ex) {
                        Log.e(DEBUG_TAG, "InputStream解放失敗", ex);
                    }
                }
            }
            return result;
        }

        private String is2String(InputStream is) throws IOException {
            BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
            StringBuffer sb = new StringBuffer();
            char[] b = new char[1024];
            int line;
            while(0 <= (line = reader.read(b))) {
                sb.append(b, 0, line);
            }
            return sb.toString();
        }
    }

    private class ListItemClickListener implements AdapterView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            Map<String, String> item = _list.get(position);
            String q = item.get("q");
            String urlFull = WEATHERINFO_URL + "&q=" + q + "&appid=" + APP_ID;

            receiveWeatherInfo(urlFull);
        }
    }
}

Listener



  

COPY

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="8dp"
    android:orientation="vertical">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tv_name" />

    <EditText
        android:id="@+id/etInput"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:inputType="textPersonName"/>

    <Button
        android:id="@+id/btClick"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="@string/bt_click" />

    <Button
        android:id="@+id/btClear"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="@string/bt_clear" />

    <TextView
        android:id="@+id/tvOutput"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:text=""
        android:textSize="25sp"/>
</LinearLayout>

package com.websarva.wings.android.hellosample;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button btClick=findViewById(R.id.btClick);
        HelloListener listener=new HelloListener();
        btClick.setOnClickListener(listener);

        Button btClear=findViewById(R.id.btClear);
        btClear.setOnClickListener(listener);
    }
    private class HelloListener implements View.OnClickListener {
        @Override
        public void onClick(View view){
            EditText input=findViewById(R.id.etInput);
            TextView output=findViewById(R.id.tvOutput);

            int id=view.getId();

            if (id==R.id.btClick) {
                String inputStr = input.getText().toString();
                output.setText(inputStr + "さん、こんにちは!!");
            } else if (id==R.id.btClear) {
                input.setText("");
                output.setText("");
            }

        }
    }
}