Integrating ButterKnife library

Overview

ButterKnife library is very powerful library that helps coder to bind view and make codebase more beautiful. However there are some issues when integrating this library to project. This paper will help you solve them.

How to integrate
You config your gradle file likes below file:

...
apply plugin: 'com.neenbedankt.android-apt'

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

...

dependencies {
    compile 'com.jakewharton:butterknife:8.4.0'
    apt 'com.jakewharton:butterknife-compiler:8.4.0'
    ...
}

Android – onAttach(Context) not called for API 23

Overview

In Android, Fragment is very common class when coding. This class is very important on every project. From Api 23, Android SDK had an important change at Fragment class. This is:

onAttach(Activity) => onAttach(Context).

Developers need to keep code run on two versions of Fragment. I will write my solution for this issue.

How to implement

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        this.onAttach();
    }

    @SuppressWarnings("deprecation")
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            this.onAttach();
        }
    }

    private void onAttach() {
        // Enter your code here.
    }

In summary

With my solution, your code will run on all version of Android SDK.

Retrofit and Json parser

Overview

Retrofit is powerful library that turns your HTTP API into a Java interface. It is very common library. Moreover it can be used to parse Json object to Java object easily. I will suggest my solution for this issue.

How to implement

  1. Intergrade Retrofit library
  2. compile 'com.squareup.retrofit2:retrofit:2.1.0'
    
  3. Create network file
  4. public interface BookService {
        String TAG = BookService.class.getSimpleName();
    
        class Factory {
            public static BookService create() {
                Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://webtruyen.com/")
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .build();
                return retrofit.create(BookService.class);
            }
        }
    
        @GET("API_IOS/all")
        Observable<Page> getPage(@Query("cate") String cate,
                                 @Query("page") int page,
                                 @Query("perpage") int perPage);
    }
    

    You @Query to add param to api. Moreover you can use @Field, …

  5. Use annotation @SerializedName
  6. public class Page implements Serializable {
        private static final String TAG = Page.class.getSimpleName();
    
        @SerializedName("story")
        private List<Book> bookList;
        @SerializedName("success")
        private int success;
        @SerializedName("numrow")
        private long rowNumber;
    
        public List<Book> getBookList() {
            return bookList;
        }
    
        public void setBookList(List<Book> bookList) {
            this.bookList = bookList;
        }
    
        public int getSuccess() {
            return success;
        }
    
        public void setSuccess(int success) {
            this.success = success;
        }
    
        public long getRowNumber() {
            return rowNumber;
        }
    
        public void setRowNumber(long rowNumber) {
            this.rowNumber = rowNumber;
        }
    }
    

    Using @SerializedName(“numrow”) to show name of attribute on Json object.

In sumary

Retrofit is very useful library. You can research about this library in this link: http://square.github.io/retrofit/

Beautiful EditText with TextInputLayout

Overview

EditText is basic UI component of Android, but basic EditText is very simple and not beautiful. There are a lot of solution to make it beautifully. In this paper, i will introduce a simple solution for this issue. This is using TextInputLayout – a library of Android SDK.

How to implement

    1. Integrating com.android.support:design library
    dependencies {
        compile 'com.android.support:design:23.3.0'
    }
    1. Wrapping EditText by TextInputLayout
<android.support.design.widget.TextInputLayout     android:layout_width="match_parent"     android:layout_height="wrap_content">
        <EditText             android:layout_width="match_parent"             android:layout_height="@dimen/login_phone_number_edit_text_height"/>
</android.support.design.widget.TextInputLayout>

In summary
We will see the result of above solution:

Screen Shot 2016-08-19 at 16.47.49

Screen Shot 2016-08-19 at 16.46.51

Screen Shot 2016-08-19 at 16.50.39

Get current Location of Android device

Overview

Getting current location of Android device is common task of developers. However there are a lot of solution for this issue. But some of them are very complex. Therefor, I will introduce my solution to solve this problem easily.

How to implement

Config:

public class LocationConfig {
    public static final int INTERVAL = 600000;
    public static final int MIN_DISTANCE = 50;
}

