When i start app in emulator, its work properly, but when i install it on phone(I tested it on 2 of my friends phones), its not working like it should
I think the problem is with permissions stuff, but im not sure. Also it could be problem with JsonObjectRequest. So when i enter city name in my phone, i recieve "aaaaaaa, enter city name" from Response.ErrorListener()
There some code, MainActivity:
package com.example.weatherapp;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.recyclerview.widget.RecyclerView;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import com.google.android.material.textfield.TextInputEditText;
import com.squareup.picasso.Picasso;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class MainActivity extends AppCompatActivity {
private RelativeLayout homeRL;
private ProgressBar loadingPB;
private TextView cityNameTV, temperatureTV,conditionTV;
private RecyclerView weatherRV;
private TextInputEditText cityEdt;
private ImageView backIV, iconIV, searchIV;
private ArrayList<WeatherRVModal> weatherRVModalArrayList;
private WeatherRVAdapter weatherRVAdapter;
private LocationManager locationManager;
private int PERMISSION_CODE=1;
private String cityName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
setContentView(R.layout.activity_main);
homeRL = findViewById(R.id.idRLHome);
loadingPB = findViewById(R.id.idPBLoading);
cityNameTV = findViewById(R.id.idTVCityName);
temperatureTV = findViewById(R.id.idTVTemprature);
conditionTV = findViewById(R.id.idTVCondition);
weatherRV = findViewById(R.id.idRVWeather);
cityEdt = findViewById(R.id.idEdtCity);
backIV = findViewById(R.id.idIVBack);
iconIV = findViewById(R.id.idIVIcon);
searchIV = findViewById(R.id.idIVSearch);
weatherRVModalArrayList = new ArrayList<>();
weatherRVAdapter = new WeatherRVAdapter(this,weatherRVModalArrayList);
weatherRV.setAdapter(weatherRVAdapter);
locationManager=(LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_CODE);
}
Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
//cityName = "London";
//getWeatherInfo(cityName);
if (location != null) {
cityName = getCityName(location.getLongitude(), location.getLatitude());
getWeatherInfo(cityName);
} else {
Toast.makeText(this,"invalid location", Toast.LENGTH_SHORT).show();
}
searchIV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//String city = cityEdt.getText().toString();
String city = cityEdt.getText().toString();
//Toast.makeText(MainActivity.this, city, Toast.LENGTH_SHORT).show();
if (city.isEmpty()){
Toast.makeText(MainActivity.this, "Enter your city name", Toast.LENGTH_SHORT).show();
} else {
cityNameTV.setText(city);
getWeatherInfo(city);
}
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode==PERMISSION_CODE) {
if (grantResults.length>0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Permission granted", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Please grant permission", Toast.LENGTH_SHORT).show();
finish();
}
}
}
private String getCityName(double longitude, double latitude){
String cityName = "Not found";
Geocoder gcd = new Geocoder(getBaseContext(), Locale.getDefault());
try {
List<Address> addresses = gcd.getFromLocation(latitude,longitude, 10);
for (Address adr : addresses) {
if (adr!=null) {
String city = adr.getLocality();
if (city!=null && !city.equals("")){
cityName = city;
} else {
Log.d("TAG", "CITY NOT FOUND");
Toast.makeText(this, "User City Not Found...", Toast.LENGTH_SHORT).show();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return cityName;
}
private void getWeatherInfo(String cityName) {
String url = "http://api.weatherapi.com/v1/forecast.json?key=978870d191bb464f997175225221411&q="+cityName+"&days=1&aqi=yes&alerts=yes";
cityNameTV.setText(cityName);
RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
loadingPB.setVisibility(View.GONE);
homeRL.setVisibility(View.VISIBLE);
weatherRVModalArrayList.clear();
try {
String temperature = response.getJSONObject("current").getString("temp_c");
temperatureTV.setText(temperature + "°C");
int isDay = response.getJSONObject("current").getInt("is_day");
String condition = response.getJSONObject("current").getJSONObject("condition").getString("text");
String conditionIcon = response.getJSONObject("current").getJSONObject("condition").getString("icon");
Picasso.get().load("http:".concat(conditionIcon)).into(iconIV);
conditionTV.setText(condition);
if (isDay == 1) {
Picasso.get().load("https://images.unsplash.com/photo-1623949366895-4d7e63f08037?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=735&q=80").into(backIV);
} else {
Picasso.get().load("https://images.unsplash.com/photo-1505322022379-7c3353ee6291?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80").into(backIV);
}
JSONObject forecastObj = response.getJSONObject("forecast");
JSONObject forecast0 = forecastObj.getJSONArray("forecastday").getJSONObject(0);
JSONArray hourArray = forecast0.getJSONArray("hour");
for (int i=0; i<hourArray.length(); i++) {
JSONObject hourObj = hourArray.getJSONObject(i);
String time = hourObj.getString("time");
String temper = hourObj.getString("temp_c");
String img = hourObj.getJSONObject("condition").getString("icon");
String wind = hourObj.getString("wind_kph");
weatherRVModalArrayList.add(new WeatherRVModal(time, temper, img, wind));
}
weatherRVAdapter.notifyDataSetChanged();
} catch (JSONException e) {
Toast.makeText(MainActivity.this, "fail", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(MainActivity.this,"aaaaaaa, enter city name", Toast.LENGTH_SHORT).show();
}
});
requestQueue.add(jsonObjectRequest);
}
}
AndroidManifest.xml:
<?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.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@drawable/cloudy"
android:label="@string/app_name"
android:roundIcon="@drawable/cloudy"
android:supportsRtl="true"
android:theme="@style/Theme.WeatherApp"
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>
WeatherRVModal:
package com.example.weatherapp;
public class WeatherRVModal {
private String time;
private String temperature;
private String icon;
private String windSpeed;
public WeatherRVModal(String time, String temperature, String icon, String windSpeed) {
this.time = time;
this.temperature = temperature;
this.icon = icon;
this.windSpeed = windSpeed;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getTemperature() {
return temperature;
}
public void setTemperature(String temperature) {
this.temperature = temperature;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public String getWindSpeed() {
return windSpeed;
}
public void setWindSpeed(String windSpeed) {
this.windSpeed = windSpeed;
}
}
WeatherRVAdapter:
package com.example.weatherapp;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.squareup.picasso.Picasso;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
public class WeatherRVAdapter extends RecyclerView.Adapter<WeatherRVAdapter.ViewHolder> {
private Context context;
private ArrayList<WeatherRVModal> weatherRVModalArrayList;
public WeatherRVAdapter(Context context, ArrayList<WeatherRVModal> weatherRVModalArrayList) {
this.context = context;
this.weatherRVModalArrayList = weatherRVModalArrayList;
}
@NonNull
@Override
public WeatherRVAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.weather_rv_item,parent,false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull WeatherRVAdapter.ViewHolder holder, int position) {
WeatherRVModal modal = weatherRVModalArrayList.get(position);
holder.temperatureTV.setText(modal.getTemperature() + "°C");
Picasso.get().load("http:".concat(modal.getIcon())).into(holder.conditionIV);
holder.windTV.setText(modal.getWindSpeed()+"Км/ч");
SimpleDateFormat input = new SimpleDateFormat("yyyy-MM-dd hh:mm");
SimpleDateFormat output = new SimpleDateFormat("hh:mm aa");
try {
Date t = input.parse(modal.getTime());
holder.timeTV.setText(output.format(t));
} catch (ParseException e) {
e.printStackTrace();
}
}
@Override
public int getItemCount() {
return weatherRVModalArrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView windTV,temperatureTV,timeTV;
private ImageView conditionIV;
public ViewHolder(@NonNull View itemView) {
super(itemView);
windTV=itemView.findViewById(R.id.idTVWindSpeed);
temperatureTV=itemView.findViewById(R.id.idTVTemprature);
timeTV=itemView.findViewById(R.id.idTVTime);
conditionIV=itemView.findViewById(R.id.idIVCondition);
}
}
}
Im new in Android Studio so if I have not attached something say and I will do it
After debugging Your Code I Found JSONException In Your HTTP api requests.
volley.Response
TO Solve This Problem Use ( HTTPS )
https://api.weatherapi.com/v1/forecast.json?key=978870d191bb464f997175225221411&q="+cityName+"&days=1&aqi=yes&alerts=yes
Thanks.