How to be sure that all views got created - android

I'm working with AsyncTask and in one of the background threads I've created, I have to know the size of a given View.
But sometimes this view is yet to be created.
So the question is: at which part of Activity's life cycle I can be sure that all the views are already in place and with the dimensions defined?
PS: My code is inside a Fragment and I already tried onResume() method.

custom the view which you want to get size:
public class SizeFetchableView extends YourView{
//constructors...
private SizeFetchListener mSizeFetchListener;
public void setSizeFetchListener(SizeFetchListener l){
mSizeFetchListener = l;
}
public void onLayout(boolean isChanged,int l,int t,int r,int b){
super.onLayout(l,t,r,b);
if(mSizeFetchListener!=null){
mSizeFetchListener.onFetchSize(this,isChanged,getWith(),getHeight());
}
}
public interface SizeFetchListener{
public void onFetchSize(View view,boolean isChanged,int w,int h);
}
}
so,you can use SizeFetchListener to get the view size in the first time,but your thread logic which depend on the size,must waiting the fetch size interface invoke.
public class Task extends Thread implements SizeFetchListener{
SizeFetchableView mSizeFetchableView;
public Task(SizeFetchableView v){
mSizeFetchableView=v;
mSizeFetchableView.setSizeFetchListner(this);
}
public void onFetchSize(View view,boolean isChanged,int w,int h){
//and this time ,you can start you thread if not,or continue you logic who waiting the size
}
}
//please forgive my bad english.Thanks

Related

Android MVP Strategy