Write LocationService file:

public class LocationService implements LocationListener {
    private static final String TAG = LocationService.class.getSimpleName();
    private static LocationService instance;

    private LocationManager locationManager;
    private boolean isGPSEnabled, isNetworkEnabled;
    private Context context;

    public static LocationService getInstance(Context context) {
        if (instance == null) {
            instance = new LocationService(context);
        }
        return instance;
    }

    private LocationService(Context context) {
        this.context = context;
    }

    @TargetApi(23)
    public void initLocationService() {
        if (Build.VERSION.SDK_INT >= 23 &&
            ContextCompat.checkSelfPermission(this.context, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
            ContextCompat.checkSelfPermission(this.context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            Log.e(TAG, "Can not get location because don't have permission!");
            return;
        }

        try {
            this.locationManager = (LocationManager) this.context.getSystemService(
                Context.LOCATION_SERVICE);

            // Get GPS and network status
            this.isGPSEnabled = this.locationManager.isProviderEnabled(
                LocationManager.GPS_PROVIDER);
            this.isNetworkEnabled = this.locationManager.isProviderEnabled(
                LocationManager.NETWORK_PROVIDER);

            if (!this.isNetworkEnabled && !this.isGPSEnabled) {
                Log.e(TAG, "Can not get location because network and GPS are disable!");
            } else {
                if (this.isNetworkEnabled) {
                    Log.i(TAG, "Get location by network");
                    this.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
                        LocationConfig.INTERVAL, LocationConfig.MIN_DISTANCE, this);
                    if (this.locationManager != null) {
                        Location location = this.locationManager.getLastKnownLocation(
                            LocationManager.NETWORK_PROVIDER);
                        if (location != null) {
                            this.updateLocation(location);
                            return;
                        }
                    }
                }
                if (this.isGPSEnabled) {
                    Log.i(TAG, "Get location by GPS");
                    this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                        LocationConfig.INTERVAL, LocationConfig.MIN_DISTANCE, this);
                    if (this.locationManager != null) {
                        Location location = this.locationManager.getLastKnownLocation(
                            LocationManager.GPS_PROVIDER);
                        this.updateLocation(location);
                        return;
                    }
                }
            }
        } catch (Exception ex) {
            Log.e(TAG, "initLocationService", ex);
        }
    }

    @Override
    public void onLocationChanged(Location location) {
        Log.i(TAG, "Location: " + location);
    }

    @Override
    public void onStatusChanged(String s, int i, Bundle bundle) {
        Log.i(TAG, "onStatusChanged: " + s);
    }

    @Override
    public void onProviderEnabled(String s) {
        Log.i(TAG, "onProviderEnabled: " + s);
    }

    @Override
    public void onProviderDisabled(String s) {
        Log.e(TAG, "onProviderDisabled: " + s);
    }

    private void updateLocation(Location location) {
        // write your code here
    }
}

Use LocationService to get current location:

LocationService service = LocationService.getInstance(context);
if (service != null) {
    service.initLocationService();
}

Conclusion

You can use my solution to get current location. However I recommend that you should to combine Receiver and my solution. This is the best way for getting current location in background task.

TextWatcher and ButterKnife library

Overview

ButterKnife library is very useful library for binding view of Android application. I will introduce the combination of TextWatcher and ButterKnife.

How to implement

@OnTextChanged(value = R.id.edit_photo_caption_row_caption,
        callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
protected void afterEditTextChanged(Editable editable) {
    // Write your code here
}

This above example shows how to implements OnTextChanged with After_Text_Changed callback.

In order to match all the methods of the TextWatcher interface, the @OnTextChanged annotation has 3 callback values.

  • The TEXT_CHANGED callback connects with the onTextChanged(CharSequence, int, int, int) method.
  • The AFTER_TEXT_CHANGED callback connects with the afterTextChanged(Editable) method.
  • The BEFORE_TEXT_CHANGED callback connects with the beforeTextChanged(CharSequence, int, int, int) method.

The default callback method for  @OnTextChanged is TEXT_CHANGED.