Android : Hello, Views > Google Map View Tuorial - java

I'm trying to complete the Android MapView tutorial # www.developer.android.com/resources/tutorials/views/hello-mapview.html
I think I've done the entire thing correctly but I'm getting an error message in Eclipse. I'm sure why. The problematic line of code is
private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
I'm relatively new to Java but I've gone through the forums of different things and I really have no idea on this one. I've [attached][2] a screen shot of the development environment - hopefully it wont be anything too obvious or hard to fix either!
http://www.limedomains.com/files/download/34780?dirname=&file_name=hellogooglemaps.jpg
Cheers
Tom :)
** As requested heres the source code and the screenshot link is updated to something that works**
package com.example.hellogooglemaps;
import java.util.ArrayList;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.drawable.Drawable;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;
private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
public class HelloItemizedOverlay extends ItemizedOverlay{
public HelloItemizedOverlay(Drawable defaultMarker) {
super(boundCenterBottom(defaultMarker));
}
#Override
protected OverlayItem createItem(int i) {
return mOverlays.get(i);
}
public void addOverlay(OverlayItem overlay) {
mOverlays.add(overlay);
populate();
}
#Override
public int size() {
return mOverlays.size();
}
public HelloItemizedOverlay(Drawable defaultMarker, Context context) {
super(defaultMarker);
mContext = context;
}
#Override
protected boolean onTap(int index) {
OverlayItem item = mOverlays.get(index);
AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
dialog.setTitle(item.getTitle());
dialog.setMessage(item.getSnippet());
dialog.show();
return true;
}
}

You need to declare the ArrayList inside the class, not outside, like this:
public class HelloItemizedOverlay extends ItemizedOverlay {
private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
}

Your screenshot is impossible to read.. please copy/paste what the logcat says...
For my personnal use, i use this code: List mapOverlays;

Related

At what part of the lifecycle should you initialize objects in a fragment used by a service?

I'm working on an Android app so I can learn mobile dev and I'm stuck with this problem.
Basically in my SampleFragment class I have an adapter called mAdapter and when my TestService gets my data objects and updates my dataObjects arrayList and notifies the adapter that the data has changed the adapter isn't initialized and is null at the time. Is it a thread issue or is it associated with the fragment lifecycle?
SampleFragment.java
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
public class SampleFragment extends Fragment {
private static final int SEND_DELAY = 1500;
private String userName, sEventId;
private EditText etMessage;
private ImageButton btSend;
private Context applicationContext;
private View view;
private Handler handler = new Handler();
private ArrayList<Message> dataObjects = new ArrayList<>();
private MessageListAdapter mAdapter;
private Runnable initMessageAdapter = new Runnable() {
#Override
public void run() {
initMessageAdapter();
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String eventName = CurrentActiveEvent.getInstance().getEventName();
Activity activity = getActivity();
activity.setTitle(eventName);
mAdapter = new MessageListAdapter(context, userName, dataObjects);
CurrentActiveUser currentUser = CurrentActiveUser.getInstance();
userName = currentUser.getUsername();
Intent intent = new Intent(activity, TestService.class);
activity.startService(intent);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_messaging, container, false);
applicationContext = getActivity();
sEventId = CurrentActiveEvent.getInstance().getEventID();
btSend = (ImageButton) view.findViewById(R.id.btSend);
handler.post(initMessageAdapter);
btSend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
handler.post(new Runnable() {
#Override
public void run() {
saveMessage(body);
}
});
}
});
return view;
}
// Setup message field and posting
private void initMessageAdapter() {
etMessage = (EditText) view.findViewById(R.id.etMessage);
ListView lvChat = (ListView) view.findViewById(R.id.lvChat);
lvChat.setAdapter(mAdapter);
}
public void updatedataObjects(List<objs> newdataObjects){
this.dataObjects.clear();
this.dataObjects.addAll(newdataObjects);
mAdapter.notifyDataSetChanged();
}
}
TestService.java
import android.app.IntentService;
import android.content.Intent;
import java.util.Collections;
import java.util.List;
public class TestService extends IntentService {
private static final int MAX_RESULTS = 50;
private static final String CLASS_NAME = TestService.class.getSimpleName();
private final String sEventId = CurrentActiveEvent.getInstance().getEventID();
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*/
public TestService() {
super(CLASS_NAME);
}
#Override
#SuppressWarnings("unchecked")
protected void onHandleIntent(Intent intent) {
if (NetworkState.isConnected(getApplicationContext())) {
Query query = new Query(Data.class);
query.whereEqualTo(Events.ID, sEventId);
query.orderByDESC(Data.CREATED_AT);
query.setLimit(MAX_RESULTS);
List objs = queryDB(query, Data.class.getSimpleName());
if (objs != null) {
Collections.reverse(objs);
new SampleFragment().updateMessages(objs);
}
}
}
}
Your problem comes from this line:
new SampleFragment().updateMessages(objs);
You are creating a new instance of your fragment inside your service. Since you are not attaching the fragment anywhere, it's lifecycle is not started and the onCreate() method is never called, which results in the NullPointerException.
IntentServices are great for executing tasks on a background thread, but they are components, that are meant to be separated from the UI - related components, like Activities and Fragments. You should never have direct communication between an IntentService and a Fragment or Activity. If you need to return a result from your IntentService, you should consider using the LocalBroadcastManager. It will fire an intent, containing the result, and you can register receivers to intercept it.
There are also other options, like Bound Services - they are created to provide an interface for their clients, and you can use this to return your result. But bear in mind, that, unlike IntentService they don't work in a background thread by default.
Since you are trying to work with a database, I recommend you take a look and the ContentProvider and ContentResolver classes. They are the recommended way of working with DBs in Android and come with loads of neat stuff.

