Reputation: 4093
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
Upvotes: 7
Views: 4892
Reputation: 5121
public void updateData(String[] newData) {
this.listAdapter.clear();
for(int i = 0; i < newData.length; i++) {
this.listAdapter.add(newData[i]);
}
this.listAdapter.notifyDataSetChanged();
}
// call this method in onPostExecute() method . By calling listAdapter.notifyDataSetChanged(); this adapter is updated with the data which comes from JSON object .
hope it ll help u :)
Upvotes: 0
Reputation: 560
It would be nice if i can help you because i have also faced the problem like that...
you want to set adapter which includes the string array provided by your asynctask.
create constructor in TabsPagerAdapter.class .........
ArrayList<String> arrayList_Tab = new ArrayList<String>();
** Constructor of the class */
public TabsPagerAdapter(FragmentManager fm,
ArrayList<String> arrayList1) {
super(fm);
this.arrayList = arrayList1;
................
@Override
public Fragment getItem(int index) {
Bundle data = new Bundle();
switch (index) {
case 0:
SermonsFragment ment = new SermonsFragment ();
data.putStringArrayList("data", arrayList);
ment.setArguments(data);
return ment;
case 1:
//More fragment activity
return new MoreFragment();
}
return null;
}
I have done with this arraylist but you can do this with passing array as parameters. in your MainActivity.. add your asynctask data to an arraylist and then pass to TabsPagerAdapter class
mAdapter = new TabsPagerAdapter(getFragmentManager());
change above to
mAdapter = new TabsPagerAdapter(getFragmentManager(),ArrayLListgotfromAsyctask);
now get your arraylist at SermonsFragment class as :-
ArrayList<String> arrayList = new ArrayList<String>();
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
arrayList = getArguments().getStringArrayList("data");
}
now you can set arraylist to adapter.
Good luck !!!
Upvotes: 0
Reputation: 11443
This might be of the the topic, but I just ran into a similar handshake
error using volley
and https
urls. Check here for further informations.
Simple check if your connection is refused is to trust all SSL-Certificates. (This should only be used for testing!!).
Run this before your first call (f.e. extend Application
and call the following in onCreate
)
//trust all SSL
SSLCertificateHandler.nuke();
The Trust-everything-class:
public class SSLCertificateHandler {
protected static final String TAG = "NukeSSLCerts";
public static void nuke() {
try {
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] myTrustedAnchors = new X509Certificate[0];
return myTrustedAnchors;
}
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
} };
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
} catch (Exception e) {
}
}
}
Upvotes: 1
Reputation: 61
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.
Upvotes: 4
Reputation: 6847
There lots of options:
AsyncTask
and update adapter in the onPostExecute
.AsyncTask
inside your fragment.Sample of updating data in your fragment:
public class SermonsFragment extends ListFragment {
public void update(String[] sermonsList){
listAdapter.addAll(sermonsList);
listAdapter.notifyDataSetChanged();
}
}
Upvotes: 2
Reputation: 21
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
Upvotes: 2