Thursday, June 20, 2013

Android: Solution for NetworkOnMainThreadException


NetworkOnMainThreadException
Occurs in Runtime Exception
The exception that is thrown when an application attempts to perform a networking operation on its main thread. (NetworkOnMainThreadException)

android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork
StrictMode : StrictMode is most commonly used to catch accidental disk or network access on the application's main thread. (StrictMode.ThreadPolicy.Builder)
From above statement, we can conclude there is some network operation is performed in Main Therad.
Exception:
android.os.NetworkOnMainThreadException
android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1117)
libcore.io.BlockGuardOs.connect(BlockGuardOs.java:84)
libcore.io.IoBridge.connectErrno(IoBridge.java:127)
libcore.io.IoBridge.connect(IoBridge.java:112)
java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)
java.net.PlainSocketImpl.connect(PlainSocketImpl.java:459)
java.net.Socket.connect(Socket.java:842)
org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:119)
org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:144)
org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
.
.
.
android.view.View.performClick(View.java:4204)
android.view.View$PerformClick.run(View.java:17355)
android.os.Handler.handleCallback(Handler.java:725)
android.os.Handler.dispatchMessage(Handler.java:92)
android.os.Looper.loop(Looper.java:137)
android.app.ActivityThread.main(ActivityThread.java:5041)
java.lang.reflect.Method.invokeNative(Native Method)
java.lang.reflect.Method.invoke(Method.java:511)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
dalvik.system.NativeStart.main(Native Method)

Solutions:
Remove Network operation from main thread and use background operations like Services, Async Task
Or
StrictMode implemented from api level 9, so your min android sdk support should be 9

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);

Tuesday, June 11, 2013

Android: Unit Test for Custom Content Provider using Roboelectric



Robolectric provides a simple approach to automate unit test case for android by using standard JUnit tests. It runs on any JVM, without needing the emulator or a device.
Advantages of Roboelectric:
No Mocking Frameworks Required

Run Tests Outside of the Emulator

Test Annotations

@RunWith

To run your test with Robolectric, you need to tell JUnit using the @RunWith annotation on your test class:
@RunWith (RobolectricTestRunner.class) // required for Robolectric!
For more details: http://pivotal.github.io/robolectric/user-guide.html
With Robolectric, we can write a small unit test for custom content provide like this.

@RunWith(RobolectricTestRunner.class)
public class BookContentProviderTest {

 private Activity activity;
 private BookProvider bookProvider;
 private ContentResolver contentResolver;

 public static final String AUTHORITY = "com.test.provider.Book";

 public static final String BOOK_TABLE_NAME = "book";

 /**
  * The columns we are interested in from the database
  */
 public static final String[] BOOK_PROJECTION = new String[] {
   BookColumns._ID, // 0
   BookColumns.BOOK_NAME, // 1
 };

 public static final Uri BOOK_URI = Uri.parse("content://" + AUTHORITY + "/"
   + BOOK_TABLE_NAME);

 private String[] bookList = new String[] { "angels and demons", "Book1",
   "Book2", "Book3" };

 @Before
 public void setUp() throws Exception {
  bookProvider = new BookProvider();
  activity = new Activity();
  contentResolver = activity.getContentResolver();

  bookProvider.onCreate();
  ShadowContentResolver.registerProvider(AUTHORITY, bookProvider);
 }

 @Test
 public void testContentProvider() {

  insertBook(new Book("53bfc0b980b0", "angels and demons"));
  insertBook(new Book("53bfc0b980b3", "Book1"));
  insertBook(new Book("53bfc0b980b1", "Book2"));
  insertBook(new Book("53bfc0b980b2", "Book3"));

  Cursor cursor = contentResolver.query(BOOK_URI, BOOK_PROJECTION, null,
    null, BookColumns.DEFAULT_SORT_ORDER);

  cursor.moveToFirst();

  Assert.assertTrue(cursor.getCount() == 4);

  if (cursor.getCount() != 0) {
   do {
    Assert.assertEquals(bookList[cursor.getPosition()],
      cursor.getString(cursor
        .getColumnIndex(BookColumns.BOOK_NAME)));
   } while (cursor.moveToNext());
  }

 }

 private void insertBook(Book book) {
  contentResolver.insert(BOOK_URI, getContentValue(book));
 }