Android: ArrayList getting nullpointer on second call

So I'm working on an android app and currently having an issue with some code. It's quite simple actually... I fill an arraylist, also check if it gets filled (it does) and then request that arraylist later on. But somehow when I request the arraylist later on it's empty and I'm not making a new instance or anything... Or I'm just plain missing it.
So here's the code where it's going wrong...
package net.serellyn.c2m.cal2movement;
import android.app.Activity;
import android.content.SharedPreferences;
import android.graphics.Typeface;
import android.os.Bundle;
import android.util.Log;
import android.widget.AutoCompleteTextView;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import java.util.ArrayList;
public class MainActivity extends Activity implements TaskListener{
private SharedPreferences sharedPreferences;
private SharedPreferences.Editor editor;
private TaskListener listener;
private Exercises exercises;
//...
private ArrayList<String> exerciseArrayList;
//...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setLayout();
sharedPreferences = getSharedPreferences("PreferenceValues", MODE_PRIVATE);
editor = sharedPreferences.edit();
listener = this;
exercises = new Exercises();
new sc_getExercises(listener).execute("http://www.serellyn.net/c2e/app_backend/exercises.php");
}
#Override
public void taskComplete(ArrayList e) {
exercises.setExercises(e);
for(Exercise a : exercises.getExercises()) {
Log.i("DebugInfo", a.getExercise());
}
setLayout();
}
private void setLayout() {
Typeface tf_dinBlack = Typeface.createFromAsset(getAssets(), "DIN_Black.ttf");
Typeface tf_dinMedium = Typeface.createFromAsset(getAssets(), "DIN_Medium.ttf");
Typeface tf_dinLight = Typeface.createFromAsset(getAssets(), "DIN_Light.ttf");
tv_appName = (TextView)findViewById(R.id.tv_appName);
tv_appTagline = (TextView)findViewById(R.id.tv_appTagline);
tv_hourNumber = (TextView)findViewById(R.id.tv_hoursNumber);
tv_hourText = (TextView)findViewById(R.id.tv_hoursText);
tv_minutesNumber = (TextView)findViewById(R.id.tv_minutesNumber);
tv_minutesText = (TextView)findViewById(R.id.tv_minutesText);
tv_yourActivity = (TextView)findViewById(R.id.tv_yourActivity);
s_activities = (Spinner)findViewById(R.id.s_activities);
tv_appName.setTypeface(tf_dinBlack);
tv_appTagline.setTypeface(tf_dinMedium);
tv_hourNumber.setTypeface(tf_dinLight);
tv_hourText.setTypeface(tf_dinLight);
tv_minutesNumber.setTypeface(tf_dinLight);
tv_minutesText.setTypeface(tf_dinLight);
tv_yourActivity.setTypeface(tf_dinLight);
setActivityValues();
}
private void setActivityValues() {
for(Exercise a : exercises.getExercises()) {
Log.i("DebugInfo", a.getExercise());
}
}
}
sc_getExercises is an AsyncTask which works as expected, and fills the 'exercises' array in 'TaskComplete' function. I loop the 'exercises'array to see if it's filled, and it is filled as it should be.
However, when I do the same in the 'setActivityValues' later on, I get a nullpointerexception.
So that's kinda... weird in my eyes. What am I doing wrong?
Here's the exercises class.
package net.serellyn.c2m.cal2movement;
import java.util.ArrayList;
public class Exercises {
private ArrayList<Exercise> exercises;
public Exercises(){
exercises = new ArrayList<Exercise>();
}
public ArrayList<Exercise> getExercises() {
return exercises;
}
public void setExercises(ArrayList<Exercise> exercises) {
this.exercises = exercises;
}
}
I hope someone can spot the problem. Thanks in advance.
This is your method:
private void setActivityValues() {
for(Exercise a : exercises.getExercises()) {
Log.i("DebugInfo", a.getExercise());
}
}
Either exercises is null (it is initialized in onCreate), or exercises in your Exercises class instance is null (gets a value at taskComplete, which invokes setExercises), or one of the exercises in the loop is null, or the getExercise has a NullPointerException bug.
It says nullPointerException, check your json parser it fufills your list properly or not.

