Как решить проблему Android времени выполнения "Не удалось получить список файлов xyz.geshkii.weather"? - PullRequest
0 голосов
/ 02 августа 2020

Я сделал приложение погоды, которое содержит одно действие.

activity_main. xml

<?xml version="1.0" encoding="utf-8"?>
<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:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/ic_clear_day"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/city"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:text="@string/city_name"
        android:textSize="24sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/temperature" />

    <TextView
        android:id="@+id/temperature"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="200dp"
        android:text="@string/weather_temp"
        android:textSize="48sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/getWeatherInfo"
        style="@style/Theme.AppCompat.Light"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="28dp"
        android:layout_marginBottom="44dp"
        android:drawableStart="@drawable/ic_renew_info"
        android:onClick="renewWeatherInfo"
        android:text="@string/request_info"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <TextView
        android:id="@+id/humidity"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="@string/humidity"
        android:textSize="20sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/city" />

    <EditText
        android:id="@+id/searchBox"
        android:layout_width="246dp"
        android:layout_height="37dp"
        android:layout_marginStart="28dp"
        android:layout_marginTop="32dp"
        android:drawableLeft="@drawable/ic_city"
        android:ems="10"
        android:hint="  输入要查询的城市..."
        android:inputType="text"
        android:textSize="12sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/searchCity"
        android:layout_width="58dp"
        android:layout_height="42dp"
        android:layout_marginStart="322dp"
        android:layout_marginTop="28dp"
        android:layout_marginEnd="31dp"
        android:drawableTop="@drawable/ic_search_city"
        android:onClick="searchForCity"
        android:text="@string/placeholder"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toEndOf="@+id/searchBox"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/airQuality"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="32dp"
        android:text="@string/air_quality"
        app:layout_constraintBottom_toTopOf="@+id/temperature"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.986" />

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity. java

package xyz.geshkii.weather;

import xyz.geshkii.weather.R;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.icu.text.Edits;
import android.location.Location;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.alibaba.fastjson.JSON;
import com.google.android.material.snackbar.Snackbar;
import com.jaeger.library.StatusBarUtil;

import org.jetbrains.annotations.NotNull;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Text;

import java.io.IOException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * @author sudo2u
 */
public class MainActivity extends AppCompatActivity {
    static final String weatherInfoBaseUrl = "https://api.caiyunapp.com/v2.5/";
    public static String weatherInfoToken = "ABqYRMOVFp2oTB7l",longitude, latitude;

    static final String geocodeBaseUrl = "https://restapi.amap.com/v3/geocode/geo?";
    public static String geocodeKey = "45ef5896ebf2469215dd0e4ab9964457";
    public static String geocodeCity, geocodeAddress;

    static final String regeocodeBaseUrl = "https://restapi.amap.com/v3/geocode/regeo?", regeocodeKey = "45ef5896ebf2469215dd0e4ab9964457";