I am migrating my apps to MVP. Have taken hints on a static presenter pattern from this konmik
This is my brief MVP strategy. Removed most of the boilerplate and MVP listeners for brevity. This strategy has helped me orientation change proof my background processes. The activity correctly recovers from a normal pause compared to pause which is finishing the activity. Also the Presenter only has application context so it does not hold onto activity context.
I am not a java expert and this is my first foray into MVP and using a static presenter has made me uncomfortable. Am I missing something? My app is working fine and has become much more responsive.
View
public class MainActivity extends Activity{
private static Presenter presenter;
protected void onResume() {
if (presenter == null)
presenter = new Presenter(this.getApplicationContext());
presenter.onSetView(this);
presenter.onResume();
}
protected void onPause() {
presenter.onSetView(null);
if(isFinishing())presenter.onPause();
}
}
Presenter
public class Presenter {
private MainActivity view;
Context context;
public Model model;
public Presenter(Context context) {
this.context = context;
model = new Model(context);
}
public void onSetView(MainActivity view) {
this.view = view;
}
public void onResume(){
model.resume();
}
public void onPause(){
model.pause();
}
}
Model
public class Model {
public Model(Context context){
this.context = context;
}
public void resume(){
//start data acquisition HandlerThreads
}
public void pause(){
//stop HandlerThreads
}
}
I would suggest two things.
Make Model, View, and Presenter into interfaces.
Your MVP-View (an Activity, Fragment, or View) should be so simple it does not need to be tested.
Your MVP-Presenter never directly interacts with the Activity/Fragment/View so it can be tested with JUnit. If you have dependencies on the Android Framework is bad for testing because you need to Mock out Android objects, use emulator, or use a Testing Framework like Roboelectric that can be really slow.
As an example of the interfaces:
interface MVPView {
void setText(String str);
}
interface MVPPresenter {
void onButtonClicked();
void onBind(MVPView view);
void onUnbind();
}
The MVPPresenter class now does not depend on the Android Framework:
class MyPresenter implements MVPPresenter{
MVPView view;
#Override void bind(MVPView view){ this.view = view; }
#Override void unbind() {this.view = null; }
#Override void onButtonClicked(){
view.setText("Button is Clicked!");
}
}
Instead of making the Presenter a static class, I would make it a Retained Fragment. Static objects need to be tracked carefully and removed for GC manually whenever they are not needed (otherwise it's considered a memory leak). By using a retain fragment, it is much easier to control the lifetime of the presenter. When the fragment that owns the retain fragment finishes, the retain fragment is also destroyed and the memory can be GC'd. See here for an example.
Activity, Fragments should have only overidden methods of View interface and other Android Activity, Fragment's methods.
View has methods like navigateToHome, setError, showProgress etc
Presenter interacts with both View and Interactor(has methods like onResume, onItemClicked etc)
Interactor has all the logics and calculations, does time intensive tasks such as db, network etc.
Interactor is android free, can be tested with jUnit.
Activity/fragment implements view, instantiate presenter.
Suggest edits to my understanding. :)
An example is always better than words, right?
https://github.com/antoniolg
You're on the right track, and you are correct to ask about static - whenever you notice that you have written that keyword, it's time to pause and reflect.
The Presenter's life should be tied directly to the Activity's/Fragment's. So if the Activity is cleaned up by GC, so should the presenter. This means that you should not hold a reference to the ApplicationContext in the presenter. It's ok to use the ApplicationContext in the Presenter, but it's important to sever this reference when the Activity is destroyed.
The Presenter should also take the View as a constructor parameter:
public class MainActivity extends Activity implements GameView{
public void onCreate(){
presenter = new GamePresenter(this);
}
}
and the presenter looks like:
public class GamePresenter {
private final GameView view;
public GamePresenter(GameView view){
this.view = view;
}
}
then you can notify the Presenter of the Activity LifeCycle Events like so:
public void onCreate(){
presenter.start();
}
public void onDestroy(){
presenter.stop();
}
or in onResume/onPause - try to keep it symmetrical.
In the end you only have 3 files:
(I'm taking some code from another explanation I gave here but the idea is the same.)
GamePresenter:
public class GamePresenter {
private final GameView view;
public GamePresenter(GameView view){
this.view = view;
NetworkController.addObserver(this);//listen for events coming from the other player for example.
}
public void start(){
applicationContext = GameApplication.getInstance();
}
public void stop(){
applicationContext = null;
}
public void onSwipeRight(){
// blah blah do some logic etc etc
view.moveRight(100);
NetworkController.userMovedRight();
}
public void onNetworkEvent(UserLeftGameEvent event){
// blah blah do some logic etc etc
view.stopGame()
}
}
I'm not sure exactly why you want the ApplicationContext instead of the Activity context, but if there's no special reason for that, then you can alter the void start() method to void start(Context context) and just use the Activity's context instead. To me this would make more sense and also rule out the need to create a singleton in your Application class.
GameView
is an interface
public interface GameView {
void stopGame();
void moveRight(int pixels);
}
GameFragment is a class that extends Fragment and implements GameView AND has a GamePresenter as a member.
public class GameFragment extends Fragment implements GameView {
private GamePresenter presenter;
#Override
public void onCreate(Bundle savedInstanceState){
presenter = new GamePresenter(this);
}
}
The key to this approach is to clearly understand the role of each file.
The Fragment is in control of anything view related (Buttons, TextView etc). It informs the presenter of user interactions.
The Presenter is the engine, it takes the information from the View (in this case it is the Fragment, but notice that this pattern lends itself well to Dependency injection? That's no coincidence. The Presenter doesn't know that the View is a Fragment - it doesn't care) and combines it with the information it is receiving from 'below' (comms, database etc) and then commands the View accordingly.
The View is simply an interface through which the Presenter communicates with the View. Notice that the methods read as commands, not as questions (eg getViewState()) and not to inform (eg onPlayerPositionUpdated()) - commands (eg movePlayerHere(int position)).

Android AsyncTask with notification

I am currently starting to develop Android applications, and I must say that it all came out very very simple and straightforward.
I have a small question about the AsyncTask. Maybe I've been doing something wrong, but here's the situation.
I have a small app that needs to load a list's content from the web.
I developed everything based on fake requests, and it all came out awesome. Then I updated the code with actual requests and got the 'Network on main thread error'. So I decided to switch to AsyncTask.
I was wondering if I could let AsyncTask just do the asynchronous work, and handle the result somewhere else (where I actually have the GUI connections and everything). I thought that in terms of readability and logic it makes more sense to have all the code that handles the interface in the Activity, but how could I let the Activity know when a task was completed?
I wrote these simple classes and interfaces (and it works) but I wanted to know from you if this is a good thing or there are better methods to do that.
So, here's the code:
public interface AsyncDelegate {
public void executionFinished(LazyLoaderWithDelegate lazyLoaderWithDelegate);
}
This is a simple interface. The purpose is to have the Activity implement this and handle the 'executionFinished' method. Something like a listener.
import android.os.AsyncTask;
public class LazyLoaderWithDelegate<Params, Progress, Result> extends AsyncTask<Params, Progress, Result>{
AsyncDelegate delegate;
Result result;
public LazyLoaderWithDelegate(AsyncDelegate delegate){
this.delegate = delegate;
}
#Override
protected Result doInBackground(Object... params) {
//This will be Overridden again from the subclasses anyway.
return null;
}
#Override
protected void onPostExecute(Result r){
this.result = r;
delegate.executionFinished(this);
}
public Result getResult(){
return result;
}
}
This class basically gives a skeleton structure to notify the delegate when the task is finished.
That's all. Here's an example of using this classes:
public class LazyVideoLoader extends LazyLoaderWithDelegate<Void, Void, List<List<Video>>>{
public LazyVideoLoader(AsyncDelegate delegate) {
super(delegate);
}
#Override
protected List<Video> doInBackground(Void ...params) {
return ServerInterface.getVideos();
}
}
public class MainActivity extends Activity implements AsyncDelegate {
private LazyVideoLoader videoLoader;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*
* Set up the lazy loaders
*/
videoLoader = new LazyVideoLoader(this);
videoLoader.execute();
}
#Override
public void executionFinished(LazyLoaderWithDelegate task) {
if(task == videoLoader){
List<Video> result = videoLoader.getResult();
//Do whatever you need...
}
}
Everything you run on onPostExecute is in the UI Thread. Also you can run a code on UI Thread once a certain part of the work is done simply on onProgressUpdate by calling publishProgress on doInBackground.
Refer this for more information. It has everything you need to know about AsyncTask.
If I understand this correct you have a seperate class, which runs an AsyncTask. If the task is completed the as callback used interface informs the Activity. This is good if you think in components to make the code more modular.
The most common practice is to use an AsyncTask as an inner class in an Activity. If you just wanna download a picture or something similar with relative small size this is the prefered way. Because you can access all fields in your inner class, which makes things easier than passing them around in constructors/interfaces.
Don't use an AsyncTask in an extra Class just for readability. If you have to do some fair calculation/modification on the results with different methods your way is ok.

Passing Android Acceleromter values from MainActivity to My GameView class

I am working on a game involving measuring accelerometer values and manipulating my character's position based on those values. I am only working with the X axis. I initiate my accelerometer manager in my main activity, but I need to use these values in another class. Obviously these values are constantly changing. How could I pass these values to my GameView class?
You can save them as static members of your activity, or pass them to GameView class each time there's a change in them (new value)
If you've used a sensorlistener you might think about moving that logic to the GameView class. Not totally sure without looking at your code though. Do you have any samples?
Why not do it the Android way? :)
When you implement a touch listener, you do something set like this:
myView.setOnTouchlistener(this):
This tells the view to call you back when it's touched. Here's how to do your own:
Define an interface and use a callback to let the class know that a value has changed.
public interface AccelerometerUpdateListener {
void onUpdate(int arg1, string arg2); ..<----add arguments you want to pass back
}
In your Activity:
public class MainActivity extends Activity implements AccelerometerUpdateListener {
ArrayList<AccelerometerUpdateListener > listeners = new ArrayList<AccelerometerUpdateListener >();
...
#Override
public void onCreate(Bundle savedInstanceState)
{
...
myGameClass.setResponseReceivedistener(this);
...
}
public void setUpdateListener(AccelerometerUpdateListener listener){
if (!listeners.contains(listener){
listeners.add(listener);
}
}
public void removeUpdateListener(AccelerometerUpdateListener listener){
if (listeners.contains(listener){
listeners.remove(listener);
}
}
When you update the values
for (AccelerometerUpdateListener listener:listeners){
listener.onUpdate(arg1, arg2);
}
In your receiving class:
public class MyGameClass implements AccelerometerUpdateListener {
...
#Override
public void onUpdate(int arg1, string arg2){
// do whatever you need to do
}
All from memory so please excuse typos.

passing instructions from UI thread to Rendering thread (GLSurfaceView)

The Setup : A RelativeLayout with a GLSurfaceView and a Button as shown in the image..
The Problem: Lets say I have other triangle models (The one in the picture being the initial model)... I wish to change the models cyclically on click of the button. Since button is on the UI thread and glSurfaceView runs on a separate thread, I don't exactly know how to pass the info/instruction to it. I know there is this thing called Handler in Android which might be useful in this case... But I need some help here..
Edit: If Handler is the right way, I need to know how to add Looper to that Handler... The documentation says add looper.prepare() at the start of run() method.. But the glSurfaceView creates thread implicitly, resulting in no run() method directly available..
I don't think it is necessary to use handlers to solve this issue but you may need to adjust the way you organise your classes.
Here is an example of an organisational structure that might solve your issue:
Activity Class
public class MainActivity extends Activity {
private int modelNumber = 0;
private ArrayList<Model> models = new ArrayList<Model>();
private YourRendererClass renderer;
#Override
public void onCreate(Bundle savedInstanceState) {
...
// Setup GLSurfaceView
GLSurfaceView surface = new GLSurfaceView(this);
setContentView(surface);
renderer = new YourRendererClass();
surface.setRenderer(renderer);
// Set up models
models.add(new Model(x, y, size etc..));
models.add(new Model(x, y, size etc..));
models.add(new Model(x, y, size etc..));
etc.
// Display first model
renderer.setCurrentModel(models.get(modelNumber));
...
}
// Called by the button press:
// Use android:onClick="onClick"
// in your layout xml file within button
public void onClick(View view){
// Make it loop round
modelNumber++;
if(modelNumber>=models.size()){
modelNumber=0;
}
// Display current model
renderer.setCurrentModel(models.get(modelNumber));
}
}
Renderer Class
public class YourRendererClass implements Renderer {
private Model currentModel;
#Override
public void onDrawFrame(GL10 gl) {
// ** Your existing set-up code **//
// Draw model
if (currentModel!=null){
currentModel.draw(gl);
}
}
public void setCurrentModel(Model model){
currentModel = model;
}
}
Model class
public class Model {
// Holds model information
private int size;
private int x;
private int y;
// etc...
public model(int x, int y, int size etc...){
this.x=x;
this.y=y;
this.size=size;
// etc....
}
public void draw(GL10 gl) {
// ** Draw model based on model information fields above **
}
}
The above code is untested as I don't have access to your drawing code but the structure should work if implemented correctly. I've tried to make it clear where you'll have to insert your own code to make it work. In particular I wasn't sure what defines each of your different models so you'll need to include sufficient local variables within the Model class to define them.
I hope my answer helps, let me know if you have any questions.
Tim
You should look at queueEvent! It's a very convenient way to pass informations from UI Thread to renderer Thread:
queueEvent(new Runnable(){
#Override
public void run() {
mRenderer.method();
}});

CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views

I'm doing a manipulation in database in an IntentService, and in the Activity im showing a CustomProgressBar, but I want to show also the percentage value. So, for that I get the percentage value in the IntentService and set this value in a static method in the Activity. But the error show up:
CalledFromWrongThreadException: Only the original thread that created
a view hierarchy can touch its views.
I dont want to do this operation in an AsyncTask becaus I don't want to block the UI, so I'm using a IntentService.
Here is how I am doing this.
MyIntentService.java
public class MyIntentService extends IntentService
{
#Override
public void onHandleIntent(Intent intent)
{
updateDatabase();
}
public void updateDatabase()
{
resetPercentage(cursor.getCount * 2)
do
{
// do operation for updating the database
// here I update the view everytime a new item is inserted in DB.
int updatedReturn = MyActivity.updatePercentageValue(percentage());
}
while(...)
}
public void resetPercentage(int elementsNum)
{
mUpdatePercentage = 0;
mMaxItems = elementsNum;
}
public int incrementPercentageCounter()
{
return ++mPercentageCounter;
}
public int percentage()
{
int value = (mPercentageCounter/mMaxItems)*100;
return (value > 100) ? 100 : value;
}
}
MyActivity.java
public class MyActivity extends Activity
{
private TextView mMyTextView;
#Override
public void onCreate(Bundle bundle)
{
super.onCreate(bundle);
mMyTextView = (TextView) findViewById(R.id.textview);
}
public static int updatePercentageValue(int percentageValue)
{
mMyTextView.setText("" + percentageValue + " %");
return 1;
}
}
Any Idea of how can I solve this problem or do this operation using my IntentService so the UI wont be blocked.
Obs: I want to keep using IntentService also because a lot of things is done, and I dont want to change all over again.
Thanks!
An AsyncTask won't block the UI. You should probably use it. The kind of thing you're trying to do is exactly what it's good for. The AsyncTask doesn't need to exist outside of your Activity, it's short-lived work (relatively), and your work needs to update this UI. An AsyncTask seems more appropriate than a Service here.
Doing things in an async task is specifically to not block the UI thread. It even has an on progress method to do exactly what you want to do wih updating the UI. Gven that you don't want to do that, but you need to look into the running method.
Looking at this code I am somewhat confused as to how it works since you are accessing a member variable in a static method.

Categories

Resources