Phonegap: calling a java function from Javascript

I want to call one of my Java functions in Javascript and get its result. In order to do that I followed this tutorial and this question. I followed them step by step and I still get this error
Cannot call method 'showKeyBoard' of undefined
Here is my java class:
package keyboard;
import org.apache.cordova.DroidGap;
import android.content.Context;
import android.view.inputmethod.InputMethodManager;
import android.webkit.WebView;
public class KeyBoard {
private WebView mAppView;
private DroidGap mGap;
public KeyBoard(DroidGap gap, WebView view) {
mAppView = view;
mGap = gap;
}
public void showKeyBoard() {
InputMethodManager mgr = (InputMethodManager) mGap.getSystemService(Context.INPUT_METHOD_SERVICE);
// only will trigger it if no physical keyboard is open
mgr.showSoftInput(mAppView, InputMethodManager.SHOW_IMPLICIT);
((InputMethodManager) mGap.getSystemService(Context.INPUT_METHOD_SERVICE)).showSoftInput(mAppView, 0);
}
public void hideKeyBoard() {
InputMethodManager mgr = (InputMethodManager) mGap.getSystemService(Context.INPUT_METHOD_SERVICE);
mgr.hideSoftInputFromWindow(mAppView.getWindowToken(), 0);
}
}
Here is my Main class:
package com.example.helloworld;
import keyboard.KeyBoard;
import android.os.Bundle;
import org.apache.cordova.*;
import android.view.Menu;
import QR.*;
public class MainActivity extends DroidGap {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.init();
KeyBoard keyboard = new KeyBoard(this, appView);
appView.addJavascriptInterface(keyboard, "KeyBoard");
super.loadUrl("file:///android_asset/www/index.html");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
And I call it in Javascript like this:
(function(){
window.KeyBoard.showKeyBoard();
})();
Is there anything that I haven't done or am missing? As I said I get this error:
Cannot call method 'showKeyBoard' of undefined
I recommend that you write a PhoneGap plugin instead of trying to roll your own method. We've already gone through all the pain points of the JavaScript to Java communication. Use what we've already written and you won't run into the Android bugs that we've already smoothed over in the past 3 years.
http://docs.phonegap.com/en/2.1.0/guide_plugin-development_index.md.html#Plugin%20Development%20Guide
In phonegap i recommend you using a custom plugin do this
but still if you want to make a direct call to Java see this example to get a general idea
public class MainActivity extends DroidGap {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setIntegerProperty("loadUrlTimeoutValue", 70000);
super.loadUrl("file:///android_asset/www/index.html");
super.appView.addJavascriptInterface(new Bridge(), "b");
}
}
class Bridge {
#JavascriptInterface
public String a()
{
Log.i("Bridge","This is from js");
return "This is a message";
}
}
in javascript
setTimeout(function(){
alert(b.a());
}, 1000);
#JavascriptInterface annotation is required in you code to make this work .
package keyboard;
import org.apache.cordova.DroidGap;
import android.content.Context;
import android.view.inputmethod.InputMethodManager;
import android.webkit.WebView;
public class KeyBoard {
private WebView mAppView;
private DroidGap mGap;
public KeyBoard(DroidGap gap, WebView view) {
mAppView = view;
mGap = gap;
}
/*make it visible in bridge*/
#JavascriptInterface
public void showKeyBoard() {
InputMethodManager mgr = (InputMethodManager) mGap.getSystemService(Context.INPUT_METHOD_SERVICE);
// only will trigger it if no physical keyboard is open
mgr.showSoftInput(mAppView, InputMethodManager.SHOW_IMPLICIT);
((InputMethodManager) mGap.getSystemService(Context.INPUT_METHOD_SERVICE)).showSoftInput(mAppView, 0);
}
/*make it visible in bridge*/
#JavascriptInterface
public void hideKeyBoard() {
InputMethodManager mgr = (InputMethodManager) mGap.getSystemService(Context.INPUT_METHOD_SERVICE);
mgr.hideSoftInputFromWindow(mAppView.getWindowToken(), 0);
}
}
And in Javascript call it like this:
(function(){
KeyBoard.showKeyBoard();
})();
I'm struggling with JavascriptInterface too. The reason why you cant call showKeyboard is IMHO you should call window.showKeyBoard() instead of window.Keyboard.showKeyBoard().