    static String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};

    private String locationProvider;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        StatusBarUtil.setTransparent(this);
        if(checkNetWork()){
            getGPSLocation(this);
            requestWeatherInfo();
            getReGeoInformation();
        }
    }

    public boolean checkNetWork() {
        ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
        if (networkInfo == null || !networkInfo.isAvailable()) {
            Toast toast = Toast.makeText(getApplicationContext(), "网络异常", Toast.LENGTH_SHORT);
            toast.show();
            return false;
        }
        return true;
    }

    public void checkPermissions(Context context) {
        if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_COARSE_LOCATION)) {
                showPermissionRationale();
            } else {
                requestPermissions(permissions, 1);
            }
        }
    }

    public void showPermissionRationale() {
        Snackbar.make(findViewById(R.id.layout), "天气需要精确位置来提供服务,是否授权?", Snackbar.LENGTH_LONG)
                .setAction("授权", new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        requestPermissions(permissions, 1);
                    }
                }).show();
    }

    public void getGPSLocation(Context context) {
        LocationManager loc = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        List<String> providers = loc.getProviders(true);

        /*
        for(String prov : providers){
            Log.i("GPS Providers", prov);
        }

         */

        if (providers.contains(LocationManager.GPS_PROVIDER)) {
            //如果是GPS定位
            locationProvider = LocationManager.GPS_PROVIDER;
        }
        else if(providers.contains(LocationManager.PASSIVE_PROVIDER)){
            locationProvider = LocationManager.PASSIVE_PROVIDER;
        }
        else if(providers.contains(LocationManager.NETWORK_PROVIDER)){
            locationProvider = LocationManager.NETWORK_PROVIDER ;
        }
        else {
            Toast.makeText(this, "没有可用的位置提供器", Toast.LENGTH_SHORT).show();
        }


        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            showPermissionRationale();
            getGPSLocation(this);
        }
        else{
            Location location = loc.getLastKnownLocation(locationProvider);
            if (location!=null) {
                longitude = String.valueOf(location.getLongitude());
                latitude = String.valueOf(location.getLatitude());

                Log.i("GPS Location, longitude", longitude);
                Log.i("GPS Location, latitude", latitude);
            }
        }
    }

    private String getGeocodeInfoUrl() { return geocodeBaseUrl + "key=" + geocodeKey + "&address=" + geocodeAddress + "&city=" + geocodeCity; }

    private String getWeatherInfoUrl() { return weatherInfoBaseUrl + weatherInfoToken + "/" + longitude + "," + latitude + "/realtime.json"; }

    private String getRegeocodeInfoUrl(){ return regeocodeBaseUrl + "key=" + regeocodeKey + "&location=" + longitude + "," + latitude + "&poitype=&radius=&extensions=base&batch=false&roadlevel=0"; }

    public void renewWeatherInfo(View view) {
        if(checkNetWork()){
            requestWeatherInfo();
        }
    }

    public void requestWeatherInfo() {
        String url = getWeatherInfoUrl();
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(url).build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                final String result = response.body().string();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            deserializeWeatherInfo(result);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        });
    }

    public void deserializeWeatherInfo(String result) throws JSONException {
        JSONObject totalRes = new JSONObject(result);
        String totalResResult = totalRes.optString("result");

        Log.i("Weather info", totalResResult);

        JSONObject realtimeRes = new JSONObject(totalResResult);
        String realtimeResResult = realtimeRes.optString("realtime");


        JSONObject weatherInfoRes = new JSONObject(realtimeResResult);
        double temp = weatherInfoRes.optDouble("temperature");
        double humidity = weatherInfoRes.optDouble("humidity");
        String skyCondition = weatherInfoRes.optString("skycon");

        String description = weatherInfoRes.optString("air_quality");

        JSONObject aqi_descriptionJson = new JSONObject(description);
        String aqi_description = aqi_descriptionJson.optString("description");

        JSONObject air_qualJson = new JSONObject(aqi_description);
        String air_quality = air_qualJson.optString("chn");
        Log.i("Air quality", air_quality);



        //Set temperature
        TextView tempView = (TextView) findViewById(R.id.temperature);
        tempView.setText(String.valueOf(temp) + "°");

        //Set humidity
        TextView humidView = (TextView) findViewById(R.id.humidity);
        humidView.setText(String.valueOf(humidity * 100) + "%");

        //Set air quality
        TextView airQualityView = (TextView) findViewById(R.id.airQuality);
        airQualityView.setText("空气" + air_quality);

        //Call and check sky condition
        changeSkyconStatus(skyCondition);
    }

    //TODO: 需要做完所有的Skycon背景图
    public void changeSkyconStatus(String skycon) {
        ConstraintLayout layout = (ConstraintLayout) findViewById(R.id.layout);
        if (skycon.equals("MODERATE_RAIN")) {
            layout.setBackgroundResource(R.drawable.ic_moderate_rain);
        } else if (skycon.equals("CLEAR_DAY")) {
            layout.setBackgroundResource(R.drawable.ic_clear_day);
        } else if (skycon.equals("CLEAR_NIGHT")) {
            layout.setBackgroundResource(R.drawable.ic_clear_night);
        } else if (skycon.equals("CLOUDY")) {
            layout.setBackgroundResource(R.drawable.ic_cloudy);
        } else if (skycon.equals("HEAVY_RAIN")) {
            layout.setBackgroundResource(R.drawable.ic_heavy_rain);
        } else if (skycon.equals("LIGHT_RAIN")) {
            layout.setBackgroundResource(R.drawable.ic_light_rain);
        } else if (skycon.equals("PARTLY_CLOUDY_DAY")) {
            layout.setBackgroundResource(R.drawable.ic_partly_cloudy_day);
        } else if (skycon.equals("PARTLY_CLOUDY_NIGHT")) {
            layout.setBackgroundResource(R.drawable.ic_partly_cloudy_night);
        } else if (skycon.equals("STORM_RAIN")) {
            layout.setBackgroundResource(R.drawable.ic_storm_rain);
        } else {
            String curDate = java.text.DateFormat.getDateTimeInstance().format(Calendar.getInstance().getTime());
            String timeOfDay = curDate.substring(curDate.length() - 2);
            Log.i("Time", timeOfDay);
            if (timeOfDay.equals("AM")) {
                layout.setBackgroundResource(R.drawable.ic_clear_day);
            } else {
                layout.setBackgroundResource(R.drawable.ic_clear_night);
            }

        }
    }



    public void searchForCity(View view) {
        EditText search = (EditText) findViewById(R.id.searchBox);
        String location = search.getText().toString();

        if(location.indexOf(" ") != -1){
            geocodeCity = location.substring(0, location.indexOf(" "));
            geocodeAddress = location.substring(location.indexOf(" ") + 1);

            String url = getGeocodeInfoUrl();
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder().url(url).build();
            Call call = client.newCall(request);
            call.enqueue(new Callback() {
                @Override
                public void onFailure(@NotNull Call call, @NotNull IOException e) {
                    e.printStackTrace();
                }

                @Override
                public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                    final String result = response.body().string();
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                deserializeGeocodeInfo(result);
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            });
        }
        else{
         Toast.makeText(this, "查询区域格式不正确;参照格式: 北京 朝阳", Toast.LENGTH_LONG).show();
        }
    }

    public void deserializeGeocodeInfo(String result) throws JSONException {
        String location = null;
        String geocodeInfo = result;

        Log.i("Geocode info", geocodeInfo);

        JSONObject geoInfo = new JSONObject(result);
        String count = geoInfo.optString("count");

        if(Integer.valueOf(count) != 0){
            String gcode = geoInfo.optString("geocodes");
            Log.i("Geocode info", gcode);
            List<HashMap> geocodeList = JSON.parseArray(gcode, HashMap.class);
            for (int i = 0; i < geocodeList.size(); i++) {
                location = (String) geocodeList.get(i).get("location");
            }
            longitude = location.substring(0, location.indexOf(","));
            latitude = location.substring(location.indexOf(",") + 1);

            TextView cityView = (TextView) findViewById(R.id.city);
            cityView.setText(geocodeCity);
            requestWeatherInfo();
        }
        else{
            Toast.makeText(this, "找不到该区域", Toast.LENGTH_LONG).show();
        }
    }

    public void getReGeoInformation(){
        String url = getRegeocodeInfoUrl();
        Log.i("Regeo info", url);
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(url).build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                final String result = response.body().string();
                Log.i("Regeo info", result);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            deserializeRegeocodeInfo(result);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        });
    }

    public void deserializeRegeocodeInfo(String result) throws JSONException{
        String info = result;

        JSONObject infoJson = new JSONObject(info);
        String regeocodeInfo = infoJson.optString("regeocode");

        Log.i("Regeo info", regeocodeInfo);

        JSONObject addressComponentJson = new JSONObject(regeocodeInfo);
        String addressComponentInfo = addressComponentJson.optString("addressComponent");

        Log.i("Regeo info", addressComponentInfo);

        JSONObject specAddressJson = new JSONObject(addressComponentInfo);
        String city = specAddressJson.optString("city");
        String province = specAddressJson.optString("province");

        Log.i("Regeo info", city);
        Log.i("Regeo info", province);

        TextView cityView = (TextView) findViewById(R.id.city);
        cityView.setText(province + " " + city);
    }
}

AndroidManifest. xml

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

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AppCompat.Light.NoActionBar"
        >
        <activity android:name=".MainActivity" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>

Казалось, что приложение работает без проблем на моем Xperia X Compact с Android Oreo. Но, похоже, трещал sh при запуске с моим Xperia 1, работающим Android 10.

Вот лог-код:

Connected to process 16273 on device 'sony-j9110-QV713V4B1T'.
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
I/Perf: Connecting to perf service.
E/Perf: Fail to get file list xyz.geshkii.weather
    getFolderSize() : Exception_1 = java.lang.NullPointerException: Attempt to get length of null array
    Fail to get file list xyz.geshkii.weather
    getFolderSize() : Exception_1 = java.lang.NullPointerException: Attempt to get length of null array
W/geshkii.weathe: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (greylist, reflection, allowed)
    Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (greylist, reflection, allowed)

Есть идеи, как это могло произойти? Спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...