 private ContentValues getContentValue(Book book) {
  ContentValues values;
  values = new ContentValues();
  values.put(BookColumns._ID, book.getBookId());
  values.put(BookColumns.BOOK_NAME, book.getName());
  return values;
 }
}

Friday, May 31, 2013

Android: Solution to detect when an Android app goes to the background and come back to the foreground without getRunningTasks or getRunningAppProcesses



In Android, we don’t have options directly to find whether our app goes to background or not like applicationdidenterbackground in iOS.
I have gone through lot of articles and forums; everywhere I am finding only one result.

private boolean isApplicationBroughtToBackground() {
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List tasks = am.getRunningTasks(1);
    if (!tasks.isEmpty()) {
        ComponentName topActivity = tasks.get(0).topActivity;
        if (!topActivity.getPackageName().equals(context.getPackageName())) {
            return true;
        }
    }

    return false;
}

But we can’t use getRunningTasks because android specifies “method is only intended for debugging and presenting task management user interfaces“.

Solution to detect when an Android app goes to the background and come back to the foreground without getRunningTasks or getRunningAppProcesses by using onWindowFocusChanged and onStop method

The solution i tired for my application as shown below.

BaseActivity is a superclass of all the activities.

BaseActivity.java

import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import android.widget.Toast;

/**
 * @author Harsha
 *
 *         BaseActivity class extends Activity
 */
public abstract class BaseActivity extends Activity {

protected static final String TAG = BaseActivity.class.getName();

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}

public static boolean isAppWentToBg = false;

public static boolean isWindowFocused = false;

public static boolean isMenuOpened = false;

public static boolean isBackPressed = false;

@Override
protected void onStart() {
Log.d(TAG, "onStart isAppWentToBg " + isAppWentToBg);

applicationWillEnterForeground();

super.onStart();
}

private void applicationWillEnterForeground() {
if (isAppWentToBg) {
isAppWentToBg = false;
Toast.makeText(getApplicationContext(), "App is in foreground",
Toast.LENGTH_SHORT).show();
}
}

@Override
protected void onStop() {
super.onStop();

Log.d(TAG, "onStop ");
applicationdidenterbackground();
}

public void applicationdidenterbackground() {
if (!isWindowFocused) {
isAppWentToBg = true;
Toast.makeText(getApplicationContext(),
"App is Going to Background", Toast.LENGTH_SHORT).show();
}
}

@Override
public void onBackPressed() {

if (this instanceof MainActivity) {

} else {
isBackPressed = true;
}

Log.d(TAG,
"onBackPressed " + isBackPressed + ""
+ this.getLocalClassName());
super.onBackPressed();
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {

isWindowFocused = hasFocus;

if (isBackPressed && !hasFocus) {
isBackPressed = false;
isWindowFocused = true;
}

super.onWindowFocusChanged(hasFocus);
}

public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
break;
case R.id.action_settings:
Intent i = new Intent(this, SettingActivity.class);
startActivity(i);
break;
}
return true;
}

@Override
public boolean onMenuItemSelected(int featureId, android.view.MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
break;
case R.id.action_settings:
Intent i = new Intent(this, SettingActivity.class);
startActivity(i);
break;
}
return true;
}

}

Each of the activity classes extendes BaseActivity class to track the application status.

MainActivity.java

import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;

public class MainActivity extends BaseActivity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

((ImageButton) findViewById(R.id.SecondBtn))
.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
startActivity(new Intent(getApplicationContext(),
SecondActvity.class));
}
});
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

}

SecondActvity.java

import android.os.Bundle;

public class SecondActvity extends BaseActivity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second);
}

}
 App output looks as :




Improvements
If you want to see an example without having common base class, see app-foreground-n-background-using-callbacks-in-application. It also gives the Solution to detect when an Android app goes to the background and come back to the foreground without getRunningTasks or getRunningAppProcesses. This example supports from API level 14 and above because they interface classes used are added from API level 14.

Source Code
You can download the source code by clicking here: AppStatus-SourceCode.  This project is built using eclipse IDE. Unzip and import the project into Eclipse, it’s a good idea to use the Project by clean and rebuild from the project menu. It works in all API levels.


Thanks for reading :) 
Whether this post is helpful?
If you have any other quick thoughts/hints that you think people will find useful, feel free to leave a comment.