I am a newbie in the developing section, recently I'm trying to edit the source code of the web view application. But the problem is every time of "backpress" interstitial ad appears. Which is huge disturbing. Tried to change back press code but after doing that ads totally diseapred. Now I'm confused that how can I solve this problem. Because if a web view app show ads every back press, probably google will not approve it on play store even if accepts then people will not use this app.
I've tried to limit but cannot understand, please help me.
If this is possible the ad shows only one time of back press or at least a limited backpress.
Thanks in advance <3 <3
mainactivity.java
//Views
public Toolbar mToolbar;
public View mHeaderView;
public TabLayout mSlidingTabLayout;
public SwipeableViewPager mViewPager;
//App Navigation Structure
private NavigationAdapter mAdapter;
private NavigationView navigationView;
private SimpleMenu menu;
private WebFragment CurrentAnimatingFragment = null;
private int CurrentAnimation = 0;
//Identify toolbar state
private static int NO = 0;
private static int HIDING = 1;
private static int SHOWING = 2;
//Keep track of the interstitials we show
private int interstitialCount = -1;
private InterstitialAd mInterstitialAd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ThemeUtils.setTheme(this);
setContentView(R.layout.activity_main);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
mHeaderView = (View) findViewById(R.id.header_container);
mSlidingTabLayout = (TabLayout) findViewById(R.id.tabs);
mViewPager = (SwipeableViewPager) findViewById(R.id.pager);
setSupportActionBar(mToolbar);
mAdapter = new NavigationAdapter(getSupportFragmentManager(), this);
final Intent intent = getIntent();
final String action = intent.getAction();
if (Intent.ACTION_VIEW.equals(action)) {
String data = intent.getDataString();
((App) getApplication()).setPushUrl(data);
}
//Hiding ActionBar/Toolbar
if (Config.HIDE_ACTIONBAR)
getSupportActionBar().hide();
if (getHideTabs())
mSlidingTabLayout.setVisibility(View.GONE);
hasPermissionToDo(this, Config.PERMISSIONS_REQUIRED);
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) mViewPager.getLayoutParams();
if ((Config.HIDE_ACTIONBAR && getHideTabs()) || ((Config.HIDE_ACTIONBAR || getHideTabs()) && getCollapsingActionBar())){
lp.topMargin = 0;
} else if ((Config.HIDE_ACTIONBAR || getHideTabs()) || (!Config.HIDE_ACTIONBAR && !getHideTabs() && getCollapsingActionBar())){
lp.topMargin = getActionBarHeight();
} else if (!Config.HIDE_ACTIONBAR && !getHideTabs()){
lp.topMargin = getActionBarHeight() * 2;
}
mViewPager.setLayoutParams(lp);
//Tabs
mViewPager.setAdapter(mAdapter);
mViewPager.setOffscreenPageLimit(mViewPager.getAdapter().getCount() - 1);
mSlidingTabLayout.setupWithViewPager(mViewPager);
mSlidingTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
if (getCollapsingActionBar()) {
showToolbar(getFragment());
}
mViewPager.setCurrentItem(tab.getPosition());
showInterstitial();
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
for (int i = 0; i < mSlidingTabLayout.getTabCount(); i++) {
if (Config.ICONS.length > i && Config.ICONS[i] != 0) {
mSlidingTabLayout.getTabAt(i).setIcon(Config.ICONS[i]);
}
}
//Drawer
if (Config.USE_DRAWER) {
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
DrawerLayout drawer = ((DrawerLayout) findViewById(R.id.drawer_layout));
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, mToolbar, 0, 0);
drawer.addDrawerListener(toggle);
toggle.syncState();
//Menu items
navigationView = (NavigationView) findViewById(R.id.nav_view);
menu = new SimpleMenu(navigationView.getMenu(), this);
configureMenu(menu);
if (Config.HIDE_DRAWER_HEADER) {
navigationView.getHeaderView(0).setVisibility(View.GONE);
navigationView.setFitsSystemWindows(false);
} else {
if (Config.DRAWER_ICON != R.mipmap.ic_launcher)
((ImageView) navigationView.getHeaderView(0).findViewById(R.id.drawer_icon)).setImageResource(Config.DRAWER_ICON);
else {
((ImageView) navigationView.getHeaderView(0).findViewById(R.id.launcher_icon)).setVisibility(View.VISIBLE);
((ImageView) navigationView.getHeaderView(0).findViewById(R.id.drawer_icon)).setVisibility(View.INVISIBLE);
}
}
} else {
((DrawerLayout) findViewById(R.id.drawer_layout)).setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
MobileAds.initialize(this, new OnInitializationCompleteListener() {
#Override
public void onInitializationComplete(InitializationStatus initializationStatus) {
}
});
//Admob
if (!getResources().getString(R.string.ad_banner_id).equals("")) {
// Look up the AdView as a resource and load a request.
AdView adView = (AdView) findViewById(R.id.adView);
AdRequest adRequest = new AdRequest.Builder().addTestDevice(AdRequest.DEVICE_ID_EMULATOR).build();
adView.loadAd(adRequest);
} else {
AdView adView = (AdView) findViewById(R.id.adView);
adView.setVisibility(View.GONE);
}
if (getResources().getString(R.string.ad_interstitial_id).length() > 0 && Config.INTERSTITIAL_INTERVAL > 0){
mInterstitialAd = new InterstitialAd(this);
mInterstitialAd.setAdUnitId(getResources().getString(R.string.ad_interstitial_id));
AdRequest adRequestInter = new AdRequest.Builder().addTestDevice(AdRequest.DEVICE_ID_EMULATOR).build();
mInterstitialAd.loadAd(adRequestInter);
mInterstitialAd.setAdListener(new AdListener() {
#Override
public void onAdClosed() {
// Load the next interstitial.
mInterstitialAd.loadAd(new AdRequest.Builder().addTestDevice(AdRequest.DEVICE_ID_EMULATOR).build());
}
});
}
//Application rating
AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setTitle(getString(R.string.rate_title))
.setMessage(String.format(getString(R.string.rate_message), getString(R.string.app_name)))
.setPositiveButton(getString(R.string.rate_yes), null)
.setNegativeButton(getString(R.string.rate_never), null)
.setNeutralButton(getString(R.string.rate_later), null);
new AppRate(this)
.setShowIfAppHasCrashed(false)
.setMinDaysUntilPrompt(2)
.setMinLaunchesUntilPrompt(2)
.setCustomDialog(builder)
.init();
//Showing the splash screen
if (Config.SPLASH) {
findViewById(R.id.imageLoading1).setVisibility(View.VISIBLE);
//getFragment().browser.setVisibility(View.GONE);
}
//Toolbar styling
if (Config.TOOLBAR_ICON != 0) {
getSupportActionBar().setTitle("");
ImageView imageView = findViewById(R.id.toolbar_icon);
imageView.setImageResource(Config.TOOLBAR_ICON);
imageView.setVisibility(View.VISIBLE);
if (!Config.USE_DRAWER){
imageView.setScaleType(ImageView.ScaleType.FIT_START);
}
}
}
// using the back button of the device
#Override
public void onBackPressed() {
View customView = null;
WebChromeClient.CustomViewCallback customViewCallback = null;
if (getFragment().chromeClient != null) {
customView = getFragment().chromeClient.getCustomView();
customViewCallback = getFragment().chromeClient.getCustomViewCallback();
}
if ((customView == null)
&& getFragment().browser.canGoBack()) {
getFragment().browser.goBack();
} else if (customView != null
&& customViewCallback != null) {
customViewCallback.onCustomViewHidden();
} else {
super.onBackPressed();
}
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
//Adjust menu item visibility/availability based on settings
if (Config.HIDE_MENU_SHARE) {
menu.findItem(R.id.share).setVisible(false);
}
if (Config.HIDE_MENU_HOME) {
menu.findItem(R.id.home).setVisible(false);
}
if (Config.HIDE_MENU_NAVIGATION){
menu.findItem(R.id.previous).setVisible(false);
menu.findItem(R.id.next).setVisible(false);
}
if (!Config.SHOW_NOTIFICATION_SETTINGS || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP){
menu.findItem(R.id.notification_settings).setVisible(false);
}
ThemeUtils.tintAllIcons(menu, this);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
WebView browser = getFragment().browser;
if (item.getItemId() == (R.id.next)) {
browser.goForward();
return true;
} else if (item.getItemId() == R.id.previous) {
browser.goBack();
return true;
} else if (item.getItemId() == R.id.share) {
getFragment().shareURL();
return true;
} else if (item.getItemId() == R.id.about) {
AboutDialog();
return true;
} else if (item.getItemId() == R.id.home) {
browser.loadUrl(getFragment().mainUrl);
return true;
} else if (item.getItemId() == R.id.close) {
finish();
Toast.makeText(getApplicationContext(),
getText(R.string.exit_message), Toast.LENGTH_SHORT).show();
return true;
} else if (item.getItemId() == R.id.notification_settings){
Intent intent = new Intent();
intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
intent.putExtra("app_package", getPackageName());
intent.putExtra("app_uid", getApplicationInfo().uid);
intent.putExtra("android.provider.extra.APP_PACKAGE", getPackageName());
startActivity(intent);
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onPause() {
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
}
/**
* Showing the About Dialog
*/
private void AboutDialog() {
// setting the dialogs text, and making the links clickable
final TextView message = new TextView(this);
// i.e.: R.string.dialog_message =>
final SpannableString s = new SpannableString(
this.getText(R.string.dialog_about));
Linkify.addLinks(s, Linkify.WEB_URLS);
message.setTextSize(15f);
int padding = Math.round(20 * getResources().getDisplayMetrics().density);
message.setPadding(padding, 15, padding, 15);
message.setText(Html.fromHtml(getString(R.string.dialog_about)));
message.setMovementMethod(LinkMovementMethod.getInstance());
// creating the actual dialog
AlertDialog.Builder AlertDialog = new AlertDialog.Builder(this);
AlertDialog.setTitle(Html.fromHtml(getString(R.string.about)))
// .setTitle(R.string.about)
.setCancelable(true)
// .setIcon(android.R.drawable.ic_dialog_info)
.setPositiveButton("ok", null).setView(message).create().show();
}
/**
* Set the ActionBar Title
* #param title title
*/
public void setTitle(String title) {
if (mAdapter != null && mAdapter.getCount() == 1 && !Config.USE_DRAWER && !Config.STATIC_TOOLBAR_TITLE)
getSupportActionBar().setTitle(title);
}
/**
* #return the Current WebFragment
*/
public WebFragment getFragment(){
return (WebFragment) mAdapter.getCurrentFragment();
}
/**
* Hide the Splash Screen
*/
public void hideSplash() {
if (Config.SPLASH) {
if (findViewById(R.id.imageLoading1).getVisibility() == View.VISIBLE) {
Handler mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
public void run() {
// hide splash image
findViewById(R.id.imageLoading1).setVisibility(
View.GONE);
}
// set a delay before splashscreen is hidden
}, Config.SPLASH_SCREEN_DELAY);
}
}
}
/**
* Hide the toolbar
*/
public void hideToolbar() {
if (CurrentAnimation != HIDING) {
CurrentAnimation = HIDING;
AnimatorSet animSetXY = new AnimatorSet();
ObjectAnimator animY = ObjectAnimator.ofFloat(getFragment().rl, "y", 0);
ObjectAnimator animY1 = ObjectAnimator.ofFloat(mHeaderView, "y", -getActionBarHeight());
animSetXY.playTogether(animY, animY1);
animSetXY.start();
animSetXY.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
CurrentAnimation = NO;
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
}
}
/**
* Show the toolbar
* #param fragment for which to show the toolbar
*/
public void showToolbar(WebFragment fragment) {
if (CurrentAnimation != SHOWING || fragment != CurrentAnimatingFragment) {
CurrentAnimation = SHOWING;
CurrentAnimatingFragment = fragment;
AnimatorSet animSetXY = new AnimatorSet();
ObjectAnimator animY = ObjectAnimator.ofFloat(fragment.rl, "y", getActionBarHeight());
ObjectAnimator animY1 = ObjectAnimator.ofFloat(mHeaderView, "y", 0);
animSetXY.playTogether(animY, animY1);
animSetXY.start();
animSetXY.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
CurrentAnimation = NO;
CurrentAnimatingFragment = null;
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
}
}
public int getActionBarHeight() {
int mHeight = mToolbar.getHeight();
//Just in case we get a unreliable result, get it from metrics
if (mHeight == 0){
TypedValue tv = new TypedValue();
if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true))
{
mHeight = TypedValue.complexToDimensionPixelSize(tv.data,getResources().getDisplayMetrics());
}
}
return mHeight;
}
boolean getHideTabs(){
if (mAdapter.getCount() == 1 || Config.USE_DRAWER){
return true;
} else {
return Config.HIDE_TABS;
}
}
public static boolean getCollapsingActionBar(){
if (Config.COLLAPSING_ACTIONBAR && !Config.HIDE_ACTIONBAR){
return true;
} else {
return false;
}
}
/**
* Check permissions on app start
* #param context
* #param permissions Permissions to check
* #return if the permissions are available
*/
private static boolean hasPermissionToDo(final Activity context, final String[] permissions) {
boolean oneDenied = false;
for (String permission : permissions) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
ContextCompat.checkSelfPermission(context, permission)
!= PackageManager.PERMISSION_GRANTED)
oneDenied = true;
}
if (!oneDenied) return true;
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(R.string.common_permission_explaination);
builder.setPositiveButton(R.string.common_permission_grant, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Fire off an async request to actually get the permission
// This will show the standard permission request dialog UI
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
context.requestPermissions(permissions,1);
}
});
AlertDialog dialog = builder.create();
dialog.show();
return false;
}
/**
* Show an interstitial ad
*/
public void showInterstitial(){
if (interstitialCount == (Config.INTERSTITIAL_INTERVAL - 1)) {
if (mInterstitialAd != null && mInterstitialAd.isLoaded()) {
mInterstitialAd.show();
}
interstitialCount = 0;
} else {
interstitialCount++;
}
}
/**
* Configure the navigationView
* #param menu to modify
*/
public void configureMenu(SimpleMenu menu){
for (int i = 0; i < Config.TITLES.length; i++) {
//The title
String title = null;
Object titleObj = Config.TITLES[i];
if (titleObj instanceof Integer && !titleObj.equals(0)) {
title = getResources().getString((int) titleObj);
} else {
title = (String) titleObj;
}
//The icon
int icon = 0;
if (Config.ICONS.length > i)
icon = Config.ICONS[i];
menu.add((String) Config.TITLES[i], icon, new Action(title, Config.URLS[i]));
}
menuItemClicked(menu.getFirstMenuItem().getValue(), menu.getFirstMenuItem().getKey());
}
#Override
public void menuItemClicked(Action action, MenuItem item) {
if (WebToAppWebClient.urlShouldOpenExternally(action.url)){
//Load url outside WebView
try {
startActivity(
new Intent(Intent.ACTION_VIEW, Uri.parse(action.url)));
} catch(ActivityNotFoundException e) {
if (action.url.startsWith("intent://")) {
startActivity(
new Intent(Intent.ACTION_VIEW, Uri.parse(action.url.replace("intent://", "http://"))));
} else {
Toast.makeText(this, getResources().getString(R.string.no_app_message), Toast.LENGTH_LONG).show();
}
}
} else {
//Uncheck all other items, check the current item
for (MenuItem menuItem : menu.getMenuItems())
menuItem.setChecked(false);
item.setChecked(true);
//Close the drawer
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
//Load the url
if (getFragment() == null) return;
getFragment().browser.loadUrl("about:blank");
getFragment().setBaseUrl(action.url);
//Show intersitial if applicable
showInterstitial();
Log.v("INFO", "Drawer Item Selected");
}
}
}
This is not comprehensive solution for sure, but I just implement these kind of features for my own app.
If you just want to limit the frequency of the ads showing, in AdMob, you can set limit how often per time unit the add can be shown. AdMob help for setting frequency capping
Another way of limiting the ads could be achieved using probability.
Add proper probability value for your case like this to make ad to shown only every once in a while:
private void showInterstitial(Boolean AdsEnabled) {
final int random = new Random().nextInt(101);
if(random > 95 && AdsEnabled){
if (mInterstitialAd != null && mInterstitialAd.isLoaded() ) {
mInterstitialAd.show();
Log.i("ads","Interstiade ad shown");
} else {
//Do something else
Log.i("ads","Interstiade ad was not loaded");
}
}
}
You can tune your ads to show up more natural using both of these features.
And for why you don't see any ads right now. I might be too beginner my self too, to see why this is the case. But I would add this kind of loader for each backspace press to make sure the ad is loaded. At least I have seen, that sometimes ads fails to load, and this works for me. I have this piece of code used every time I try to show the add.
if (!mInterstitialAd.isLoading() && !mInterstitialAd.isLoaded()) {
Log.i("ads", "Loading new add, because there was no ad ready");
AdRequest adRequest = new AdRequest.Builder().build();
mInterstitialAd.loadAd(adRequest);
}
It sees to me, that you load the ad when you initialise the ad, and at ad close. But if the ad fails to load at oncreate, do you have the ad close events at all to reload the ad?
I also wonder this
public void showInterstitial(){
if (interstitialCount == (Config.INTERSTITIAL_INTERVAL - 1)) {
this shows the ad only when these values are equal. So are you sure that Config.INTERSTITIAL_INTERVAL is at least 1? I think you should change "==" to ">=" to make sure you show the ads even if the INTERSTITIAL_INTERVAL is zero or negative. Or get rid of the minus 1 and keep Config.INTERSTITIAL_INTERVAL positive integer. You have interstitialCount initialised -1 at beginning so this should so the first ad one click later than the next ads, but again, I'm not sure why the ads are not shown right now.
I hope these answers helped you. But as I said, I'm still beginner my self.
-Jussi
I have a mind-boggling problem I can't seem to solve.
The data in my RecyclerView is not updating, and after an entire day of debugging, I can't find the problematic code. The API returns the correct data, and I parse the correct data in a wallItemList which I pass to the Adapter.
How It Should Behave
After changing the language setting to either one of the 2 (English or Dutch), the items in my Recyclerview should update with it and the title of the element should change to the translated string.
What I Have Tried
Creating a refresh function inside the adapter, and update the wallItemList manually by passing the created wallItemList from the MainActivity and calling notifyDataSetChanged()
Calling notifyDataSetChanged() before, in and after the OnClickListener in the MyRecyclerViewAdapter
Setting the item in onBindViewHolder in the MyRecyclerViewAdapter
Strangely enough, when logging the language of the wallItem just before adapter.setOnItemClickListener in populateRecyclerView(), the language is right. But when I get the string from the object in MyRecyclerViewAdapter's onBindViewHolder, it shows the wrong language.
Here is my MainActivity.java:
public class MainActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
private List<WallItem> WallItemList;
private RecyclerView mRecyclerView;
private MyRecyclerViewAdapter adapter;
private ProgressBar progressBar;
// LifeCycle variables
private String JSONResults = "";
final static private String JSON_KEY_RESULTS = "";
final static private String WALL_ITEM_LIST_KEY = "";
// SharedPrefences variables
private String APIUrlPreferenceString = "";
private String langPreferenceString = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
// Setup shared preferences
setupSharedPreferences();
// Load the recyclerView
loadRecyclerView(savedInstanceState);
}
private void setLanguageSettings(String lang)
{
//create a string for country
String country = "";
if(lang.equals("en"))
{
country = "EN";
}
else if(lang.equals("nl"))
{
country = "NL";
}
//use constructor with country
Locale locale = new Locale(lang, country);
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config,
getBaseContext().getResources().getDisplayMetrics());
}
private void setupSharedPreferences()
{
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
APIUrlPreferenceString = sharedPreferences.getString(getString(R.string.pref_api_url_key), getString(R.string.pref_api_url_def_value));
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
// Language settings
if(sharedPreferences.getBoolean(getString(R.string.pref_lang_check_key), true))
{
// Use device settings
setLanguageSettings(Resources.getSystem().getConfiguration().locale.getLanguage());
langPreferenceString = Resources.getSystem().getConfiguration().locale.getLanguage();
}
else
{
// Use preference settings
setLanguageSettings(sharedPreferences.getString(getString(R.string.pref_lang_list_key), getString(R.string.pref_lang_label_en)));
langPreferenceString = sharedPreferences.getString(getString(R.string.pref_lang_list_key), getString(R.string.pref_lang_label_en));
}
}
private void loadRecyclerView(Bundle savedInstanceState)
{
// Lifecycle event to preserve data to prevent repeating API calls
if(savedInstanceState != null && savedInstanceState.containsKey(WALL_ITEM_LIST_KEY) && savedInstanceState.containsKey(JSON_KEY_RESULTS))
{
progressBar.setVisibility(View.GONE);
// Set again in order to preserve state on future rotations
JSONResults = savedInstanceState.getString(JSON_KEY_RESULTS);
// Set wallItemList again in order to preserve state on future rotations
WallItemList = savedInstanceState.getParcelableArrayList(WALL_ITEM_LIST_KEY);
populateRecyclerView();
}
else
{
// First execution
new DownloadTask().execute();
}
}
public class DownloadTask extends AsyncTask<Void, Void, Boolean> {
#Override
protected void onPreExecute() {
progressBar.setVisibility(View.VISIBLE);
}
#Override
protected Boolean doInBackground(Void... params) {
boolean result;
String blindWallResults;
try {
// Error fix, because NetworkUtils.buildUrl returns null when failing
if(null == NetworkUtils.buildUrl(APIUrlPreferenceString))
return false;
// Get response from API
blindWallResults = NetworkUtils.getResponseFromHttpUrl(NetworkUtils.buildUrl(APIUrlPreferenceString));
// Send to parser
JSONResults = blindWallResults;
parseResult(blindWallResults);
result = true;
} catch (IOException e) {
e.printStackTrace();
result = false;
}
// When failed
return result;
}
#Override
protected void onPostExecute(Boolean result) {
progressBar.setVisibility(View.GONE);
// If succeeded
if (result) {
populateRecyclerView();
// Show toast when data has been loaded for the first time
Toast.makeText(MainActivity.this, getString(R.string.json_toast_data_loaded), Toast.LENGTH_SHORT).show();
} else {
// If failed make toast
Toast.makeText(MainActivity.this, getString(R.string.json_toast_data_failed), Toast.LENGTH_SHORT).show();
}
}
}
/**
* Populates recyclerView and adds OnItemClickListener
*/
private void populateRecyclerView()
{
WallItem w = WallItemList.get(0);
adapter = new MyRecyclerViewAdapter(MainActivity.this, WallItemList);
mRecyclerView.setAdapter(adapter);
adapter.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(WallItem item) {
// Function to start new activity
Class detailActivity = DetailActivity.class;
// Create intent
Intent startDetailActivityIntent = new Intent(MainActivity.this, detailActivity);
// Add object to intent
startDetailActivityIntent.putExtra("detailWallItem", (Parcelable)item);
// Start activity
startActivity(startDetailActivityIntent);
}
});
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Save instances of existing objects
outState.putString(JSON_KEY_RESULTS, JSONResults);
outState.putParcelableArrayList(WALL_ITEM_LIST_KEY, (ArrayList<? extends Parcelable>) this.WallItemList);
}
/**
* Parses JSON result
*
* #param result
*/
private void parseResult(String result) {
WallItemList = new ArrayList<>();
try {
JSONArray mJsonArray = new JSONArray(result);
// Loop through JSON array
for (int i = 0; i < mJsonArray.length(); i++) {
// Get picture URI fragment from JSON
String pictureURIFragment = mJsonArray.getJSONObject(i)
.getJSONArray("images").getJSONObject(0)
.getString("url");
// Load images into String
JSONArray JSONImageArray = mJsonArray.getJSONObject(i)
.getJSONArray("images");
// Create array for wallItem
String[] imageArray = new String[JSONImageArray.length()];
// Loop through JSONArray
for(int x = 0; x < JSONImageArray.length(); x++)
{
String pictureURLFragment = JSONImageArray.getJSONObject(x).getString("url");
// Built picture
URL pictureURL = NetworkUtils.builtPictureUrl(pictureURLFragment.toLowerCase());
imageArray[x] = java.net.URLDecoder.decode(pictureURL.toString());
}
// Built picture
URL pictureURL = NetworkUtils.builtPictureUrl(pictureURIFragment.toLowerCase());
String cleanPictureUrl = java.net.URLDecoder.decode(pictureURL.toString());
// add wall item to the list
WallItem item = new WallItem();
// Set fields of wallItem
item.setThumbnail(cleanPictureUrl);
item.setTitle(mJsonArray.getJSONObject(i).getString("author"));
item.setPhotographer(mJsonArray.getJSONObject(i).getString("photographer"));
item.setAddress(mJsonArray.getJSONObject(i).getString("address"));
item.setMaterial(mJsonArray.getJSONObject(i).getJSONObject("material").getString(langPreferenceString));
item.setDescription(mJsonArray.getJSONObject(i).getJSONObject("description").getString(langPreferenceString));
item.setImgURLArray(imageArray);
// Add wallItem to list
WallItemList.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId() == R.id.api_url_settings_item)
{
Intent startSettingsActivity = new Intent(this, SettingsActivity.class);
startActivity(startSettingsActivity);
return true;
}
return super.onOptionsItemSelected(item);
}
private void getDeviceLanguage()
{
Log.d("HERE", Locale.getDefault().getLanguage());
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if(key.equals(getString(R.string.pref_api_url_key)))
{
// Update String again
APIUrlPreferenceString = sharedPreferences.getString(getString(R.string.pref_api_url_key), getString(R.string.pref_api_url_def_value));
new DownloadTask().execute();
}
if(key.equals(getString(R.string.pref_lang_check_key)))
{
// 1. If true, use system language.
// 2. if System language != en or nl, use default language: en.
// 3. if false, make selectable
}
if(key.equals(getString(R.string.pref_lang_list_key)) || key.equals(getString(R.string.pref_lang_check_key)))
{
// Language settings
if(sharedPreferences.getBoolean(getString(R.string.pref_lang_check_key), true))
{
// Use device settings
setLanguageSettings(Resources.getSystem().getConfiguration().locale.getLanguage());
langPreferenceString = Resources.getSystem().getConfiguration().locale.getLanguage();
}
else
{
// Use preference settings
setLanguageSettings(sharedPreferences.getString(getString(R.string.pref_lang_list_key), getString(R.string.pref_lang_label_en)));
langPreferenceString = sharedPreferences.getString(getString(R.string.pref_lang_list_key), getString(R.string.pref_lang_label_en));
}
// Reload data after executing new Download task
new DownloadTask().execute();
this.recreate();
}
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
#Override
protected void onDestroy() {
super.onDestroy();
PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this);
}
}
Here is my MyRecyclerViewAdapter.java
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.CustomViewHolder> {
private List<WallItem> wallItemList;
private Context mContext;
private OnItemClickListener onItemClickListener;
public MyRecyclerViewAdapter(Context context, List<WallItem> wallItemList) {
this.wallItemList = wallItemList;
this.mContext = context;
WallItem w = wallItemList.get(0);
}
#Override
public CustomViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_row, null);
CustomViewHolder viewHolder = new CustomViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(CustomViewHolder customViewHolder, int i) {
final WallItem wallItem = wallItemList.get(i);
//Download image using picasso library
if (!TextUtils.isEmpty(wallItem.getThumbnail())) {
// Load image into imageView
Picasso.with(mContext).load(wallItem.getThumbnail())
.error(R.drawable.placeholder)
.placeholder(R.drawable.placeholder)
.into(customViewHolder.imageView);
}
//Setting text view title
customViewHolder.textView.setText(Html.fromHtml(wallItem.getMaterial()));
// Set OnClickListener to wallItem
View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View v) {
onItemClickListener.onItemClick(wallItem);
}
};
customViewHolder.imageView.setOnClickListener(listener);
customViewHolder.textView.setOnClickListener(listener);
}
// Overwrite to return
#Override
public int getItemCount() {
return (null != wallItemList ? wallItemList.size() : 0);
}
class CustomViewHolder extends RecyclerView.ViewHolder {
protected ImageView imageView;
protected TextView textView;
public CustomViewHolder(View view) {
super(view);
this.imageView = (ImageView) view.findViewById(R.id.thumbnail);
this.textView = (TextView) view.findViewById(R.id.title);
}
}
public OnItemClickListener getOnItemClickListener() {
return onItemClickListener;
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
}
My apologies for posting all the code but I can't identify the crucial points and don't have enough experience to pinpoint where it's going wrong. If anyone could help you would it would be greatly appreciated!
I suggest you to initialize and set the adapter in onCreate() method with an empty array of WallItems.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new MyRecyclerViewAdapter(MainActivity.this, new ArrayList<WallItem>());
mRecyclerView.setAdapter(adapter);
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
// Setup shared preferences
setupSharedPreferences();
// Load the recyclerView
loadRecyclerView(savedInstanceState);
}
To update the list of items, I normally have a setItems method inside my adapter that updates the list and calls notifyDataSetChanged()
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.CustomViewHolder> {
...
public void setItems(List<WallItem> items) {
this.wallItemList = wallItemList;
notifyDataSetChanged();
}
}
Your populateRecyclerView method then should call the setItems method to update the new list of items.
private void populateRecyclerView()
{
WallItem w = WallItemList.get(0);
adapter.setItems(WallItemList);
adapter.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(WallItem item) {
// Function to start new activity
Class detailActivity = DetailActivity.class;
// Create intent
Intent startDetailActivityIntent = new Intent(MainActivity.this, detailActivity);
// Add object to intent
startDetailActivityIntent.putExtra("detailWallItem", (Parcelable)item);
// Start activity
startActivity(startDetailActivityIntent);
}
});
}
I didn't test, buy this is how I normally use RecyclerView.
I'm trying to play video on player and the video is url that I fetch from an api
so I have a channels in recycleview1 and when I click on one channel the channel start play in new activity
in that activity the player take half of screen and the rest is for recycleview2 which contain some channels for easy and fast navigate between channels
so when I open the channel from recycleview1 and it start playing then I rotate the screen to landscape it work fine then restore the screen to portrate again the channel still working
but the problem is when I click on channel from recycleview2 which lead to update the url that already played and start the new one
so each time I click on channel from recycleview2 the videoview updated to new channel url that clicked
I face problem when I rotate the screen after played channel from recycleview2 the videoview start play a channel that I clicked from recyclewview1 before clicking on new channel from recycleview2 because it return to onCreate method which build the url depend on the information passed with on click
so I used to save the instance state of url so when I rotate the screen to landscape the vidoeview still played the last channel that played
but the problem is when I re rotate the screen to portrate again the videoview here return to the first channel played when start the activity
I tried to save instance state too but it doesn't working
this is the code:
public class TVChannel extends AppCompatActivity implements
TVAdapter.TVAdapterOnClickHandler {
private VideoView videoView;
private int position = 0;
private String video;
private MediaController mediaController;
String mChannelTitle;
String mChannelApp;
String mChannelStreamname;
String mChannelCat;
TVAdapter mAdapter;
RecyclerView mSportsList;
private TextView mCategory;
private TextView mErrorMessageDisplay;
private ProgressBar mLoadingIndicator;
Context mContext ;
public TVItem channelObject;
Uri vidUri;
String myBoolean;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
setContentView(R.layout.activity_tv_channel);
ButterKnife.bind(this);
mSportsList = (RecyclerView) findViewById(R.id.rv_channel);
mErrorMessageDisplay = (TextView) findViewById(R.id.tv_error_message_display);
mContext = this;
channelObject = getIntent().getParcelableExtra("TVChannel");
if (channelObject != null) {
mChannelTitle = String.valueOf(channelObject.getTitle());
mChannelApp = String.valueOf(channelObject.getApp());
mChannelStreamname = String.valueOf(channelObject.getStreamName());
mChannelCat = String.valueOf(channelObject.getCat());
}
mCategory = (TextView) findViewById(R.id.category);
videoView = (VideoView) findViewById(R.id.videoView);
String host = "http://ip/";
String app = mChannelApp;
String streamname = mChannelStreamname;
String playlist = "playlist.m3u8";
vidUri = Uri.parse(host).buildUpon()
.appendPath(app)
.appendPath(streamname)
.appendPath(playlist)
.build();
videoView.setVideoURI(vidUri);
final PlayerControlView playerControlView = (PlayerControlView) findViewById(R.id.player_control_view);
playerControlView.setAlwaysShow(true);
PlayerControlView.ViewHolder viewHolder = playerControlView.getViewHolder();
viewHolder.pausePlayButton.setPauseDrawable(ContextCompat.getDrawable(this, R.drawable.pause));
viewHolder.pausePlayButton.setPlayDrawable(ContextCompat.getDrawable(this, R.drawable.play));
viewHolder.controlsBackground.setBackgroundColor(ContextCompat.getColor(this, R.color.colorPrimaryDark));
viewHolder.currentTimeText.setTextColor(ContextCompat.getColor(this, R.color.colorAccent));
// viewHolder.totalTimeText.setTextSize(18);
playerControlView.setNextListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(TVChannel.this, "onClick Next", Toast.LENGTH_SHORT).show();
}
});
playerControlView.setPrevListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(TVChannel.this, "onClick Prev", Toast.LENGTH_SHORT).show();
}
});
mediaController = playerControlView.getMediaControllerWrapper();
videoView.setMediaController(mediaController);
videoView.seekTo(position);
videoView.start();
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
playerControlView.show();
}
});
GridLayoutManager LayoutManagerSports = new GridLayoutManager(this, 3);
mSportsList.setLayoutManager(LayoutManagerSports);
mSportsList.setHasFixedSize(true);
mAdapter = new TVAdapter(this, mContext);
mSportsList.setAdapter(mAdapter);
mLoadingIndicator = (ProgressBar) findViewById(R.id.pb_loading_indicator);
String sortchannels = mChannelCat.toLowerCase() + ".php";
loadTVData(sortchannels);
} else {
setContentView(R.layout.activity_tv_channel2);
ButterKnife.bind(this);
mSportsList = (RecyclerView) findViewById(R.id.rv_channel);
mErrorMessageDisplay = (TextView) findViewById(R.id.tv_error_message_display);
mContext = this;
channelObject = getIntent().getParcelableExtra("TVChannel");
if (channelObject != null) {
mChannelTitle = String.valueOf(channelObject.getTitle());
mChannelApp = String.valueOf(channelObject.getApp());
mChannelStreamname = String.valueOf(channelObject.getStreamName());
mChannelCat = String.valueOf(channelObject.getCat());
}
mCategory = (TextView) findViewById(R.id.category);
videoView = (VideoView) findViewById(R.id.videoView);
if (savedInstanceState != null){
myBoolean = savedInstanceState.getString("video");
Toast.makeText(this, "This is my Toast message!",
Toast.LENGTH_LONG).show();
videoView.setVideoURI(Uri.parse(myBoolean));
}
else {
String host = "http://ip/";
String app = mChannelApp;
String streamname = mChannelStreamname;
String playlist = "playlist.m3u8";
vidUri = Uri.parse(host).buildUpon()
.appendPath(app)
.appendPath(streamname)
.appendPath(playlist)
.build();
videoView.setVideoURI(vidUri);
}
final PlayerControlView playerControlView = (PlayerControlView) findViewById(R.id.player_control_view);
playerControlView.setAlwaysShow(false);
PlayerControlView.ViewHolder viewHolder = playerControlView.getViewHolder();
viewHolder.pausePlayButton.setPauseDrawable(ContextCompat.getDrawable(this, R.drawable.pause));
viewHolder.pausePlayButton.setPlayDrawable(ContextCompat.getDrawable(this, R.drawable.play));
viewHolder.controlsBackground.setBackgroundColor(ContextCompat.getColor(this, R.color.controlBackground));
viewHolder.currentTimeText.setTextColor(ContextCompat.getColor(this, R.color.colorAccent));
// viewHolder.totalTimeText.setTextSize(18);
playerControlView.setNextListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(TVChannel.this, "onClick Next", Toast.LENGTH_SHORT).show();
}
});
playerControlView.setPrevListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(TVChannel.this, "onClick Prev", Toast.LENGTH_SHORT).show();
}
});
mediaController = playerControlView.getMediaControllerWrapperFullScreen();
videoView.setMediaController(mediaController);
videoView.seekTo(position);
videoView.start();
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
playerControlView.show();
}
});
GridLayoutManager LayoutManagerSports = new GridLayoutManager(this, 3);
mSportsList.setLayoutManager(LayoutManagerSports);
mSportsList.setHasFixedSize(true);
mAdapter = new TVAdapter(this, mContext);
mSportsList.setAdapter(mAdapter);
mLoadingIndicator = (ProgressBar) findViewById(R.id.pb_loading_indicator);
String sortchannels = mChannelCat.toLowerCase() + ".php";
loadTVData(sortchannels);
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
// Store current position.
savedInstanceState.putString("video", String.valueOf(vidUri));
videoView.start();
}
// After rotating the phone. This method is called.
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Get saved position.
video = savedInstanceState.getString("video");
videoView.start();
}
private void loadTVData(String sortChannels) {
showTVDataView();
new FetchTVTask().execute(sortChannels);
}
#Override
public void onClick(TVItem channel, View view) {
if (channel != null) {
mChannelTitle = String.valueOf(channel.getTitle());
mChannelApp = String.valueOf(channel.getApp());
mChannelStreamname = String.valueOf(channel.getStreamName());
}
String host = "http://ip/";
String app = mChannelApp;
String streamname = mChannelStreamname;
String playlist = "playlist.m3u8";
vidUri = Uri.parse(host).buildUpon()
.appendPath(app)
.appendPath(streamname)
.appendPath(playlist)
.build();
videoView.setVideoURI(vidUri);
final PlayerControlView playerControlView = (PlayerControlView) findViewById(R.id.player_control_view);
playerControlView.setAlwaysShow(true);
PlayerControlView.ViewHolder viewHolder = playerControlView.getViewHolder();
viewHolder.pausePlayButton.setPauseDrawable(ContextCompat.getDrawable(this, R.drawable.pause));
viewHolder.pausePlayButton.setPlayDrawable(ContextCompat.getDrawable(this, R.drawable.play));
viewHolder.controlsBackground.setBackgroundColor(ContextCompat.getColor(this, R.color.colorPrimaryDark));
viewHolder.currentTimeText.setTextColor(ContextCompat.getColor(this, R.color.colorAccent));
// viewHolder.totalTimeText.setTextSize(18);
playerControlView.setNextListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(TVChannel.this, "onClick Next", Toast.LENGTH_SHORT).show();
}
});
playerControlView.setPrevListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(TVChannel.this, "onClick Prev", Toast.LENGTH_SHORT).show();
}
});
videoView.setMediaController(playerControlView.getMediaControllerWrapper());
//
videoView.seekTo(position);
videoView.start();
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
playerControlView.show();
}
});
}
private void showTVDataView() {
mErrorMessageDisplay.setVisibility(View.INVISIBLE);
mSportsList.setVisibility(View.VISIBLE);
}
private void showErrorMessage() {
mSportsList.setVisibility(View.INVISIBLE);
mErrorMessageDisplay.setVisibility(View.VISIBLE);
}
public class FetchTVTask extends AsyncTask<String, Void, ArrayList<TVItem>> {
#Override
protected void onPreExecute() {
super.onPreExecute();
mLoadingIndicator.setVisibility(View.VISIBLE);
}
#Override
protected ArrayList<TVItem> doInBackground(String... params) {
if (params.length == 0) {
return null;
}
String sortChannels = params[0];
URL channelRequestUrl = NetworkTV.buildUrl(sortChannels);
try {
String jsonTVResponse = NetworkTV.getResponseFromHttpUrl(channelRequestUrl);
ArrayList<TVItem> simpleJsonTVData = JsonTV.getSimpleTVStringsFromJson(TVChannel.this, jsonTVResponse);
return simpleJsonTVData;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(ArrayList<TVItem> TVData) {
mLoadingIndicator.setVisibility(View.INVISIBLE);
mCategory.setText(TVData.get(0).getCat());
if (TVData != null) {
showTVDataView();
mAdapter.setTVData(TVData);
} else {
showErrorMessage();
}
}
}
}
you can see that I use:
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
}
else{
}
to set content view for portrait and landscape
and inside else this is the code that I use to save the url in landscape mode:
if (savedInstanceState != null){
myBoolean = savedInstanceState.getString("video");
Toast.makeText(this, "This is my Toast message!",
Toast.LENGTH_LONG).show();
videoView.setVideoURI(Uri.parse(myBoolean));
}
else {
String host = "http://ip/";
String app = mChannelApp;
String streamname = mChannelStreamname;
String playlist = "playlist.m3u8";
vidUri = Uri.parse(host).buildUpon()
.appendPath(app)
.appendPath(streamname)
.appendPath(playlist)
.build();
videoView.setVideoURI(vidUri);
}
and if savedInstanceState null so build url like this from on click information that I pass in portrait mode:
channelObject = getIntent().getParcelableExtra("TVChannel");
if (channelObject != null) {
mChannelTitle = String.valueOf(channelObject.getTitle());
mChannelApp = String.valueOf(channelObject.getApp());
mChannelStreamname = String.valueOf(channelObject.getStreamName());
mChannelCat = String.valueOf(channelObject.getCat());
}
how can I save the url channel when I re rotate screen from landscape to portrait mode again?
I apologize in advance for the potentially confusing title, I'm not exactly sure how to phrase the question, but I'll try to clearly explain what my issue is...
My issue arises when I'm trying to set the text of the TextViews to display the individual distances. I'm using a single TextView in a list_item.xml which my Custom ArrayAdapter then inflates and populates the ListView (word_list.xml) with.
I've tried many methods, but I've only "succeeded" with one specific method - it only ended up populating the first list item with the data, but not the rest of them.
My prime issue is with mFormattedDistanceString (found at the very bottom of the ListView Activity I've copied here). It is the variable in which all my calculated location distance information resides. I can't seem to get it to set to the TextViews within the ArrayList. I feel like the answer might be simple, but I just can't seem to think straight with it - I've tried many different options that I've researched, to no avail.
Custom Data Type for ArrayAdapter.
public class Word {
private String mName;
private int mImageResourceId = NO_IMAGE_PROVIDED;
private double mDistanceLat;
private double mDistanceLong;
private String mLocationData;
private static final int NO_IMAGE_PROVIDED = -1;
public Word(String name) {
mName = name;
}
public Word(String name, int imageResourceId) {
mName = name;
mImageResourceId = imageResourceId;
}
public Word(String name, int imageResourceId, double distanceLat, double distanceLong,
String locationData){
mName = name;
mImageResourceId = imageResourceId;
mDistanceLat = distanceLat;
mDistanceLong = distanceLong;
mLocationData = locationData;
}
public Word(int imageResourceId) {
mImageResourceId = imageResourceId;
}
public String getName() {
return mName;
}
public int getImageResourceId() {
return mImageResourceId;
}
public double getDistanceLat() {
return mDistanceLat;
}
public double getDistanceLong() {
return mDistanceLong;
}
public String getLocationData() {
return mLocationData;
}
public boolean hasImage() {
return mImageResourceId != NO_IMAGE_PROVIDED;
}
}
Custom ArrayAdapter.
I've researched for hours and even tried a few different methods within the getView method, but I couldn't get all my list-items to display the data, only the first element in the list.
public class LocationsAdapter extends ArrayAdapter<Word> {
private LayoutInflater mInflater;
private Context mContext;
private Location mLocation;
private String mFormattedDistanceString;
static class ViewHolder {
TextView text;
ImageView image;
TextView distanceText;
}
public LocationsAdapter(Activity context, List<Word> locations, String formattedDistanceString) {
super(context, 0, locations);
mContext = context;
mInflater = LayoutInflater.from(context);
mFormattedDistanceString = formattedDistanceString;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
Word currentWord = getItem(position);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item, parent, false);
viewHolder = new ViewHolder();
viewHolder.text = (TextView) convertView.findViewById(R.id.name_text_view);
viewHolder.image = (ImageView) convertView.findViewById(R.id.icon_image_view);
viewHolder.distanceText = (TextView) convertView.findViewById(R.id.distance_text_view);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.text.setText(currentWord.getName());
viewHolder.distanceText.setText(currentWord.getLocationData());
if (currentWord.hasImage())
{
viewHolder.image.setVisibility(View.VISIBLE);
} else {
viewHolder.image.setVisibility(View.GONE);
}
return convertView;
}
}
One of my ListView Activites.
public class Locations extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
private static final int PERMISSION_REQUEST_ACCESS_FINE_LOCATION = 100;
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
private static final String LOG_TAG = Locations.class.getName();
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private String mFormattedDistanceString;
public List<Word> locations = new ArrayList<>();
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[],
int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_ACCESS_FINE_LOCATION: {
mGoogleApiClient.connect();
}
}
}
private String simplifiedMilesDecimal(double miles) {
DecimalFormat simplifiedDistance = new DecimalFormat("0.0 Miles Away");
return simplifiedDistance.format(miles);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.word_list);
if (ContextCompat.checkSelfPermission(this,
ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
ACCESS_FINE_LOCATION)) {
} else {
ActivityCompat.requestPermissions(this,
new String[]{ACCESS_FINE_LOCATION},
PERMISSION_REQUEST_ACCESS_FINE_LOCATION);
}
}
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(10 * 1000) // 10 seconds, in milliseconds
.setFastestInterval(1 * 1000); // 1 second, in milliseconds
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
locations.add(new Word("Bristol", R.drawable.bristol,
41.670374, -71.276565, mFormattedDistanceString));
locations.add(new Word("Warren", R.drawable.warren,
41.729085, -71.282283, mFormattedDistanceString));
locations.add(new Word("Newport", R.drawable.newport_breakers,
41.486677, -71.315144, mFormattedDistanceString));
locations.add(new Word("Jamestown", R.drawable.jamestown,
41.496313, -71.368435, mFormattedDistanceString));
locations.add(new Word("Beavertail", R.drawable.beavertail,
41.458054, -71.395744, mFormattedDistanceString));
locations.add(new Word("Providence", R.drawable.providence,
41.830279, -71.414955, mFormattedDistanceString));
locations.add(new Word("Roger Williams Park", R.drawable.roger_williams_park,
41.788673, -71.414179, mFormattedDistanceString));
locations.add(new Word("Colt State Park", R.drawable.colt_state_park,
41.677248, -71.298871, mFormattedDistanceString));
ListView listView = (ListView) findViewById(R.id.list);
ViewCompat.setNestedScrollingEnabled(listView, true);
listView.setAdapter(new LocationsAdapter(this, locations, mFormattedDistanceString));
// Set a click listener to open the default Maps app when the list item is clicked on
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
if (position == 0) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:41.670374, -71.276565?z=15"));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
} else if (position == 1) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:41.729085, -71.282283?z=15"));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
} else if (position == 2) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:41.486677, -71.315144?z=13"));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
} else if (position == 3) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:41.496313, -71.368435?z=14"));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
} else if (position == 4) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:41.458054, -71.395744?z=14"));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
} else if (position == 5) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:41.830279, -71.414955?z=14"));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
} else if (position == 6) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:41.788673, -71.414179?z=16"));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
} else if (position == 7) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:41.677248, -71.298871?z=14"));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
}
});
}
#Override
protected void onStart() {
if (ContextCompat.checkSelfPermission(this,
ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mGoogleApiClient.connect();
}
super.onStart();
}
#Override
protected void onResume() {
if (ContextCompat.checkSelfPermission(this,
ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mGoogleApiClient.connect();
}
super.onResume();
}
#Override
protected void onPause() {
super.onPause();
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient,
this);
mGoogleApiClient.disconnect();
}
}
protected void onStop() {
// If the user has stopped the app, disconnect from the GoogleApiClient.
mGoogleApiClient.disconnect();
super.onStop();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.i(LOG_TAG, "Location services connected.");
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (location == null) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
} else {
handleNewLocation(location);
}
}
#Override
public void onConnectionSuspended(int i) {
Log.i(LOG_TAG, "Location services suspended. Please reconnect.");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
if (connectionResult.hasResolution()) {
try {
// Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(this,
CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
} else {
Log.i(LOG_TAG, "Location services connection failed with code " +
connectionResult.getErrorCode());
}
}
#Override
public void onLocationChanged(Location location) {
handleNewLocation(location);
}
private void handleNewLocation(Location location) {
Log.d(LOG_TAG, location.toString());
LatLng currentUserCoord = new LatLng(location.getLatitude(), location.getLongitude());
Word locationsListItem = locations.get(0);
LatLng destinationCoord = new LatLng(locationsListItem.getDistanceLat(),
locationsListItem.getDistanceLong());
double distanceInMiles =
LatLngTool.distance(currentUserCoord, destinationCoord, LengthUnit.MILE);
String formattedDistance = simplifiedMilesDecimal(distanceInMiles);
mFormattedDistanceString = toString().valueOf(formattedDistance);
Log.i(LOG_TAG, mFormattedDistanceString);
}
}
I tried using a for-loop within the Locations Activity to iterate through the elements in the ArrayList, but I'm not sure if I set it up wrong or if it just isn't the right way to go about solving the problem.
Is the best way to go about it to somehow get the location data held within mFormattedDistanceString and pass it to the LocationsAdapter so that the getView method can do its thing and populate the ListView with the distance information, just like it already does with the ImageViews, etc?
Let me know if I'm wrong and what you think I should do!
UPDATE
Here are my blocks of code with the changes suggested by #cark so we can find the solution... I feel like it's something quite simple, but I can't figure it out - so many variables, references, and methods to keep track of... :(
Word class.
public class Word {
private static final String LOG_TAG = Word.class.getName();
private String mName;
private int mImageResourceId = NO_IMAGE_PROVIDED;
private double mDistanceLat;
private double mDistanceLong;
private Location currentLocation;
private String mFormattedDistanceString;
private String simplifiedMilesDecimal(double miles) {
DecimalFormat simplifiedDistance = new DecimalFormat("0.0 Miles Away");
return simplifiedDistance.format(miles);
}
public void updateDistance(Location location){
if(location.equals(currentLocation)) return;
LatLng currentUserCoord = new LatLng(location.getLatitude(), location.getLongitude());
Log.i(LOG_TAG, toString().valueOf(currentUserCoord));
LatLng destinationCoord = new LatLng(this.getDistanceLat(),
this.getDistanceLong());
double distanceInMiles =
LatLngTool.distance(currentUserCoord, destinationCoord, LengthUnit.MILE);
String formattedDistance = simplifiedMilesDecimal(distanceInMiles);
mFormattedDistanceString = toString().valueOf(formattedDistance);
currentLocation = location;
}
private static final int NO_IMAGE_PROVIDED = -1;
public Word(String name) {
mName = name;
}
public Word(String name, int imageResourceId) {
mName = name;
mImageResourceId = imageResourceId;
}
public Word(String name, int imageResourceId, double distanceLat, double distanceLong,
String formattedDistanceString){
mName = name;
mImageResourceId = imageResourceId;
mDistanceLat = distanceLat;
mDistanceLong = distanceLong;
mFormattedDistanceString = formattedDistanceString;
}
public Word(String name, int imageResourceId, double distanceLat, double distanceLong){
mName = name;
mImageResourceId = imageResourceId;
mDistanceLat = distanceLat;
mDistanceLong = distanceLong;
}
public Word(int imageResourceId) {
mImageResourceId = imageResourceId;
}
public String getName() {
return mName;
}
public int getImageResourceId() {
return mImageResourceId;
}
public double getDistanceLat() {
return mDistanceLat;
}
public double getDistanceLong() {
return mDistanceLong;
}
public String getFormattedDistance() {
return mFormattedDistanceString;
}
public boolean hasImage() {
return mImageResourceId != NO_IMAGE_PROVIDED;
}
}
LocationsAdapter class.
public class LocationsAdapter extends ArrayAdapter<Word> {
private LayoutInflater mInflater;
private Context mContext;
private Location mLocation;
static class ViewHolder {
TextView text;
ImageView image;
TextView distanceText;
}
public LocationsAdapter(Activity context, List<Word> locations, Location location) {
super(context, 0, locations);
mLocation = location;
mContext = context;
mInflater = LayoutInflater.from(context);
}
public void setCurrentLocation(Location lastLocation)
{
mLocation = lastLocation;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
Word currentWord = getItem(position);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item, parent, false);
viewHolder = new ViewHolder();
viewHolder.text = (TextView) convertView.findViewById(R.id.name_text_view);
viewHolder.image = (ImageView) convertView.findViewById(R.id.icon_image_view);
viewHolder.distanceText = (TextView) convertView.findViewById(R.id.distance_text_view);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.text.setText(currentWord.getName());
currentWord.updateDistance(mLocation);
viewHolder.distanceText.setText(currentWord.getFormattedDistance());
if (currentWord.hasImage())
{
viewHolder.image.setImageResource(currentWord.getImageResourceId());
viewHolder.image.setVisibility(View.VISIBLE);
} else {
// Otherwise hide the ImageView (set visibility to GONE)
viewHolder.image.setVisibility(View.GONE);
}
return convertView;
}
}
Locations Activity.
public class Locations extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
private static final int PERMISSION_REQUEST_ACCESS_FINE_LOCATION = 100;
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
private static final String LOG_TAG = Locations.class.getName();
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private String mFormattedDistanceString;
Location mLocation = new Location(LocationManager.NETWORK_PROVIDER);
private ListView mListView;
public List<Word> locations = new ArrayList<>();
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[],
int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_ACCESS_FINE_LOCATION: {
mGoogleApiClient.connect();
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.word_list);
mListView = (ListView) findViewById(R.id.list);
if (ContextCompat.checkSelfPermission(this,
ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
ACCESS_FINE_LOCATION)) {
} else {
ActivityCompat.requestPermissions(this,
new String[]{ACCESS_FINE_LOCATION},
PERMISSION_REQUEST_ACCESS_FINE_LOCATION);
}
}
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(10 * 1000) // 10 seconds, in milliseconds
.setFastestInterval(1 * 1000); // 1 second, in milliseconds
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mFormattedDistanceString = new String();
locations.add(new Word("Bristol", R.drawable.bristol,
41.670374, -71.276565, mFormattedDistanceString));
locations.add(new Word("Warren", R.drawable.warren,
41.729085, -71.282283, mFormattedDistanceString));
locations.add(new Word("Newport", R.drawable.newport_breakers,
41.486677, -71.315144, mFormattedDistanceString));
locations.add(new Word("Jamestown", R.drawable.jamestown,
41.496313, -71.368435, mFormattedDistanceString));
locations.add(new Word("Beavertail", R.drawable.beavertail,
41.458054, -71.395744, mFormattedDistanceString));
locations.add(new Word("Providence", R.drawable.providence,
41.830279, -71.414955, mFormattedDistanceString));
locations.add(new Word("Roger Williams Park", R.drawable.roger_williams_park,
41.788673, -71.414179, mFormattedDistanceString));
locations.add(new Word("Colt State Park", R.drawable.colt_state_park,
41.677248, -71.298871, mFormattedDistanceString));
ViewCompat.setNestedScrollingEnabled(mListView, true);
mListView.setAdapter(new LocationsAdapter(this, locations, mLocation));
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
if (position == 0) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:41.670374, -71.276565?z=15"));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
} else if (position == 1) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:41.729085, -71.282283?z=15"));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
} else if (position == 2) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:41.486677, -71.315144?z=13"));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
} else if (position == 3) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:41.496313, -71.368435?z=14"));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
} else if (position == 4) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:41.458054, -71.395744?z=14"));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
} else if (position == 5) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:41.830279, -71.414955?z=14"));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
} else if (position == 6) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:41.788673, -71.414179?z=16"));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
} else if (position == 7) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:41.677248, -71.298871?z=14"));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
}
});
}
#Override
protected void onStart() {
// If the app already has the permission to access the user's location at high accuracy
// (fine location), then connect to the GoogleApiClient.
if (ContextCompat.checkSelfPermission(this,
ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mGoogleApiClient.connect();
}
super.onStart();
}
#Override
protected void onResume() {
if (ContextCompat.checkSelfPermission(this,
ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mGoogleApiClient.connect();
}
super.onResume();
}
#Override
protected void onPause() {
super.onPause();
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient,
this);
mGoogleApiClient.disconnect();
}
}
protected void onStop() {
// If the user has stopped the app, disconnect from the GoogleApiClient.
mGoogleApiClient.disconnect();
super.onStop();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.i(LOG_TAG, "Location services connected.");
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mLocation == null) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
} else {
handleNewLocation(mLocation);
}
}
#Override
public void onConnectionSuspended(int i) {
Log.i(LOG_TAG, "Location services suspended. Please reconnect.");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(this,
CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
} else {
Log.i(LOG_TAG, "Location services connection failed with code " +
connectionResult.getErrorCode());
}
}
#Override
public void onLocationChanged(Location location) {
LocationsAdapter adapter = (LocationsAdapter) mListView.getAdapter();
adapter.setCurrentLocation(location);
adapter.notifyDataSetChanged();
}
private void handleNewLocation(Location location) {
Log.d(LOG_TAG, location.toString());
}
}
try this:
when the onLocationChanged is called, pass the Location to the LocationsAdapter (create the method setCurrentLocation).
call (LocationsAdapter)(listView.getAdapter()).notifyDataSetChanged();
(listView has to become a class field)
in the getView of your adapter calculate the distance and set the text to the textView.
In order to optimize the distance calculation you can store the value in the model, but remember to store the Location object as well.
In this way you can check, in the future calls, if the Location object has changed. If the Location object changes you need to recalculate the distance, otherwise you can show the last calculated distance.
UPDATE
Remove private String mFormattedDistanceString; from LocationsAdapter. You don't need this, and remove it from the constructor as well.
In your LocationsAdapter you have mLocation, but you never assign it. Add this method to LocationsAdapter to assign mLocation when it changes in your activity.
public void setCurrentLocation(Location lastLocation){ mLocation = lastLocation}
Make listView a field of Locations activity and change onLocationChanged in this way:
public void onLocationChanged(Location location) {
LocationsAdapter adapter = (LocationsAdapter)listView.getAdapter();
adapter.setCurrentLocation(location);
adapter.notifyDataSetChanged();
}
create this method in your Word class:
Location currentLocation;
public void updateDistance(Location location){
if(location.equals(currentLocation)) return;
//calculate the distance and create the distance string, and set it
//as a class field (you can call it mFormattedDistanceString)
currentLocation = location;
}
In the getView of the adapter, call updateDistance, and than set the TextView text using mFormattedDistanceString of Word