I'm making my first Android app, which on initial load determines the user's current location and goes to it in a MapView. I've delegated initializing the MapView/MapController to an AsyncTask to make the app feel more responsive, but I'm getting a RuntimeException in my doInBackground method. Here's the code for my initial Activity and the AsyncTask which I'm using.
public class MainActivity extends MapActivity {
Location latestLocation, targetLocation;
MapController mapController;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Get a reference to the MapView
MapView myMapView = (MapView)findViewById(R.id.myMapView);
MapLoader map = new MapLoader();
try {
map.execute(myMapView).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
mapController = myMapView.getController();
//code which determines current location and animates to it in the Mapview.
}
}
And here's the code for my AsyncTask.
public class MapLoader extends AsyncTask<MapView ,Void, Void>{
MapController mapController;
MapView mapView;
#Override
protected Void doInBackground(MapView... params) {
// Get the Map View’s controller
mapController = params[0].getController();
// Configure the map display options
mapView.setSatellite(true);
mapView.displayZoomControls(false);
// Zoom in
mapController.setZoom(19);
return null;
}
}
Should I put the code for determining the location inside the AsyncTask as well? Currently, my app is pretty slow on loading, as well as being quite unresponsive even after everything's initialized.
Related
Clipboard data returns null when MainActivity is not active in top view activity when I click the button in Android java
I read this restriction about android10 and higher, but my activity is not a background service.
I need to get clipboard data when I click on the button located in the top view activity like the Google Translate application.
In my case, the clipboard returns null when MainActivity is not active.
https://developer.android.com/about/versions/10/privacy/changes#clipboard-data
public class MainActivity extends BridgeActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initializes the Bridge
this.init(savedInstanceState, new ArrayList<Class<? extends Plugin>>() {{
// Additional plugins you've installed go here
// Ex: add(TotallyAwesomePlugin.class);
}});
startActivity(new Intent(MainActivity.this, FloatingWindow.class));
}
}
public class FloatingWindow extends Activity {
// ... additional code ....
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
floatingButtonDefinedInClass.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
self.getClipboardText();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
public void getClipboardText() throws IOException {
try {
ClipboardManager myClipboard = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE);
ClipData clipData = myClipboard.getPrimaryClip();
if(clipData != null) {
text = (String) clipData.getItemAt(0).getText();
System.out.println(text); // returns null when mainactivity is not active
}
} catch (Exception e) {
e.printStackTrace();
}
}
// ... additional code ....
}
what does "mainactivity is not active" mean? you are getting access to ClipboardManager inside OnClickListener attached to Button, which is a View and need Context, so there must be alive Activity, which keeps this Button on the screen for clicking purpose...
btw. maybe you are you checking on Android 10 or above? it looks like according to docs
Limited access to clipboard data
Unless your app is the default input method editor (IME) or is the app
that currently has focus, your app cannot access clipboard data on
Android 10 or higher.
privacy/security reasons, thats how it will be working now
I am new to android developing, as a part of my learning, I am making a multilingual news reader application, where the application is fetching rss feeds from google news and parses.
for this, I am using tabbed view for showing multiple languages, user can swipe through different language. application contains Hindi,Malayalam,English, and Tamil tabs, all lists particular news items.
each language view page is separate fragment. and there are totally four fragments is there in the application and main activity holds all these.
for all these fragments I have one AsyncTask extended class, which loads and parses news from the server.and returns an array list on its doInBackground method, but the problem with this is when I swiping from one tab to another it works very slow. I am pasting my code down. I think my AsyncTask usage is not correct, because I am showing a progress bar in onPreExecute method, but it also not showing in proper.
please anyone look on to my code and help me to correct
EnglishNewsFragment.java
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
ArrayList<HashMap<String, String>> newsWrapper;
context = getActivity();
View rootView = inflater.inflate(R.layout.english_news_fragment, container, false);
NewsLoader newsLoader = new NewsLoader(context, language);
newsLoader.execute();
try {
newsWrapper = newsLoader.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
showNews(newsWrapper);
}
return rootView;
}
NewsLoader
public class NewsLoader extends AsyncTask{
public NewsLoader(Context context, String language) {
this.context = context;
this.language = language;
}
#Override
protected void onPreExecute() {
startDialogue();
initAll(language);
}
#Override
protected ArrayList<HashMap<String, String>> doInBackground(Void... params) {
getNews();
news = processXML();
} catch (Exception e) {
e.printStackTrace();
}
return news;
}
#Override
protected void onPostExecute(ArrayList<HashMap<String, String>> aVoid) {
super.onPostExecute(aVoid);
stopDialogue();
}
}
UPDATE
AsyncTask.get() blocks the UI. so that I have to implement a call back interface, can anyone help me to do it I have read a little from here but how will be its calling and how do I pass the result to MainActivity ?
Screen shot
The Asynctask.get() method blocks the UI until doInBackground() finished. You can use instead the onPostExecute() to deliver result back on the UI.
The slowdown or bottleneck in the UI is probably coming from onPreExecute() or onPostExecute(). Add code like Log.d() and print the timing difference to see which code causes the bottleneck. For example, code initAll(language) may be moved to the non-UI thread of doInBackground(). Perhaps that method is slow. Basically with onPreExecute and onPostExecute, be quick in whatever needs to be done.
I think you don't need to call super.onPreExecute() or super.onPostExecute(aVoid). Google's sample does not do so or suggest to # AsyncTask. Maybe that causes the bottleneck also.
Hope that helps...
I have got the answer.
I have made a callback interface for passing the result to Fragment
public interface CallBackReciever {
public void recieveData(ArrayList<HashMap<String,String>> result);
}
and implemented this interface with fragment.
then passed a context of this interface to AsyncTask. and in its onPostExecute() method invoked recieveData() method
Fragment
#Override
public void recieveData(ArrayList<HashMap<String, String>> result) {
newsWrapper = result;
showNewsOnUI();
}
AsyncTask
public class NewsLoader extends AsyncTask<Void, Void, ArrayList<HashMap<String, String>>>{
public NewsLoader(CallBackReciever callBackReciever) {
this.callBackReciever = callBackReciever;
}
#Override
protected void onPreExecute() {
startDialogue();
}
#Override
protected ArrayList<HashMap<String, String>> doInBackground(Void... params) {
initAll(language);
result = processNews()
return result;
}
#Override
protected void onPostExecute(ArrayList<HashMap<String, String>> result) {
stopDialogue();
callBackReciever.recieveData(result);
}
}
I am having a slight problem in Android Async Task. In my MainActivity, I am calling GetEventAsyncTask which will execute the method inside called retrieveEventJSON:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
context = this;
public void onSingleTap(float x, float y) {
final Point point = mMapView.toMapPoint(x, y);
eventModel.setEventX(String.valueOf(point.getX()));
eventModel.setEventY(String.valueOf(point.getY()));
new MyAsyncTask(new MyAsyncTask.OnRoutineFinished() {
public void onFinish() {
CreateEvent.createEventDialog(context, point.getX(),
point.getY(), eventAddress); //this will be called after the task finishes
}
}).execute(eventModel);
}
});
new GetEventAsyncTask().execute();
}
In my GetEventAsyncTask, basically I am just retrieving the data returned from JSON and save them into an array:
public class GetEventAsyncTask extends AsyncTask<Event, Integer, Double> {
EventController eventCtrl = new EventController();
String eventAddress;
Event eventModel = new Event();
public interface OnRoutineFinished{ //interface
void onFinish();
}
private OnRoutineFinished mCallbacks;
public GetEventAsyncTask(OnRoutineFinished callback){ //constructor with interface
mCallbacks = callback;
}
public GetEventAsyncTask(){} //empty constructor to maintain compatibility
#Override
protected Double doInBackground(Event... params) {
try {
eventAddress = eventCtrl.getStreetAddressFromGeometry(eventModel.getEventX(), eventModel.getEventY());
eventCtrl.retrieveEventJSON();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(Double result) {
if(mCallbacks !=null)
mCallbacks.onFinish(); //call interface on finish
}
protected void onProgressUpdate(Integer... progress) {
}
}
Then when the navigation drawer item onselected, I am calling the plotting marker on map method which takes in the array I saved just now:
case 0:
eventCtrl.plotEventOnMap(context);
break;
I tried to print out the data retrieved in retrieveJSON and it did printed out. But somehow, when I tried to plot onto the map, it does not shows anything. I wonder which part that I overlapped or reinitialize some Object?
The strange thing is if I put getEventAsyncTask under MainActivity, it did run and retrieved the data. But however, if I shifted the getEventAsyncTask out as an individual class, it stopped working. I wonder why is it so?
Thanks in advance.
I am developing an Android app which has 2 classes. Game, which extends Activity, and GameView, which extends View.
When the game is loaded, it sets the content view to GameView, which is just a drawing class that uses a canvas to display the game.
I am trying to create a ProgressDialog in the Game class which will show a spinner after a certain action has been done, as this takes a long time to complete. So far I have the following:
setContentView(R.layout.activity_game);
ProgressDialog pd = new ProgressDialog(this);
pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pd.setMessage("Calculating hint");
pd.show();
AsyncTask<String[][], Void, SudokuSquare> nextSquareThread = new GetNextSquare().execute(puzzleNumbers);
next = nextSquareThread.get();
pd.dismiss();
setContentView(gameView);
And my AsyncTask class looks like this:
private class GetNextSquare extends AsyncTask<String[][], Void, SudokuSquare> {
private ProgressDialog dialog = new ProgressDialog(Game.this);
#Override
protected void onPreExecute() {
this.dialog.setMessage("Finding next number");
this.dialog.show();
}
#Override
protected SudokuSquare doInBackground(final String[][]... args) {
try {
SudokuAdvancedSolver solver = new SudokuSolver(args[0]);
return solver.getOneValue();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
#Override
protected void onPostExecute(final SudokuSquare result) {
if (dialog.isShowing()) {
dialog.dismiss();
}
}
}
At the moment I have two ProgressDialogs, one inside the AsyncTask and one outside. Which one is correct? Also, the spinner is not being displayed at all. What am I overlooking which is causing this to be the case?
only the one outside is correct. because you are trying the main thread (the UI thread of your activity) by another thread (your asychronic task). you should use a handler in place of this :
1/ you show the progress bar
2/ you load the game in a thread
3/ when the game is loaded you send a message to the handler which will stop the progress bar.
See this exemple . you should dismiss your dialog in the handler (when the handler receives the message from the thread) .
If you don't implement a listener on Asynctask, i could suggest you to dismiss your progress dialog onPostExecute
private ProgressDialog dialog;
public void setProgressDialog(ProgressDialog dialog){
this.dialog = dialog;
}
#Override
protected void onPostExecute(final SudokuSquare result) {
dialog.dismiss();
}
and before you executing Asynctask add this code
nextSquareThread.setProgressDialog(pd);
My application crashes after click the button, but the code executes properly.
public void makeLead(View v) throws Exception {
try {
RegisterTimer rt = new RegisterTimer();
rt.ma = this;
rt.execute(null);
} catch (Exception e) {
e.printStackTrace();
}
}
public void log(String msg)
{
final TextView tv = (TextView)findViewById(R.id.editText);
tv.append(msg);
}
private class RegisterTimer extends AsyncTask {
public MainActivity ma;
#Override
protected Object doInBackground(Object[] objects) {
ma.log("ausd");
return null;
}
}
makeLead is onClick event. Method ma.log generates an error but works properly (msg added to textEdit). When I delete ma.log, app doesn't crash. I have no logs in my AndroidStudio so I can't see error message. What's wrong ?
You can not touch the Views in a non UI Thread.
and you are appending text to TextView in a background Thread which is not allowed.
and I hope there is no problem with the initialization of MainActivity inside RegisterTimer as you are not creating the instance of Activity manually. You are in correct way with the initialization rt.ma = this. and why do you need AsyncTask just for changing the text of a TextView?
You cannot update ui from a doInbackground. Initializing ma is not required
Make AsyncTask an inner class of Activity and update ui in onPostExecute
or use interface as a callback to the activity
Edit:
To make it clear
Make asynctaks an inner class of activity. Declare textview as a instance variable. Return result in doInbackground
In Activity
TextView tv;
#Override
public void onCreate(Bundle savedInstancestate)
super.onCreate(savedInstancestate);
setContentView(R.layout.yourlayout);
tv = (TextView)findViewById(R.id.editText);
Then
#Override
protected String doInBackground(Void objects) {
// some background computation
return "ausd";
}
In onpostExecute
#Override
protected void onPostExecute(String result)
{
super.onPostExecute();
tv.append(result);
}
Also you need
private class RegisterTimer extends AsyncTask<Void,Void,String> { // args missing
As described by #Raghunandan you have not initialized ma.
next is you cannot access view in background thread.
if your thread class is inside of MainActivity class then you can use
runOnUiThread(new Runnable() {
#Override
public void run() {
ma.log("ausd");
}
});
inside doInBackground method to update view.
Your method log is public, you don't need to make an object of the MainActivity class to access it, instead you can call it directly. Also you need to add some template after your ASYNC task, if you want to pass some input to your background process, you are using ASYNC task in a wrong way.