I have main activity which will get JSON data from a url async
This is MainActivity.java
public class MainActivity extends FragmentActivity implements ActionBar.TabListener{
private ViewPager viewPager;
private TabsPagerAdapter mAdapter;
private ActionBar actionBar;
//Tab titles
private String[] tabs = {"Sermons", "More"};
private String[] sermonsList = new String[0];
//JSON URL for sermonList data
private static String sermonListJSONUrl = "https://dl.dropboxusercontent.com/u/12345/index.php";
//Variable to save JSON Object
private static final String JSON_KEY_SERMONS = "sermon";
private JSONObject sermonListJSONObject = null;
private JSONArray sermonListJSONArray = null;
SermonsFragment mSermonFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Call JSONParser Asynchronously to get sermonList in JSON Format
new callJSONParserAsync().execute(sermonListJSONUrl);
//this.mSermonFragment = (SermonsFragment) getFragmentManager().findFragmentById(android.R.id.list);
this.mSermonFragment = (SermonsFragment) getFragmentManager().findFragmentById(R.id.pager);
//Initialization
viewPager = (ViewPager) findViewById(R.id.pager);
actionBar = getActionBar();
mAdapter = new TabsPagerAdapter(getFragmentManager());
viewPager.setAdapter(mAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
//Adding Tabs
for(String tab_name : tabs) {
actionBar.addTab(actionBar.newTab().setText(tab_name).setTabListener(this));
}
/**
* on swiping the viewpager make respective tab selected
*/
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
//on changing the page
//make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
This is activity_main.xml
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v4.view.ViewPager>
This is SermonsFragment.java
public class SermonsFragment extends ListFragment {
private String[] sermonsList;
ArrayAdapter listAdapter;
String imageUrl = "https://fbcdn-sphotos-b-a.akamaihd.net/" +
"hphotos-ak-prn2/t1.0-9/10415605_10132423542_6220704573655530117_n.jpg";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sermonsList = ((MainActivity)getActivity()).getSermonsList();
//ListView for the sermon list, only show if there is something in listview
listAdapter = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, sermonsList);
if(listAdapter.getCount() != 0) {
setListAdapter(listAdapter);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_sermons, container, false);
// show The Image
new getSermonBannerImage((ImageView) rootView.findViewById(R.id.series_banner))
.execute(imageUrl);
return rootView;
}
public void updateListView(String[] newData) {
if(newData.length == 0) {
Log.d("myTesting3", "sermonsList is Empty");
} else {
Log.d("myTestingSermonFragment", newData[0]);
Log.d("myTestingSermonFragment", newData[1]);
}
sermonsList = newData;
Log.d("myTestingSermonFragment", sermonsList[1]);
this.listAdapter.clear();
this.listAdapter.addAll(newData);
this.listAdapter.notifyDataSetChanged();
}
This is fragment_sermon.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#222222" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Shows an image from your drawable resources -->
<ImageView
android:id="@+id/series_banner"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:src="@drawable/series_banner" />
<!-- Closing tag for the horizontal nested layout -->
<View
android:layout_width="fill_parent"
android:layout_height="10dp"
android:layout_marginBottom="10dp"
android:background="@android:color/darker_gray"/>
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#ffffffff" />
<TextView
android:id="@android:id/empty"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="No Data" />
</LinearLayout>
</RelativeLayout>
This is TabsPagerAdapter.java
public class TabsPagerAdapter extends FragmentPagerAdapter {
public TabsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int index) {
switch (index) {
case 0:
//Sermons fragment activity
return new SermonsFragment();
case 1:
//More fragment activity
return new MoreFragment();
}
return null;
}
@Override
public int getCount() {
//get item count - equal to number of tabs
return 2;
}
}
and lastly this is the error
07-27 16:42:27.921 1549-1555/org.myapp.myapp E/jdwp﹕ Failed writing handshake bytes: Broken pipe (-1 of 14)
07-27 16:42:29.941 1549-1549/org.myapp.myapp E/OpenGLRenderer﹕ Getting MAX_TEXTURE_SIZE from GradienCache
07-27 16:42:29.941 1549-1549/org.myapp.myapp E/OpenGLRenderer﹕ MAX_TEXTURE_SIZE: 16384
07-27 16:42:29.953 1549-1549/org.myapp.myapp E/OpenGLRenderer﹕ Getting MAX_TEXTURE_SIZE from Caches::initConstraints()
07-27 16:42:29.953 1549-1549/org.myapp.myapp E/OpenGLRenderer﹕ MAX_TEXTURE_SIZE: 16384
07-27 16:42:30.353 1549-1549/org.myapp.myapp E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: org.myapp.myapp, PID: 1549
java.lang.NullPointerException
at org.myapp.myapp.MainActivity$callJSONParserAsync.onPostExecute(MainActivity.java:174)
at org.myapp.myapp.MainActivity$callJSONParserAsync.onPostExecute(MainActivity.java:157)
at android.os.AsyncTask.finish(AsyncTask.java:632)
at android.os.AsyncTask.access$600(AsyncTask.java:177)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)
I'm not sure why there is OpenGLRenderer Error, but it's always been there ever since I create this app and it run just fine, so that's not the problem (Although if you can point out how to fix this it will be great). MainActivity.java:174 is this line on mSermonFragment.updateListView(sermonsList);
How can I make sure it is populate correctly? preferably async so it's not locking the UI, maybe by updating the listview later after async complete.
It would be nice, if you could also point out, how to make it so during async, it will check if there's internet connection, the list view will show loading circle, and if it has no internet, or empty list it will show no data, otherwise it will show the list
Since you only have two fragments, you can keep track of them saving the instances. Using callbacks as suggested it's not the best option.
So, in your pager adapter:
public class TabsPagerAdapter extends FragmentPagerAdapter {
SermonsFragment mSermonsFragment;
MoreFragment mMoreFragment;
public TabsPagerAdapter(FragmentManager fm) {
super(fm);
this.mSermonsFragment = new SermonsFragment();
this.mMoreFragment = new MoreFragment();
}
@Override
public Fragment getItem(int index) {
switch (index) {
case 0:
//Sermons fragment activity
return mSermonsFragment;
case 1:
//More fragment activity
return mMoreFragment;
}
return null;
}
@Override
public int getCount() {
//get item count - equal to number of tabs
return 2;
}
public updateSermonsFragment(String[] data) {
mSermonsFragment.updateData(data);
}
//i don't know what's the data type managed by MoreFragment
public updateMoreFragment(Object data) {
mMoreFragment.updateData(data)
}
}
Create a method to update your adapter in your fragment:
public void updateData(String[] newData) {
this.listAdapter.clear();
for(int i = 0; i < newData.length; i++) {
this.listAdapter.add(newData[i]);
}
this.listAdapter.notifyDataSetChanged();
}
Then you can call this method from the onPostExecute of your AsyncTask trought your adapter method:
protected void onPostExecute(JSONObject jsonObject) {
sermonListJSONObject = jsonObject;
sermonListJSONArray =
parseJSONObjToJSONArray(sermonListJSONObject, JSON_KEY_SERMONS);
String[] sermonsList;
.... // here you need set an array with the strings you parsed
//here you call the new method on the adapter to update your data.
mAdapter.updateSermonsFragment(sermonsList);
}
Another best practice it's to define a static newInstace(String[] data)
method in your fragment, so you can initialize the fragment data at the very first network call, to be sure your fragment has a dataset to work with then update as described above.
Why do you not call/execute
sermonsList = ((MainActivity)getActivity()).getSermonsList();
in onPostExecute() of the AsyncJob?
onPostExecute is running on UI-Thread - so it should be no problem
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With