Thursday, May 15, 2014

ActionBar dissapears although I'm using a scrollView

ActionBar dissapears when I click EditText although I'm using a ScrollView. This behavior appears after an orienation change when I click the EditText view.

Solution :
Seems that I need to add also  adjustResize on my manifest :
            android:windowSoftInputMode="adjustResize"

    //TODO
    further investigate that behavior

Sunday, February 23, 2014

ToDo List example

Since repetition is the mother of all learning and the following example is one of the most distinct examples of how to start android development I wrote it down as well to try to explain it as best as I can.

What we are going to do is a ToDo List app.

Bearing the design in mind will help us better understand what components will be needed ( plus I prefer a more visualized approach to such kind of problems ).

android todo app

As we can see from the mockup sketch two fragments are needed. One will just display an EditText widget and when the user clicks 'Send' on the software keyboard we will pass the text to the list bellow. That gets us to the second fragment which is a ListFragment.


Both of them are in the MainActivity.
Since we are using a ListFragment we have to use an Adapter to bind the data to the list.

Also we will need a data model for our todo items. Lets name it DataItem class.
Last but not least we will create a custom view from each list item.

Let me summarize things a little bit : We have one MainActivity class with its layout, composed of two fragments ( one is a ListFragment ). The ListFragment also needs an Adapter class. Our data model will only need a String variable and a Custom View for each ListFragment's item for the time.


So let's start from our model. We only need one getter and one setter method since our only variable will be a String. You can check the code here .

Now its time to create the TopFragment. As you can see 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".TopFragment" > <EditText android:id="@+id/myEditText1" android:inputType="textCapSentences|textAutoCorrect" android:imeOptions="actionSend" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" /> </LinearLayout>
 the layout is just an EditText. We inflate that layout in onCreateView method ( like we do with every fragment ). The “tricky” part here is adding an OnEditorActionListener  so we can listen for the 'SEND' action, get the user input and clear the text in EditText. An Interface is also necessary so we can implement it on the MainActivity and get the user's text input. All of these data will be stored on an ArrayList in the MainActivity and passed to the Adapter to bind them to the view.  


The TaskListAdapter gets each item from the ArrayList as we said above, creates a new list item and sets the data.

ListFragment just inflates the layout which consists of a ListView with the android:divider atrribute set to null so we don't have to deal with the default divider line from the ListView widget.


Since each item is just a TextView our custom view needs to extend a TextView. We saw on a previous post  how to create a custom view so I will not go into details.

The XML layout file for the custom view, used by the TaskListAdapter is:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".TaskListFragment" > <org.codeteo.todolist.CustomItemView android:id="@+id/row" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp" android:textColor="#FF0000" android:textSize="20sp" /> </LinearLayout>


Now we have to check the MainActivity code. The MainActivity implements the OnItemAddedListener Interface we declared on the TopFragment and create the method onNewItemAdded() so it can get the data user's input and store it on an ArrayList.
That input along with the id resource of the XML file that represents the list
item are passed to the Adapter.
The code is below :

 public class MainActivity extends Activity  implements TopFragment.OnItemAddedListener {
 
   private ArrayList todoItems;
   private TaskListAdapter aa; 

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
       
     // Get references to the Fragments
     FragmentManager fm = getFragmentManager();
     TaskListFragment todoListFragment = 
       (TaskListFragment)fm.findFragmentById(R.id.TaskListFragment);
      
     // Create the array list of to do items
     todoItems = new ArrayList();
      
     // Create the array adapter to bind the array to the ListView
     int resID = R.layout.tasklist_fragment;   
     aa = new TaskListAdapter(this, resID, todoItems);
      
     // Bind the array adapter to the ListView.
     todoListFragment.setListAdapter(aa);
   }
   
   public void onNewItemAdded(String newItem) {
     DataItem newTodoItem = new DataItem(newItem);
     todoItems.add(0, newTodoItem);
     aa.notifyDataSetChanged();
   }
}


The method onNewItemAdded() adds the DataItem before every other ArrayList item and also notify the data set has changed.
You can find the code of the project in the github repo here and you can import it and run it on your eclipse.
This example is based on Reto Meier's example on chapter four of his book "Professional Android 4 Application Development" you can find in this link

Sunday, December 29, 2013

Custom Views

We get Custom Views by extending an existing Widget ( Button, EditText, TextView, etc ), something that fits better to the functionality we want to achieve and by defining attributes for that view.

1. By extending a View we now have a Class, whose fully qualified name can be used as an XML tag, to add to the layout file. If the package is com.androidexamples.customviews and my Custom View's Class name is MyEditText then the XML code we are going to add is :

