I'm programming with android studio and I want to parse a json and put the details in my object in a function in MainActivity and I do it well in that function and every thing is ok! But when I want to use it in onCreate it's null.
What should I do?
MainActivity:
public class MainActivity extends ActionBarActivity {
ArrayList<Details> details= new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new myserver2().execute("");
Adapter adptor=new Adapter(this,details);
ListView l= (ListView) findViewById(R.id.listview);
l.setAdapter(adptor);
}
private class myserver2 extends AsyncTask<String,String,String> {
String s;
#Override
protected String doInBackground(String... params) {
HttpClient client = new DefaultHttpClient();
HttpGet hp = new HttpGet("http://jsonplaceholder.typicode.com/posts");
try
{
HttpResponse r = client.execute(hp);
HttpEntity ent = r.getEntity();
String s = EntityUtils.toString(ent);
JSONArray array = new JSONArray(s);
JSONObject obj = new JSONObject();
for(int i=0;i<array.length();i++){
Details d = new Details();
obj=array.getJSONObject(i);
d.setId(Integer.parseInt(obj.getString("id")));
d.setUserid(Integer.parseInt(obj.getString("userId")));
d.setBody(obj.getString("body"));
d.setTitle(obj.getString("title"));
Log.i("**(*", obj.getString("title"));
details.add(d);
}
Log.i("**(*", details.get(0).getTitle());
} catch (
IOException e
)
{
e.printStackTrace();
} catch (
JSONException e
)
{
e.printStackTrace();
}
return null;
}
}
Details:
public class Details {
int id=0,userid=0;
String body,title;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getUserid() {
return userid;
}
public void setUserid(int userid) {
this.userid = userid;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
My log after the for in myserver given the true title but if I had this Log in onCreate it throws an exception:
java.lang.IndexOutOfBoundsException
And it's because of my Arraylis is null in onCreate but why and what should I do,I dont know!
Your onCreates tries to access the arraylist while the asyc task is not finished. To mamke sure you set the adapter only after asyc task is finished, set the adapter inside onPostExecute()
#Override
protected void onPostExecute(String result)
{
super.onPostExecute(result);
if(details.size > 0){
Adapter adptor=new Adapter(this,details);
l.setAdapter(adptor);
}else{
l.setAdapter(null);
}
}
Hope that helps!
You can override the onPostExecute() method inside your AsyncTask and you can set the adapter there normally. Add this code inside myserver2 class
#Override
protected void onPostExecute(String message) {
super.onPostExecute(message);
Adapter adptor=new Adapter(MainActivity.this,details);
ListView l= (ListView) findViewById(R.id.listview);
l.setAdapter(adptor);
}
and remove those 3 lines from your onCreate().
you can do this in asynctask Onpost() method
because some time network operation take time to get date but
Adapter adptor=new Adapter(this,details);
l.setAdapter(adptor);
since onPostExecute-Method from AsyncTask is called within your main UI-Thread, you can initialize you listview and adapter in onPostExecute-Method.
onPostExecute(Result), invoked on the UI thread after the background
computation finishes. The result of the background computation is
passed to this step as a parameter.
http://developer.android.com/reference/android/os/AsyncTask.html
#Override
protected void onPostExecute(String message) {
super.onPostExecute(message);
Adapter adptor=new Adapter(MainActivity.this,details);
ListView l= (ListView) findViewById(R.id.listview);
l.setAdapter(adptor);
}
do this in your oncreate method
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Adapter adptor=new Adapter(this,details);
ListView l= (ListView) findViewById(R.id.listview);
l.setAdapter(adptor);
new myserver2().execute("");
}
and add this method in your AsyncTask
#Override
protected void onPostExecute(String message) {
super.onPostExecute(message);
adpter.notifydatasetchanged()
}
Related
i have request in retrofit where return List which assign for my dataSet field. i did it in onResponse method. But initializing of recycle view in MainActivity is faster than request and view is showing nothing. What i can to do for waiting onResponse method.
I have this two methods in class NewsRepository.java
private void setNews(){
GetDataService service = RetrofitClientInstance.getRetrofitInstance().create(GetDataService.class);
Call<ItemsAPI> call = service.getAllItems();
call.enqueue(new Callback<ItemsAPI>() {
#Override
public void onResponse(Call<ItemsAPI> call, Response<ItemsAPI> response) {
Log.d(TAG, "onResponse");
items = response.body();
dataSet = items.getItems();
Log.d(TAG, dataSet.get(0).getTitle());
}
#Override
public void onFailure(Call<ItemsAPI> call, Throwable t) {
Log.d(TAG, "onFailure "+ t.getMessage());
}
});
}
public MutableLiveData<List<News>> getNews(){
setNews();
MutableLiveData<List<News>> data = new MutableLiveData<>();
data.setValue(dataSet);
return data;
}
And have this in MainActivityModelView.java
public void init(){
if(mNews != null){
return;
}
mRepo = NewsRepository.getInstance();
mNews = mRepo.getNews();
}
And this is MyActivity.java
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private RecyclerView mRecycleView;
private RecycleViewAdapter mAdapter;
private MainActivityViewModel mMainActivityViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecycleView = findViewById(R.id.recyclev_view);
mMainActivityViewModel = ViewModelProviders.of(this).get(MainActivityViewModel.class);
mMainActivityViewModel.init();
mMainActivityViewModel.getNews().observe((LifecycleOwner) this, new Observer<List<News>>() {
#Override
public void onChanged(#Nullable List<News> news) {
mAdapter.notifyDataSetChanged();
}
});
mMainActivityViewModel.getIsUpdating().observe((LifecycleOwner) this, new Observer<Boolean>() {
#Override
public void onChanged(#Nullable Boolean aBoolean) {
if(aBoolean){
}
else{
mRecycleView.smoothScrollToPosition(mMainActivityViewModel.getNews().getValue().size()-1);
}
}
});
initRecyclerView();
Log.d(TAG, "RecycleView is inited");
}
private void initRecyclerView(){
mAdapter = new RecycleViewAdapter(this, mMainActivityViewModel.getNews().getValue());
RecyclerView.LayoutManager linearLayoutManager = new LinearLayoutManager(this);
mRecycleView.setLayoutManager(linearLayoutManager);
mRecycleView.setAdapter(mAdapter);
}
}
The Activity is init is faster then my request.
2019-05-18 09:32:12.299 13859-13859/com.krasnov.rxjavalearning D/MainActivity: RecycleView is inited
2019-05-18 09:32:13.098 13859-13859/com.krasnov.rxjavalearning D/NewsRepository: onResponse
I think it's better to move this code above othre code below findViewById
initRecyclerView();
Log.d(TAG, "RecycleView is inited");
In this function its better to not use this constractor
mAdapter = new RecycleViewAdapter(this, mMainActivityViewModel.getNews().getValue());
Use this instead (create this constractor)
mAdapter = new RecycleViewAdapter(this);
And when your data arrive fire this function in adapter
public void setData( List<News> list) {
this.list= list
notifyDataSetChanged()
}
So your code is like
mMainActivityViewModel.getNews().observe((LifecycleOwner) this, new Observer<List<News>>() {
#Override
public void onChanged(#Nullable List<News> news) {
mAdapter.setData(news)
}
});
in your onResponse you should notify adapter add this:
yourAdapter.notifyDataSetChanged();
On resume call the retrofit service,
after response create a callback
method in ViewModel to notify in Activty class, after notified then
initialise recyclerview.
.
I am generating an ArrayList of Book Objects in my MainActivity using the function getBooks. But I am unable to get the ArrayList into my onCreate since everytime I access it in my onCreate I get an outofBounds exeception indicating that my list size is 0.
Also how do I send this list of objects through bundle. I actually tried parcelable but the savedinstancestate is always null in the onCreate of the fragment and the application halts.
public class MainActivity extends AppCompatActivity implements FragmentA.Communicator{
FragmentA f1;
FragmentB f2;
static ArrayList<Book> b = new ArrayList<Book>();
FragmentManager manager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getBooks();
Log.d("Main-Title",b.get(3).getTitle());
manager = getSupportFragmentManager();
f1 = (FragmentA) manager.findFragmentById(R.id.fragment);
f1.setCommunicator(this);
}
#Override
public void respond(int index) {
f2 = (FragmentB) manager.findFragmentById(R.id.fragment2);
if(f2!=null && f2.isVisible())
{
f2.changeData(index);
}
else
{
Bundle bundle = new Bundle();
bundle.putInt("index", index);
Fragment newFragment = new FragmentC();
newFragment.setArguments(bundle);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment, newFragment);
transaction.addToBackStack(null);
transaction.commit();
}
}
private void getBooks(){
String url = Book.API.BASE_URL;
//ArrayList<Book> boo;
Retrofit retrofit = new Retrofit.Builder().baseUrl(Book.API.BASE_URL).addConverterFactory(GsonConverterFactory.create()).build();
Book.API api = retrofit.create(Book.API.class);
Call<ArrayList<Book>> call = api.getBooks();
call.enqueue(new Callback<ArrayList<Book>>() {
#Override
public void onResponse(Call<ArrayList<Book>> call, Response<ArrayList<Book>> response) {
ArrayList<Book> Books = response.body();
for(Book h: Books){
Log.d("Title",h.getTitle());
b.add(h);
}
}
#Override
public void onFailure(Call<ArrayList<Book>> call, Throwable t) {
Toast.makeText(getApplicationContext(),t.getMessage(),Toast.LENGTH_SHORT).show();
}
});
}
}
You are trying to get data asynchronously, The getBooks() method doesn't stop until the data is retrieved. so your list is empty.
public void onCreate(){
getBooks();
//here b might be empty
}
public void afterGettingBooks(){
//here b will have retrieved data
}
private void getBooks(){
//code
call.enqueue(new Callback<ArrayList<Book>>() {
#Override
public void onResponse(Call<ArrayList<Book>> call, Response<ArrayList<Book>> response) {
//upadte b
afterGettingBooks();
}
}
#Override
public void onFailure(Call<ArrayList<Book>> call, Throwable t) {
}
});
}
I have a mind-boggling problem I can't seem to solve.
The data in my RecyclerView is not updating, and after an entire day of debugging, I can't find the problematic code. The API returns the correct data, and I parse the correct data in a wallItemList which I pass to the Adapter.
How It Should Behave
After changing the language setting to either one of the 2 (English or Dutch), the items in my Recyclerview should update with it and the title of the element should change to the translated string.
What I Have Tried
Creating a refresh function inside the adapter, and update the wallItemList manually by passing the created wallItemList from the MainActivity and calling notifyDataSetChanged()
Calling notifyDataSetChanged() before, in and after the OnClickListener in the MyRecyclerViewAdapter
Setting the item in onBindViewHolder in the MyRecyclerViewAdapter
Strangely enough, when logging the language of the wallItem just before adapter.setOnItemClickListener in populateRecyclerView(), the language is right. But when I get the string from the object in MyRecyclerViewAdapter's onBindViewHolder, it shows the wrong language.
Here is my MainActivity.java:
public class MainActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
private List<WallItem> WallItemList;
private RecyclerView mRecyclerView;
private MyRecyclerViewAdapter adapter;
private ProgressBar progressBar;
// LifeCycle variables
private String JSONResults = "";
final static private String JSON_KEY_RESULTS = "";
final static private String WALL_ITEM_LIST_KEY = "";
// SharedPrefences variables
private String APIUrlPreferenceString = "";
private String langPreferenceString = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
// Setup shared preferences
setupSharedPreferences();
// Load the recyclerView
loadRecyclerView(savedInstanceState);
}
private void setLanguageSettings(String lang)
{
//create a string for country
String country = "";
if(lang.equals("en"))
{
country = "EN";
}
else if(lang.equals("nl"))
{
country = "NL";
}
//use constructor with country
Locale locale = new Locale(lang, country);
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config,
getBaseContext().getResources().getDisplayMetrics());
}
private void setupSharedPreferences()
{
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
APIUrlPreferenceString = sharedPreferences.getString(getString(R.string.pref_api_url_key), getString(R.string.pref_api_url_def_value));
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
// Language settings
if(sharedPreferences.getBoolean(getString(R.string.pref_lang_check_key), true))
{
// Use device settings
setLanguageSettings(Resources.getSystem().getConfiguration().locale.getLanguage());
langPreferenceString = Resources.getSystem().getConfiguration().locale.getLanguage();
}
else
{
// Use preference settings
setLanguageSettings(sharedPreferences.getString(getString(R.string.pref_lang_list_key), getString(R.string.pref_lang_label_en)));
langPreferenceString = sharedPreferences.getString(getString(R.string.pref_lang_list_key), getString(R.string.pref_lang_label_en));
}
}
private void loadRecyclerView(Bundle savedInstanceState)
{
// Lifecycle event to preserve data to prevent repeating API calls
if(savedInstanceState != null && savedInstanceState.containsKey(WALL_ITEM_LIST_KEY) && savedInstanceState.containsKey(JSON_KEY_RESULTS))
{
progressBar.setVisibility(View.GONE);
// Set again in order to preserve state on future rotations
JSONResults = savedInstanceState.getString(JSON_KEY_RESULTS);
// Set wallItemList again in order to preserve state on future rotations
WallItemList = savedInstanceState.getParcelableArrayList(WALL_ITEM_LIST_KEY);
populateRecyclerView();
}
else
{
// First execution
new DownloadTask().execute();
}
}
public class DownloadTask extends AsyncTask<Void, Void, Boolean> {
#Override
protected void onPreExecute() {
progressBar.setVisibility(View.VISIBLE);
}
#Override
protected Boolean doInBackground(Void... params) {
boolean result;
String blindWallResults;
try {
// Error fix, because NetworkUtils.buildUrl returns null when failing
if(null == NetworkUtils.buildUrl(APIUrlPreferenceString))
return false;
// Get response from API
blindWallResults = NetworkUtils.getResponseFromHttpUrl(NetworkUtils.buildUrl(APIUrlPreferenceString));
// Send to parser
JSONResults = blindWallResults;
parseResult(blindWallResults);
result = true;
} catch (IOException e) {
e.printStackTrace();
result = false;
}
// When failed
return result;
}
#Override
protected void onPostExecute(Boolean result) {
progressBar.setVisibility(View.GONE);
// If succeeded
if (result) {
populateRecyclerView();
// Show toast when data has been loaded for the first time
Toast.makeText(MainActivity.this, getString(R.string.json_toast_data_loaded), Toast.LENGTH_SHORT).show();
} else {
// If failed make toast
Toast.makeText(MainActivity.this, getString(R.string.json_toast_data_failed), Toast.LENGTH_SHORT).show();
}
}
}
/**
* Populates recyclerView and adds OnItemClickListener
*/
private void populateRecyclerView()
{
WallItem w = WallItemList.get(0);
adapter = new MyRecyclerViewAdapter(MainActivity.this, WallItemList);
mRecyclerView.setAdapter(adapter);
adapter.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(WallItem item) {
// Function to start new activity
Class detailActivity = DetailActivity.class;
// Create intent
Intent startDetailActivityIntent = new Intent(MainActivity.this, detailActivity);
// Add object to intent
startDetailActivityIntent.putExtra("detailWallItem", (Parcelable)item);
// Start activity
startActivity(startDetailActivityIntent);
}
});
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Save instances of existing objects
outState.putString(JSON_KEY_RESULTS, JSONResults);
outState.putParcelableArrayList(WALL_ITEM_LIST_KEY, (ArrayList<? extends Parcelable>) this.WallItemList);
}
/**
* Parses JSON result
*
* #param result
*/
private void parseResult(String result) {
WallItemList = new ArrayList<>();
try {
JSONArray mJsonArray = new JSONArray(result);
// Loop through JSON array
for (int i = 0; i < mJsonArray.length(); i++) {
// Get picture URI fragment from JSON
String pictureURIFragment = mJsonArray.getJSONObject(i)
.getJSONArray("images").getJSONObject(0)
.getString("url");
// Load images into String
JSONArray JSONImageArray = mJsonArray.getJSONObject(i)
.getJSONArray("images");
// Create array for wallItem
String[] imageArray = new String[JSONImageArray.length()];
// Loop through JSONArray
for(int x = 0; x < JSONImageArray.length(); x++)
{
String pictureURLFragment = JSONImageArray.getJSONObject(x).getString("url");
// Built picture
URL pictureURL = NetworkUtils.builtPictureUrl(pictureURLFragment.toLowerCase());
imageArray[x] = java.net.URLDecoder.decode(pictureURL.toString());
}
// Built picture
URL pictureURL = NetworkUtils.builtPictureUrl(pictureURIFragment.toLowerCase());
String cleanPictureUrl = java.net.URLDecoder.decode(pictureURL.toString());
// add wall item to the list
WallItem item = new WallItem();
// Set fields of wallItem
item.setThumbnail(cleanPictureUrl);
item.setTitle(mJsonArray.getJSONObject(i).getString("author"));
item.setPhotographer(mJsonArray.getJSONObject(i).getString("photographer"));
item.setAddress(mJsonArray.getJSONObject(i).getString("address"));
item.setMaterial(mJsonArray.getJSONObject(i).getJSONObject("material").getString(langPreferenceString));
item.setDescription(mJsonArray.getJSONObject(i).getJSONObject("description").getString(langPreferenceString));
item.setImgURLArray(imageArray);
// Add wallItem to list
WallItemList.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId() == R.id.api_url_settings_item)
{
Intent startSettingsActivity = new Intent(this, SettingsActivity.class);
startActivity(startSettingsActivity);
return true;
}
return super.onOptionsItemSelected(item);
}
private void getDeviceLanguage()
{
Log.d("HERE", Locale.getDefault().getLanguage());
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if(key.equals(getString(R.string.pref_api_url_key)))
{
// Update String again
APIUrlPreferenceString = sharedPreferences.getString(getString(R.string.pref_api_url_key), getString(R.string.pref_api_url_def_value));
new DownloadTask().execute();
}
if(key.equals(getString(R.string.pref_lang_check_key)))
{
// 1. If true, use system language.
// 2. if System language != en or nl, use default language: en.
// 3. if false, make selectable
}
if(key.equals(getString(R.string.pref_lang_list_key)) || key.equals(getString(R.string.pref_lang_check_key)))
{
// Language settings
if(sharedPreferences.getBoolean(getString(R.string.pref_lang_check_key), true))
{
// Use device settings
setLanguageSettings(Resources.getSystem().getConfiguration().locale.getLanguage());
langPreferenceString = Resources.getSystem().getConfiguration().locale.getLanguage();
}
else
{
// Use preference settings
setLanguageSettings(sharedPreferences.getString(getString(R.string.pref_lang_list_key), getString(R.string.pref_lang_label_en)));
langPreferenceString = sharedPreferences.getString(getString(R.string.pref_lang_list_key), getString(R.string.pref_lang_label_en));
}
// Reload data after executing new Download task
new DownloadTask().execute();
this.recreate();
}
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
#Override
protected void onDestroy() {
super.onDestroy();
PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this);
}
}
Here is my MyRecyclerViewAdapter.java
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.CustomViewHolder> {
private List<WallItem> wallItemList;
private Context mContext;
private OnItemClickListener onItemClickListener;
public MyRecyclerViewAdapter(Context context, List<WallItem> wallItemList) {
this.wallItemList = wallItemList;
this.mContext = context;
WallItem w = wallItemList.get(0);
}
#Override
public CustomViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_row, null);
CustomViewHolder viewHolder = new CustomViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(CustomViewHolder customViewHolder, int i) {
final WallItem wallItem = wallItemList.get(i);
//Download image using picasso library
if (!TextUtils.isEmpty(wallItem.getThumbnail())) {
// Load image into imageView
Picasso.with(mContext).load(wallItem.getThumbnail())
.error(R.drawable.placeholder)
.placeholder(R.drawable.placeholder)
.into(customViewHolder.imageView);
}
//Setting text view title
customViewHolder.textView.setText(Html.fromHtml(wallItem.getMaterial()));
// Set OnClickListener to wallItem
View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View v) {
onItemClickListener.onItemClick(wallItem);
}
};
customViewHolder.imageView.setOnClickListener(listener);
customViewHolder.textView.setOnClickListener(listener);
}
// Overwrite to return
#Override
public int getItemCount() {
return (null != wallItemList ? wallItemList.size() : 0);
}
class CustomViewHolder extends RecyclerView.ViewHolder {
protected ImageView imageView;
protected TextView textView;
public CustomViewHolder(View view) {
super(view);
this.imageView = (ImageView) view.findViewById(R.id.thumbnail);
this.textView = (TextView) view.findViewById(R.id.title);
}
}
public OnItemClickListener getOnItemClickListener() {
return onItemClickListener;
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
}
My apologies for posting all the code but I can't identify the crucial points and don't have enough experience to pinpoint where it's going wrong. If anyone could help you would it would be greatly appreciated!
I suggest you to initialize and set the adapter in onCreate() method with an empty array of WallItems.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new MyRecyclerViewAdapter(MainActivity.this, new ArrayList<WallItem>());
mRecyclerView.setAdapter(adapter);
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
// Setup shared preferences
setupSharedPreferences();
// Load the recyclerView
loadRecyclerView(savedInstanceState);
}
To update the list of items, I normally have a setItems method inside my adapter that updates the list and calls notifyDataSetChanged()
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.CustomViewHolder> {
...
public void setItems(List<WallItem> items) {
this.wallItemList = wallItemList;
notifyDataSetChanged();
}
}
Your populateRecyclerView method then should call the setItems method to update the new list of items.
private void populateRecyclerView()
{
WallItem w = WallItemList.get(0);
adapter.setItems(WallItemList);
adapter.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(WallItem item) {
// Function to start new activity
Class detailActivity = DetailActivity.class;
// Create intent
Intent startDetailActivityIntent = new Intent(MainActivity.this, detailActivity);
// Add object to intent
startDetailActivityIntent.putExtra("detailWallItem", (Parcelable)item);
// Start activity
startActivity(startDetailActivityIntent);
}
});
}
I didn't test, buy this is how I normally use RecyclerView.
I've parsed some XML Data in Asynctask and printed it in the log, but whenever I try to copy the ArrayList of data into my Activity, it always remains null.
Here's the code,
public class MainActivity extends AppCompatActivity {
static ArrayList<NewsItems>myData=new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ReadRss readRss = new ReadRss(this);
readRss.execute();
Log.d("TAG", String.valueOf(myData.size()));//This stays empty
}
public static void getData(ArrayList<NewsItems>items){
for (int i=0; i<items.size(); i++){
myData.add(items.get(i));
}
}
class ReadRss extends AsyncTask<Void, Void, Void>{
ArrayList<NewsItems>feedItems = new ArrayList<>();
Context context;
String address = "http://www.thedailystar.net/frontpage/rss.xml";
ProgressDialog progressDialog;
URL url;
public ReadRss(Context context) {
this.context = context;
progressDialog = new ProgressDialog(context);
progressDialog.setMessage("Loading...");
}
#Override
protected void onPreExecute() {
if(progressDialog!=null){
if (!progressDialog.isShowing()){
progressDialog.show();
}
}
super.onPreExecute();
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if(progressDialog!=null){
if (progressDialog.isShowing()){
progressDialog.hide();
}
}
MainActivity.getData(feedItems);
}
#Override
protected Void doInBackground(Void... params) {
ProcessXml(Getdata());
return null;
}
private void ProcessXml(Document data) {
if (data != null) {
Element root = data.getDocumentElement();
Node channel = root.getChildNodes().item(1);
NodeList items = channel.getChildNodes();
for (int i = 0; i < items.getLength(); i++) {
Node currentchild = items.item(i);
if (currentchild.getNodeName().equalsIgnoreCase("item")) {
NewsItems item=new NewsItems();
NodeList itemchilds = currentchild.getChildNodes();
for (int j = 0; j < itemchilds.getLength(); j++) {
Node current = itemchilds.item(j);
if (current.getNodeName().equalsIgnoreCase("title")){
item.setTitle(current.getTextContent());
}else if (current.getNodeName().equalsIgnoreCase("description")){
item.setDescription(current.getTextContent());
}else if (current.getNodeName().equalsIgnoreCase("media:thumbnail")){
item.setMedia(current.getAttributes().getNamedItem("url").getTextContent());
}else if (current.getNodeName().equalsIgnoreCase("link")){
item.setUrl(current.getTextContent());
}
}
feedItems.add(item);
Log.d("itemTitle", item.getTitle());
Log.d("itemDescription",item.getDescription());
Log.d("itemMediaLink",item.getMedia());
Log.d("itemLink",item.getUrl());
}
}
}
}
public Document Getdata() {
try {
url = new URL(address);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
InputStream inputStream = connection.getInputStream();
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document xmlDoc = builder.parse(inputStream);
return xmlDoc;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
}
I tried calling a static method of the Activity in the onPostExecute method, it doesn't work.
1) You should declare the ArrayList variable as a member of mainActivity and then pass its reference into the Asynctask.
2) You can verify that the data is present in the list, only after you are sure the Asynctask has completed processing. (You can do that within the onPostExecute of the AsyncTask).
public class MainActivity extends AppCompatActivity {
ArrayList<NewsItems>myData=new ArrayList<>(); //No need for static
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ReadRss readRss = new ReadRss(this,myData); //Pass the list variable reference into the asynctask instance
readRss.execute();
Log.d("TAG", String.valueOf(myData.size()));//This will be empty due to concurrent call to asynctask, which executes parallel to main thread.
}
public void getData(ArrayList<NewsItems>items){//Static qualifier unneccessary here
for (int i=0; i<items.size(); i++){
myData.add(items.get(i));
}
}
class ReadRss extends AsyncTask<Void, Void, Void>{
ArrayList<NewsItems>feedItems = new ArrayList<>();
Context context;
String address = "http://www.thedailystar.net/frontpage/rss.xml";
ProgressDialog progressDialog;
URL url;
public ReadRss(Context context,ArrayList<NewsItems> feedItems) {
this.context = context;
this.feedItems = feedItems; //Assign the reference of the list here so that modifications done within the Asynctask are reflected in the MainActivity
progressDialog = new ProgressDialog(context);
progressDialog.setMessage("Loading...");
}
#Override
protected void onPreExecute() {
if(progressDialog!=null){
if (!progressDialog.isShowing()){
progressDialog.show();
}
}
super.onPreExecute();
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if(progressDialog!=null){
if (progressDialog.isShowing()){
progressDialog.hide();
}
}
//Do whatever you need with the arraylist data here
getData(feedItems);
}
#Override
protected Void doInBackground(Void... params) {
ProcessXml(Getdata());
return null;
}
Avoid static variables as much as possible. Unnecessary static fields land you into problems hard to understand.
If you are populating it in an AdapterView like ListView, remember to call adapter.notifyDataSetChanged() when you have the data set ready with you.
You can actually pass the result of your doInBackground() to onPostExecute() to continue doing your work on the calling thread, which is the main thread in your case.
new AsyncTask<Void, Void, ArrayList<NewsItems>>() {
#Override
protected ArrayList<NewsItems> doInBackground(Void... params) {
ArrayList<NewsItems> response = whatEverMethodGetsMeNetworkCallResponse();
return response;
}
#Override
protected void onPostExecute(ArrayList<NewsItems> response) {
super.onPostExecute(response);
// Do whatever you want to do with the network response
}
}.execute();
Or you can even set up listeners and do it in a more sophisticated way like:
onCreate() {
...
getNewsItems(new NewsItemsListener() {
void onFetched(ArrayList<NewsItems> items) {
// Do whatever you want to do with your news items
}
});
}
public void getNewsItems(final NewsItemsListener listener)
new AsyncTask<Void, Void, ArrayList<NewsItems>>() {
#Override
protected ArrayList<NewsItems> doInBackground(Void... params) {
ArrayList<NewsItems> response = whatEverMethodGetsMeNetworkCallResponse();
return response;
}
#Override
protected void onPostExecute(ArrayList<NewsItems> response) {
super.onPostExecute(response);
listener.onFetched(response);
}
}.execute();
}
public interface NewsItemsListener {
void onFetched(ArrayList<NewsItems> items);
}
I know this is a duplicate question but please hold on. I have read some similar questions and answer but none of them seems working for me.
What to do:
I have to do a search which will send a request to a web service and receive a response.
As i can't consume network on UI thread, I used AsyncTask.
What i tried:
I tried using task.execute() this returns immediately without even showing progressdialog box and i receive response as null (set in onPostExecute)
if i use task.execute.get() then it freezes screen and again no dialog box shows up (but i receive response correctly).
Below is my code with task.execute. Kindly correct me.
public class LookIn extends AppCompatActivity implements View.OnClickListener{
private Button btn=null;
private TextView txtPinCode=null;
private Service service=null;
private final static int timeout=20;
private String jsonResponse;
//private ProgressBar helperSearchProgressBar;
private String pincode="";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_look_in);
btn=(Button)findViewById(R.id.button);
btn.setOnClickListener(this);
txtPinCode=(TextView) findViewById(R.id.txtPinCode);
this.service=(Service) ParamFactory.getParam(ConstantLabels.SELECTED_SERVICE_ID);
// this.helperSearchProgressBar=(ProgressBar)findViewById(R.id.helperSearchProgressBar);
}
#Override
public void onClick(View v) {
String pincode= txtPinCode.getText().toString();
if(pincode==null || pincode.isEmpty() || pincode.length()!=6)
{
this.txtPinCode.setError("Please enter a 6 degit pin code from 700000 to 700200");
return;
}
ParamFactory.setParam(ConstantLabels.PINCODE_ID,pincode);
this.pincode=pincode;
loadHelper();
Intent intent= new Intent(LookIn.this,SearchResult.class);
startActivity(intent);
}
public void setJsonResponse(String jsonResponse)
{
this.jsonResponse=jsonResponse;
}
private void loadHelper()
{
Log.v("Callme", "Running thread:" + Thread.currentThread().getId());
ArrayAdapter<User> adapter=null;
String params=this.pincode+","+this.service.getId();
List<User> result=null;
try {
new CallmeGetHelperAsyncTask().execute(params); //my task.execute()
result= RestUtil.getUserList(jsonResponse);
adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, result);
ParamFactory.setParam("getHelperForService", adapter);
}
catch(JSONException x)
{
Log.e("Callme", Log.getStackTraceString(x));
}
}
class CallmeGetHelperAsyncTask extends AsyncTask<String,Void,String > {
// private Context context=null;
private ProgressDialog dialog=null;
private String jsonResponse;
private LookIn activity;
public CallmeGetHelperAsyncTask(){}
public CallmeGetHelperAsyncTask(LookIn activity)
{
this.activity=activity;
}
#Override
protected void onPreExecute() {
this.dialog= new ProgressDialog(LookIn.this);
this.dialog.setMessage("Loading...");
this.dialog.show();
Log.v("Callme","Dialog Shown");
}
#Override
protected void onPostExecute(String s) {
if(s!=null)
{
this.activity.setJsonResponse(s);
}
else
{
Log.v("Callme","kill me");
}
if(this.dialog.isShowing())
{
Log.v("Callme","Closing Dialog");
this.dialog.dismiss();
}
}
#Override
protected String doInBackground(String... params) {
Log.v("Callme","From Background:"+Thread.currentThread().getId());
String pincode=params.clone()[0].split(",")[0];
String serviceId=params.clone()[0].split(",")[1];
String url=String.format(URL.GET_HELPER,serviceId,pincode);
jsonResponse= null;
try {
jsonResponse = RestUtil.makeRestRequest(url);
} catch (IOException e) {
e.printStackTrace();
}
return jsonResponse;
}
}
}
Note: I haven't tried using while loop to waiting for the asynctask, because i think that will also end up freezing my screen. Please correct me if i am wrong
I haven't tried using while loop to waiting for the asynctask
No need to use loop for waiting AsyncTask Result.
Because onPostExecute method execute after doInBackground so instead of using jsonResponse just after call of execute method, do it inside setJsonResponse method, because this method called from onPostExecute which always run on Main UI Thread:
public void setJsonResponse(String jsonResponse)
{
this.jsonResponse=jsonResponse;
//Create adapter object here
result= RestUtil.getUserList(jsonResponse);
adapter = new ArrayAdapter(...);
ParamFactory.setParam("getHelperForService", adapter);
}