Is it possible to display an overlay item on Google Maps when a marker is tapped?

I already made a simple android application, which I also have integrated Google Maps in it..
It is also capable of connecting to MySQL (localhost) to display my desired places using longitude and latitude values..
My question is, is it possible to make another overlay item above Google Maps when a marker is clicked (just like what happens in foursquare)?
To be specific, i want to display a text that contains the name of a place.
Heres my class of displaying the overlay items.
I made an onTap method, but it display a dialog box, I want to display a simple text box that shows the name of the place.
package finddroid.map;
import java.util.ArrayList;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.text.TextPaint;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapView;
import com.google.android.maps.OverlayItem;
public class CustomItemizedOverlay extends ItemizedOverlay<OverlayItem>
{
private int markerHeight;
private ArrayList<OverlayItem> mapOverlays = new ArrayList<OverlayItem>();
private Context context;
public CustomItemizedOverlay(Drawable defaultMarker)
{
super(boundCenterBottom(defaultMarker));
markerHeight = ((BitmapDrawable) defaultMarker).getBitmap().getHeight();
populate();
}
public CustomItemizedOverlay(Drawable defaultMarker, Context context)
{
this(defaultMarker);
this.context = context;
}
#Override
protected OverlayItem createItem(int i)
{
return mapOverlays.get(i);
}
#Override
public int size()
{
return mapOverlays.size();
}
#Override
//Event when a place is tapped
protected boolean onTap(int index)
{
OverlayItem item = mapOverlays.get(index);
AlertDialog.Builder dialog = new AlertDialog.Builder(context);
dialog.setTitle(item.getTitle());
dialog.setMessage(item.getSnippet());
dialog.show();
return true;
}
public void addOverlay(OverlayItem overlay)
{
mapOverlays.add(overlay);
this.populate();
}
}
Have a look at this project - balloon itemized overlay. It is using own class extending FrameLayout to show balloons.
So if you want to modify your code put this into your onTap method to display a TextView above taped item
TextView text = new TextView(context);
text.setText(item.getTitle());
MapView.LayoutParams params = new MapView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT, item.getPoint(), MapView.LayoutParams.BOTTOM_CENTER);
params.mode = MapView.LayoutParams.MODE_MAP;
mMapView.addView(text, params);
I think this code is simple and easy to understand and you can improve it accordingly to your needs. To make it work you have to pass instance of MapView to constructor of your overlay and save it to private variable mMapView.
private MapVeiw mMapView;
public CustomItemizedOverlay(Drawable defaultMarker, Context context, MapView mapView) {
this(defaultMarker);
this.context = context;
this.mMapView = mapView;
}
And don't forget to add MapView as one of parameters when you call new CustomItemizedOverlay().

Overlays not working in Google MapView Tutorial Android

Got some errors following the tutorial for MapView when i was going to integrate overlays.
TravelBuddy.java
package com.jappapps.android.travelbuddy;
import java.util.List;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
public class TravelBuddy extends MapActivity {
List<Overlay> mapOverlays;
Drawable drawable;
Overlays itemizedOverlay;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main); // changed to lowercase
MapView mapView = (MapView) findViewById(R.id.mapview); // match id in main.xml
mapView.setBuiltInZoomControls(true);
mapOverlays = mapView.getOverlays();
drawable = this.getResources().getDrawable(R.drawable.androidmarker);
itemizedOverlay = new Overlays(drawable);
}
#Override
protected boolean isRouteDisplayed() {
return false;
}
}
Overlays.java
package com.jappapps.android.travelbuddy;
import java.util.ArrayList;
import android.graphics.drawable.Drawable;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.OverlayItem;
public class Overlays extends ItemizedOverlay {
public Overlays(Drawable arg0) {
super(arg0);
Object overlayitem;
ItemizedOverlay.addOverlay(overlayitem);
Object itemizedoverlay;
ArrayList<OverlayItem> mapOverlays;
mapoverlays.add(itemizedOverlay);
}
private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
super(boundCenterBottom(defaultMarker));
public void addOverlay(OverlayItem overlay) {
mOverlays.add(overlay);
populate();}
#Override
protected OverlayItem createItem(int i) {
return mOverlays.get(i);
}
#Override
public int size() {
return 0;
}
}
Sorry if i look like a complete newbie, but i am trying to learn and i got an awesome app idea which needs mapview, webview, overlays and tabs.
#Override
public int size() {
return mOverlays.size();
}
I was using androidmarker.png from the "official" google mapview tutorial and was stuck with the overlays not showing up. I tried several other people's working examples and still same problem. I switched out androidmarker.png with a smaller png and it worked. So the code was fine, but something to do with the marker asset.

Categories