<com.androidexamples.customviews.MyEditText
    android:id=”@+id/myview”
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
        …

/>

2. Into res/values/attrs.xml inside a <declare-styleable> tag we add the attributes for our view. A valid example could be :

<resources>
        <declare-styleable>
            <attr name=”attr_color” format=”color” />
            <attr name=”attr_firstname” format=”string” />
       </declare-styleable>
</resources>


From now on we can use these attributes either in our layout file as part of our custom View XML tag, or through code.
In order to use them in the layout file we have to first define a custom namespace similar to what android does with its own attributes. The android default namespace is : xmlns:android="http://schemas.android.com/apk/res/androidand it's defined into the parent element of the layout file.
Respectively our attributes' namespace uses the same format but instead of android we can use whatever name we want ( like “app” or “custom” ) and the schema is defined with our package name instead of the android. So a valid example could be :
xmlns:app="http://schemas.android.com/apk/res/com.androidexamples.customviews"

Now we can add the “attr_firstname” to the XML in the form : 
                       app:attr_firstname=”Some Random Text”


Through the code we have access to an array that stores each attribute. It is a special container named TypedArray and it can get referenced to the attributes with obtainStyledAttributes().


3. In our Class code it is a common practise to use an init() method to get the attributes and assign initial values to them. This method is then passed to our View's constructor.

4. Then all it's left to do is to override the onDraw() and onMeasure() methods.


By overriding onDraw() we have access to the Canvas object. You can now create your UI for your View. The styling of the elements is done through a Paint object.


OnMeasure() is called with the width and height specifications from the parent layout element. Those values should be treated as requirements for the restrictions on width and height measurements we will produce.


Some key points you should keep in mind ( otherwise it leads you to hard ) :
  • call recycle() after you get the attributes from TypedArray.
  • Don't create Paint objects inside onDraw() method. Views are redrawn frequently and creating objects inside onDraw() its expensive waste of resources.
  • After every change on our attributes' values we have to call invalidate() so the system will know there might be a change in its appearance and needs to be redrawn.



The code below gives as a custom EditText which uses Paint to underline each line with a light green color.




public class MyEditText extends EditText {

 private Rect mRect;
 private Paint mPaint;
  
 private int attrColor;
 
 
 public MyEditText(Context context) {
  super(context);
 }

 public MyEditText(Context context, AttributeSet attrs) {
  super(context, attrs);
  
  TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyEditText);
     attrColor = ta.getInteger(R.styleable.MyEditText_attr_color, 0xff00ff00);
     ta.recycle();
  
  init();
 }

 public void init() {
  
  mRect = new Rect();
  mPaint = new Paint();
  mPaint.setStyle(Paint.Style.FILL);
  mPaint.setColor(attrColor);    //get value from attr
  
 }
 
 
 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  int count = getLineCount();
  
  Rect r = mRect;
  Paint p = mPaint;
  
  
 for(int i=0; i< count; i++)  {
   int baseline = getLineBounds(i, r);
   canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, p);
  }
  
 }
 
}



Monday, December 9, 2013

Add Views programmatically

Example of adding two Buttons in a RelativeLayout :

1) Instantiate the RelativeLayout
2) Instantiate the Buttons.
3) Create the LayoutParams for each Buttons.
4) Add Views to their parent. That's the RelativeLayout.

One key point here. The LayoutParams for the child Views must the same type as that of their parent. So in our case both Buttons  LayoutParams have to be RelativeLayout.LayoutParams.

Let's see how this applies to code :

RelativeLayout layout = new RelativeLayout(this); // Instantiate the parent

b3 = new Button(this); b3.setId(1);
b3.setText("Relative Button 3");

b4 = new Button(this); b4.setId(2);
b4.setText("Relative Button 4");

RelativeLayout.LayoutParams b3_lp = new RelativeLayout.LayoutParams(
                   LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);


RelativeLayout.LayoutParams b4_lp = new RelativeLayout.LayoutParams(
                  LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
b4_lp.addRule(RelativeLayout.RIGHT_OF, b3.getId());

layout.addView(b3, b3_lp);
layout.addView(b4, b4_lp);

setContentView(layout);


The result is :



Notice the addRule() which sets the Button b4 to the right of the b3.
To achieve that we have to set Id's for our Buttons so we can refer to the view that acts as an anchor.



Sunday, November 24, 2013

Send JSON unicode data to server with POST request

HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url); // Address ( url )
HttpResponse response;

JSONObject json = new JSONObject();

json.put("passwd", param1);
json.put("comment", param2);

                        // String Entity to UTF-8
StringEntity se = new StringEntity(json.toString(), "UTF-8");
se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));

httppost.getParams().setParameter("json", json);
httppost.setEntity(se);

response = httpclient.execute(httppost);

Friday, November 1, 2013

Android Studio and Gradle Basics - part 1

With Android Studio there's a new build system called Gradle. In fact Gradle is much more than just a build system but we will focus on the basics here.

First of all lets see the Project Structure :



The root folder contains two Project folders and two gradle files.

For now build.gradle is empty while settings.gradle  :
include ':MyDemo', ':MyLibProject'

Between MyDemo  and MyLibProject Project there are some differences :
1. Library Projects do not generate APK. Instead they generate an .aar package.
2. build.gradle of MyDemo contains a line apply plugin: 'android'  where for Library Project
    we  have apply plugin : 'android-plugin'

Let's have a look at MyDemo build.gradle file :

buildscript {
     repositories {
         mavenCentral()
     }
     dependencies {
          classpath 'com.android.tools.build:gradle:0.6.+'
     }
}
apply plugin: 'android'

repositories {
      mavenCentral()
}

android {
     compileSdkVersion 18
     buildToolsVersion "18.1.1"

     defaultConfig {
          minSdkVersion 8
         targetSdkVersion 18
     }
}


and MyLibProject build.gradle file :

buildscript {
     repositories {
         mavenCentral()
     }
     dependencies {
          classpath 'com.android.tools.build:gradle:0.6.+'
     }
}
apply plugin: 'android-library'

repositories {
      mavenCentral()
}

android {
     compileSdkVersion 18
     buildToolsVersion "18.1.1"

     defaultConfig {
          minSdkVersion 8
         targetSdkVersion 18
     }
}


We can take the first block code of each file ( which is the same ) and move it to the external build.gradle :


buildscript {
     repositories {
         mavenCentral()
     }
     dependencies {
          classpath 'com.android.tools.build:gradle:0.6.+'
     }
}


Android Projects have source folders ( MyDemo ) , Library Projects ( MyLibProject ) and jar file dependencies.
There are three kinds of dependencies :
1. Maven
2. jar file
3. Module

If we choose to add a dependency like ActionBarSherlock to our project from the maven repositories we go to http://search.maven.org/ , write actionbarsherlock to the input area and click search button.
What we see is :


We can use it in our build.gradle code :

 dependencies {
  compile 'com.actionbarsherlock:actionbarsherlock:4.4.0@aar'
 }

Instead of the above way we can also download the rar file, add it to the /libs folder and

 dependencies {
  compile file ('libs/actionbarsherlock.jar')
 }

Or if we had downloaded the source code and add it like a Library Project ( File > Project Structure > Modules ) and add it to the project. Then we had to add to the build.gradle 

 dependencies {
  compile project (':ActionBarSherlock')
 }

Just keep in mind that if we add an artifact as a .jar file to a libs folder and we have the same jar file in another library folder then we are going to have a conflict. We just need to have only one copy of the jar file.
That's a good reason for you to start using the maven repository and don't just add jar files. In that case if we have added the same artifact more than once there will be no conflict.

From the Command Line. Go to the root dir of your project. Gradle works with tasks.
gradlew tasks to see all available tasks.
gradlew assemble to build the project and
gradlew installDebug to install it to the connected devices.

Wednesday, September 11, 2013

Check if Google's location Service is enabled

Check if Google's location Service is enabled by the user, else open Settings > Location so the user enables them.
First get the
String locationProviders = Settings.Secure.getString(getContentResolver(),Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
contains "network" or "gps" or both values separated by comma.

If the string is empty => Google Location Service is closed and you have to prompt the user to open it. Wifi might or not be open.
If the string equals "network" => WiFi and Google Location Service are enabled.
If the string equals "network,gps" => WiFi and GPS and Location Service are enabled.

We need to create a Dialog and ask the user to take the action he wants. In our case we want the user when she clicks Yes to open the Settings > Location , so she can enable the Location Service.
We can achieve that with ACTION_LOCATION_SOURCE_SETTINGS.

The code is :

     if (locationProviders == null || locationProviders.equals("")) {
         
            new AlertDialog.Builder(this)
            .setTitle("Enable Location Service")
            .setMessage("This Application requires the use of Google Location's service.  " +
                    "Do you wish to enable this feature")
            .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    // show system settings
                    startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
                }
            })
            .setNegativeButton("No", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    // do nothing
                }
            })
            .show();
}

Link : http://stackoverflow.com/questions/10311834/android-dev-how-to-check-if-location-services-are-enabled