I'm new to Fragments, and I have an problem with pressing back in some fragments.
MainActivity.java
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.drawer_main);
//Fragments are added programmatically here...
LoginFragment fragment = new LoginFragment();
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
android.support.v4.app.FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.add(R.id.content_frame, fragment);
transaction.commit();
}
#Override
public void onBackPressed() {
android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
Fragment curFrag;
curFrag = (Fragment) fm.findFragmentByTag("keuzen");
if (curFrag.isVisible() || curFrag.getTag() == "keuzen") {
Toast.makeText(getBaseContext(), "much keuzen", Toast.LENGTH_SHORT).show();
//keuzenFrag = null;
}
//Fragment curFrag = ((FragmentManager) fm.getFragments()).findFragmentByTag("single");
curFrag = (Fragment) fm.findFragmentByTag("single");
if (curFrag.isVisible()) {
Toast.makeText(getBaseContext(), "very single", Toast.LENGTH_SHORT).show();
}
}
I do not do anything with onBackPressed in the Fragments.
The wierd thing is, that only one Fragment with Async code, which crashes when I hit the back button.
But when I go to a other Fragment, and then back to the Fragment with Async code, and press the back button, it crashes.
The Async code in the fragment Fragment2
/**
* Async task class to get json by making HTTP call
* */
private class GetKeuzes extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// Showing progress dialog
pDialog = new ProgressDialog(getActivity()); //KeuzenActivity.this
pDialog.setMessage("Laden...");
pDialog.setCancelable(false);
pDialog.show();
}
#Override
protected Void doInBackground(Void... arg0) {
// Creating service handler class instance
ServiceHandler sh = new ServiceHandler();
// Making a request to url and getting response
String jsonStr = sh.makeServiceCall(url , ServiceHandler.GET);
Log.d("Response: ", "> " + jsonStr);
if (jsonStr != null) {
try {
JSONObject jsonObj = new JSONObject(jsonStr);
// Getting JSON Array node
docent_opties = jsonObj.getJSONArray("docent_opties");
// loop door alle keuzes heen uit de JSON
for (int i = 0; i < docent_opties.length(); i++) {
JSONObject c = docent_opties.getJSONObject(i);
naam_cursus = c.getString(TB_naam_cursus);
naam_locatie = c.getString(TB_naam_locatie);
datum_vol = c.getString(TB_datum_vol);
naam_dagdeel = c.getString(TB_naam_dagdeel);
// Phone node is JSON Object
//JSONObject phone = c.getJSONObject(TAG_PHONE);
//String mobile = phone.getString(TAG_PHONE_MOBILE);
//String home = phone.getString(TAG_PHONE_HOME);
//String office = phone.getString(TAG_PHONE_OFFICE);
// temp HashMap voor enkele keuze
HashMap<String, String> keuze = new HashMap<String, String>();
// adding each child node to HashMap key => value
keuze.put(TB_naam_cursus, naam_cursus);
keuze.put(TB_naam_locatie, naam_locatie);
keuze.put(TB_datum_vol, datum_vol);
keuze.put(TB_naam_dagdeel, naam_dagdeel);
keuze.put("datum_dagdeel", datum_vol + ", '" + naam_dagdeel + "'");
keuzenList.add(keuze);
}
} catch (JSONException e) {
e.printStackTrace();
}
} else {
Log.e("ServiceHandler", "Gegevens ophalen via de url is mislukt");
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// Dismiss the progress dialog
if (pDialog.isShowing())
pDialog.dismiss();
/**
* Updating parsed JSON data into ListView
* */
ListAdapter adapter = new SimpleAdapter(
getActivity(), keuzenList,
R.layout.list_item, new String[] { TB_naam_cursus, TB_naam_locatie, "datum_dagdeel" }, new int[]
{ R.id.naamcursus, R.id.locatie, R.id.datum });
setListAdapter(adapter);
}
}
However, even when removing the Async code from the Fragment, the same problem still occurs...
So it shouldn't be the Async code.
This is the logcat:
http://pastebin.com/J5VhhCLG
Try using the FragmentManager's findFragmentById() or findFragmentByTag() methods, fragment Tag is your issue.
How are you adding the fragment:
FragmentTransaction.add(int containerViewId, Fragment fragment, String tag) ?
Remember fragment transaction runs asynchronously, make sure the tag is set.
Yes, its "find" not get, sorry about that.
The awnser was in the fact that I tried opening a other fragment from a fragment.
What you should do is make a function in your MainActivity:
public void openSesame(Bundle bundle) {
//Method2: pass data to fragment directly.
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
KeuzenFragment keuzenFragment = new KeuzenFragment();
keuzenFragment.setArguments(bundle);
android.support.v4.app.FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.content_frame, keuzenFragment, "keuzen").addToBackStack("keuzen");
transaction.remove(fragment1);
transaction.commit();
}
You probably want to change it up a bit for use with Fragments in the overload.
But that function goes in your MainActivity.
Call that function from the MainActivity like this:
((MainActivity)getActivity()).openSesame(bundle);
Done. :)
Related
I am calling rest API which gets access token from salesforce. after I make a rest call to get data from Salesforce and I'm successfully getting records. and all records are shown in android activity list view.
after that I call fragment but fragment view is not showing.
if I'm not making rest call then fragment show properly.
Here is the MainActivity class
public class MainActivity extends AppCompatActivity {
DrawerLayout dLayout;
private ArrayAdapter<String> listAdapter;
ProgressDialog progressDialog;
JSONTokener tokener;
String accessToken_, instanceURL_;
JSONArray finalResult;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setNavigationDrawer(); // call method
// button_save_account = (Button) findViewById(R.id.button_save_account);
accessToken_ = "00D7F000005oJve!ARUAQPJ8hMWibtO1flIPjZfzV4A__Kzj6wTjJ5XA_xE1zbqDs_0fOTZuxJFiLVxsFx_kNPxuNNK6c7yREtbxq4J7W1oWuUEs";
instanceURL_ = "https://harishgakhar40-dev-ed.my.salesforce.com";
// Create list adapter
listAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, new ArrayList<String>());
((ListView) findViewById(R.id.contacts_list)).setAdapter(listAdapter);
try {
MyAsyncTasks myAsyncTasks = new MyAsyncTasks();
myAsyncTasks.execute(accessToken_, instanceURL_).get();
} catch (Exception e) {
}
}
private void setNavigationDrawer() {
dLayout = (DrawerLayout) findViewById(R.id.drawer_layout); // initiate a DrawerLayout
NavigationView navView = (NavigationView) findViewById(R.id.navigation); // initiate a Navigation View
navView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
Fragment frag = null; // create a Fragment Object
int itemId = menuItem.getItemId(); // get selected menu item's id
if (itemId == R.id.first) {
frag = new InsertRecords();
Bundle bundle = new Bundle();
bundle.putString("access token", accessToken_);
bundle.putString("instanc url", instanceURL_);
frag.setArguments(bundle);
} else if (itemId == R.id.second) {
Log.v("fragment second ---- ", "In Fragment Second ---- ");
frag = new SecondFragment();
} else if (itemId == R.id.third) {
frag = new ThirdFragment();
}
Toast.makeText(getApplicationContext(), menuItem.getTitle(), Toast.LENGTH_SHORT).show();
if (frag != null) {
Log.v("frag ---- ", "frag ------ " + frag);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Log.v("transaction ---- ", "transaction ------ " + frag);
transaction.replace(R.id.frame, frag); // replace a Fragment with Frame Layout
transaction.commit(); // commit the changes
dLayout.closeDrawers(); // close the all open Drawer Views
return true;
}
return false;
}
});
}
public class MyAsyncTasks extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// display a progress dialog for good user experiance
progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setMessage("Please Wait");
progressDialog.setCancelable(false);
progressDialog.setMessage("Loading...");
progressDialog.show();
}
#Override
protected String doInBackground(String... params) {
String accessToken = params[0];
String instanceURL = params[1];
// implement API in background and store the response in current variable
String result = "";
DefaultHttpClient client = new DefaultHttpClient();
String url = instanceURL + "/services/data/v20.0/query/?q=";
String soqlQuery = "Select Id, Name, BillingStreet, BillingCity, BillingState From Account Limit 10 ";
try {
url += URLEncoder.encode(soqlQuery, "UTF-8");
} catch (UnsupportedEncodingException e) {
}
HttpGet getRequest = new HttpGet(url);
getRequest.addHeader("Authorization", "OAuth " + accessToken);
Log.v("Token in doin ---- ", "accessToken ---- in doin ---- " + accessToken);
Log.v("instanceURL doin ---- ", "instanceURL ---- in doin ---- " + instanceURL);
try {
HttpResponse response = client.execute(getRequest);
result = EntityUtils.toString(response.getEntity());
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
#Override
protected void onPostExecute(String result) {
try {
progressDialog.dismiss();
// dismiss the progress dialog after receiving data from API
JSONObject object = (JSONObject) new JSONTokener(result).nextValue();
JSONArray records = object.getJSONArray("records");
// globalState.setAccountNames(new String[records.length()]);
// globalState.setAccounts(new JSONObject[records.length()]);
listAdapter.clear();
for (int i = 0; i < records.length(); i++) {
JSONObject record = (JSONObject) records.get(i);
String accountName = record.getString("Name");
Log.v("accountName---- ", "accountName ---- " + accountName);
listAdapter.add(accountName);
// globalState.getAccountNames()[i] = accountName;
//globalState.getAccounts()[i] = record;
}
} catch (Exception e) {
}
Log.d("data", result.toString());
}
}
}
You are blocking MainThread which is rendering UI.
To avoid this, android provides AsyncTask.
BUT make yourself and others working on your project favor and use Retrofit or other libraries. It will save you so much time and make your code cleaner.
Here you can find a good article.
If you really don't feel like using Retrofit, AsyncTask is an option too
You need to call your getAccountData function inside an AsyncTask. The implementation right now is blocking your UI thread, which created the problem I think.
public class GetAccountData implements AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
// Get account data here.
}
#Override
protected void onPostExecute(final String accountName) {
// Pass the accountName to the calling Activity here.
}
// Implement other methods if you need
}
If you are confused about how you can pass the data from your AsyncTask to your Activity, please consider looking into this answer here.
I have a problem with my activity. It work well for the first time i start but after that is crashed with this
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1842)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1860)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:650)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:609)
I try add this to my activity but it not working
#Override
protected void onSaveInstanceState(Bundle outState) {
//No call for super(). Bug on API Level > 11.
}
When i use commitAllowingStateLoss() instead of commit() for changing Fragment the error now is Activity has been destroy. I have to close the app. I dont know why it run only in the first time of the activity is called.
Here is my function to change the fragment
private void showWaitingFragment() {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
WaitingFragment fragment = new WaitingFragment();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
private void showAnswerFragment() {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
AnswerFragment fragment = new AnswerFragment();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
First i call showWattingFragment after the server emit event on socket i call showAnswerFragment.
The code for socket
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.d("socket_log", "connected");
}
}).on("quizQuestionReady", new Emitter.Listener() {
#Override
public void call(Object... args) {
showWaitingFragment();
}
}).on("quizQuestionLoaded", new Emitter.Listener() {
#Override
public void call(Object... args) {
showAnswerFragment();
}
}).on("quizEnded", new Emitter.Listener() {
#Override
public void call(Object... args) {
showResultFragment();
}
}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {}
});
socket.connect();
As I said before this worked for the first time i start the activity, not working after i call onBackPress() or finish() then startActivity again
UPDATE my activity
public class StudentQuizActivity extends AppCompatActivity {
#BindView(R.id.quiz_content_frame)
FrameLayout _frame_content;
public Socket socket;
String quiz_code;
public SharedPreferences prefs;
ProgressDialog progressDialog;
int user_id;
String token;
public int currentQuestionIndex = -1;
public int currentQuestionIndexForShowing = 0;
public int countCorrect = 0;
public boolean no_answer = true;
public ArrayList<String> answers;
public ArrayList<String> correct_answers;
public ArrayList<Boolean> corrects;
public JSONObject quizConfig;
public JSONArray quizQuestions;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_student_quiz);
prefs = new SecurePreferences(this);
quiz_code = prefs.getString(AppVariable.QUIZ_CODE, null);
user_id = prefs.getInt(AppVariable.USER_ID, 0);
token = prefs.getString(AppVariable.USER_TOKEN, null);
ButterKnife.bind(this);
this.setTitle("QUIZ");
// prepare spinner
progressDialog = new ProgressDialog(this, R.style.AppTheme_Dark_Dialog);
progressDialog.setIndeterminate(true);
progressDialog.setCanceledOnTouchOutside(false);
prefs.edit().putString(AppVariable.QUIZ_MESSAGE, "Waiting for the quiz to start").apply();
answers = new ArrayList<>();
correct_answers = new ArrayList<>();
corrects = new ArrayList<>();
setSocket();
new GetQuizTask().execute();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
//No call for super(). Bug on API Level > 11.
}
//UI
private void showWaitingFragment() {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
WaitingFragment fragment = new WaitingFragment();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
private void showAnswerFragment() {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
AnswerFragment fragment = new AnswerFragment();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
private void showResultFragment() {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ResultFragment fragment = new ResultFragment();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
public void showDetailFragment() {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
DetailFragment fragment = new DetailFragment();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
#Override
public void onBackPressed() {
super.onBackPressed();
}
private class GetQuizTask extends AsyncTask<String, Void, Integer> {
private Exception exception;
private String strJsonResponse;
#Override
protected void onPreExecute() {
progressDialog.setMessage("Loading...");
progressDialog.show();
}
#Override
protected Integer doInBackground(String... params) {
int flag = 0;
try {
URL url = new URL(Network.API_GET_QUIZ);
//prepare json data
JSONObject jsonUserData = new JSONObject();
jsonUserData.put("token", token);
jsonUserData.put("quiz_code", quiz_code);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
try {
connection.setReadTimeout(10000);
connection.setConnectTimeout(15000);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setRequestProperty("Accept", "application/json");
connection.setDoInput(true);
connection.setDoOutput(true);
//write
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.write(jsonUserData.toString());
writer.flush();
//check http response code
int status = connection.getResponseCode();
switch (status){
case HttpURLConnection.HTTP_OK:
//read response
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
sb.append(line).append("\n");
}
bufferedReader.close();
strJsonResponse = sb.toString();
flag = HttpURLConnection.HTTP_OK;
default:
exception = new Exception(connection.getResponseMessage());
}
}
finally{
connection.disconnect();
}
}
catch(Exception e) {
exception = e;
}
return flag;
}
#Override
protected void onPostExecute(Integer status) {
if (status != HttpURLConnection.HTTP_OK){
displayToast(exception.getMessage());
}
else {
try{
JSONObject jsonObject = new JSONObject(strJsonResponse);
String result = jsonObject.getString("result");
if (result.equals("failure")){
String message = jsonObject.getString("message");
progressDialog.dismiss();
displayToast(message);
return;
}
quizConfig = jsonObject.getJSONObject("quiz");
quizQuestions = quizConfig.getJSONArray("questions");
prefs.edit().putInt(AppVariable.QUIZ_TOTAL, quizQuestions.length())
.putString(AppVariable.QUIZ_TITLE, quizConfig.getString("title")).apply();
progressDialog.dismiss();
showWaitingFragment();
return;
} catch (JSONException e) {
e.printStackTrace();
displayToast(e.getMessage());
}
}
progressDialog.dismiss();
}
}
//Socket
private void setSocket(){
if (Network.isOnline(this)){
try {
socket = IO.socket(Network.HOST);
} catch (URISyntaxException e) {
e.printStackTrace();
}
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.d("socket_log", "connected");
}
}).on("quizQuestionReady", new Emitter.Listener() {
#Override
public void call(Object... args) {
currentQuestionIndexForShowing += 1;
prefs.edit().putString(AppVariable.QUIZ_MESSAGE, "Ready for the next question")
.putInt(AppVariable.QUIZ_INDEX, currentQuestionIndexForShowing).apply();
showWaitingFragment();
}
}).on("quizQuestionLoaded", new Emitter.Listener() {
#Override
public void call(Object... args) {
currentQuestionIndex += 1;
showAnswerFragment();
}
}).on("quizQuestionEnded", new Emitter.Listener() {
#Override
public void call(Object... args) {
}
}).on("quizEnded", new Emitter.Listener() {
#Override
public void call(Object... args) {
prefs.edit()
.putInt(AppVariable.QUIZ_INDEX, 0).apply();
showResultFragment();
}
}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {}
});
socket.connect();
}
}
public void emitAnswer(String option){
JSONObject payload = new JSONObject();
try {
payload.put("quiz_code", quiz_code);
payload.put("question_index", currentQuestionIndex);
payload.put("option", option);
payload.put("student_id", user_id);
} catch (JSONException e) {
e.printStackTrace();
}
no_answer = false;
try {
JSONObject quizDetail = quizQuestions.getJSONObject(currentQuestionIndex);
String correct_option = quizDetail.getString("correct_option");
ArrayList<String> options = new ArrayList<>();
options.add(quizDetail.getString("option_a"));
options.add(quizDetail.getString("option_b"));
options.add(quizDetail.getString("option_c"));
options.add(quizDetail.getString("option_d"));
String[] keys = {"a", "b", "c", "d"};
for (int i = 0; i < 4; i++){
if (correct_option.equals(options.get(i))){
correct_option = keys[i];
break;
}
}
if (option.equals(correct_option)){
corrects.add(true);
countCorrect += 1;
}
else {
corrects.add(false);
}
correct_answers.add(correct_option);
} catch (JSONException e) {
e.printStackTrace();
}
answers.add(option);
socket.emit("answeredQuiz", payload);
}
}
There are many things need to check inside your code. Let take a look one by one.
Inner class GetQuizTask
This is an API request task which could take much time. By default, if everything ok, AsyncTask will help you handle it in background, then post the result in UI thread.
In your onPostExecute(Integer status), you implicit call showWaitingFragment() which is the same as this.showWaitingFragment().
That means you are holding a parent reference inside your inner class. This could lead you to memory leak. Example: If your request takes 10 seconds to finish, but before onPostExecute() called, what happens if your activity is destroyed or change its state before 10 seconds? (There are many things could make you activity change, like you call finish(), rotate the screen, System have to clean memory, User press Home button, etc...). So when these things happen, the activity (or this in this. showWaitingFragment()) can't be collected by garbage collection). That leads you to the memory leak.
One more thing. If your activity changed from foreground to background (user press Home button), the onPostExecute needs to perform showFragment in UI thread, which can't be done right now, what happens then?
Those errors will give you the IllegalStateException.
Solution: Using WeakPreference, something like this:
private class GetQuizTask extends AsyncTask<String, Void, Integer> {
WeakReference<StudentQuizActivity> studentQuizActivity;
#Override
protected void onPreExecute() {
// do your work before the task execute..
}
#Override
protected Integer doInBackground(String... params) {
// do your work in background..
}
#Override
protected void onPostExecute(Integer status) {
try{
if (studentQuizActivity.get() != null) {
studentQuizActivity.get().showInfo();
}
} catch (Exception e) {
}
}
}
Avoid boilerplate codes
There are many functions to show fragment, which can simplify like this
private void showFragment(Fragment fragment) {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
Then
showFragment(yourResultFragment);
showFragment(yourTransactionFragment);
Before using dismiss for ProgressDialog, check if (progressDialog.isShowing()). Because user can dismiss it before onPostExecute() performing.
Please, decouple your code. Don't push everything inside your inner class. It will easily lead you to tons of errors. One more thing, if there is no special use-case, try to use the static inner class instead. Follow this answers.
I can't detect all your mistake because I don't get your situation, but I wish this helps! Rewrite your code, carefully, one by one.
This is very simple.
You should use commitAllowingStateLoss() instead of commit()
transaction.commitAllowingStateLoss();
After switching to sdk24, I have a problem.
read json php application, but no longer updated. You must give closure forces her to reread.
before I used to refresh and update listfragment perfect. not now.
I give I add new information is added to the database, or you can delete, but the application does not update.
code json reader + inserd + deleted + refresh:
public class playlist_torrent extends ListFragment {
Main2Activity activity= (Main2Activity) getActivity();
private ProgressDialog pDialog;
// URL to get contacts JSON
private static String url = "http://vrt.ro/remote/index-torrent.php?token=";
// JSON Node names
private static final String TAG_ID = "id";
private static final String TAG_NAME = "name";
private static final String TAG_IMAGE = "image";
private static final String TAG_ADDRESS = "address";
String POPUP_LOGIN_TITLE;
String POPUP_LOGIN_TEXT;
String EMAIL_HINT;
String PASSWORD_HINT;
// contacts JSONArray
JSONArray contacts = null;
// Hashmap for ListView
ArrayList<HashMap<String, String>> contactList;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.activity_playlist_torrent, container, false);
POPUP_LOGIN_TITLE=getActivity().getString(R.string.text_titlu_insert_stream_playlist);
POPUP_LOGIN_TEXT=getActivity().getString(R.string.text_completeaza_datele);
EMAIL_HINT=getActivity().getString(R.string.name_torrent);
PASSWORD_HINT=getActivity().getString(R.string.magnet_torrent);
final FloatingActionButton actionA = (FloatingActionButton) v.findViewById(R.id.action_a);
actionA.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View view) {
actionA.setTitle(getActivity().getString(R.string.text_add_new_url));
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
alert.setTitle(POPUP_LOGIN_TITLE);
alert.setMessage(POPUP_LOGIN_TEXT);
// Set an EditText view to get user input
final EditText name = new EditText(getActivity());
name.setHint(EMAIL_HINT);
final EditText url_streaming = new EditText(getActivity());
url_streaming.setHint(PASSWORD_HINT);
LinearLayout layout = new LinearLayout(getActivity().getApplicationContext());
layout.setOrientation(LinearLayout.VERTICAL);
layout.addView(name);
layout.addView(url_streaming);
alert.setView(layout);
alert.setPositiveButton(getActivity().getString(R.string.ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
if (url_streaming.getText().toString().compareToIgnoreCase("") == 0) {
Snackbar.make(view, R.string.error_url_emty_playlist, Snackbar.LENGTH_LONG).show();
return;
}
new Thread() {
public void run() {
try {
HttpURLConnection.setFollowRedirects(false);
// note : you may also need
//HttpURLConnection.setInstanceFollowRedirects(false)
Bundle args = getArguments();
String token = args.getString("token");
String name_streaming = name.getText().toString();
String Url_streaming = url_streaming.getText().toString();
HttpURLConnection con = (HttpURLConnection) new URL("http://vrt.ro/remote/insert-torrent.php?token="+token+"&nume="+name_streaming+"&url="+Url_streaming).openConnection();
con.setRequestMethod("HEAD");
if(con.getResponseCode() == HttpURLConnection.HTTP_OK) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.detach(playlist_torrent.this).attach(playlist_torrent.this).commit();
// Reload current fragment
}
else{
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
});
alert.setNegativeButton(getActivity().getString(R.string.cancel), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Canceled.
}
});
alert.show();
}
});
final FloatingActionButton actionB = (FloatingActionButton) v.findViewById(R.id.action_b);
actionB.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
actionB.setTitle(getActivity().getString(R.string.refresh_done));
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.detach(playlist_torrent.this).attach(playlist_torrent.this).commit();
}
});
return v;
}
#Override
public void onViewCreated (View view, Bundle savedInstanceState) {
contactList = new ArrayList<HashMap<String, String>>();
ListView lv = getListView();
// Listview on item click listener
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, final View view,
int position, long id) {
// getting values from selected ListItem
final String description = ((TextView) view.findViewById(R.id.mobile)).getText().toString();
final String id_stream = ((TextView) view.findViewById(R.id.id_streaming)).getText().toString();
// Starting single contact activity
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AppCompatAlertDialogStyle);
builder.setTitle("Select");
// builder.setMessage("Lorem ipsum dolor ....");
builder.setItems(new CharSequence[]
{getString(R.string.play_video), getString(R.string.remove_video)},
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// The 'which' argument contains the index position
// of the selected item
switch (which) {
case 0:
TorrentPlayerFragment fragment3 = new TorrentPlayerFragment();
fragment3.onDestroyView();
FragmentTransaction fragmentTransaction3 = getFragmentManager().beginTransaction();
Bundle args = new Bundle();
args.putString("url", description);
fragment3.setArguments(args);
fragmentTransaction3.addToBackStack(null);
//getFragmentManager().popBackStack();
fragmentTransaction3.remove(fragment3);
fragmentTransaction3.replace(R.id.frame,fragment3);
fragmentTransaction3.commit();
//----
break;
case 1:
// Snack Bar
Snackbar bar = Snackbar.make(view, R.string.confirm_delete_playlist, Snackbar.LENGTH_LONG)
.setAction(R.string.yes, new View.OnClickListener() {
#Override
public void onClick(View v) {
// ---Control remote api---
new Thread() {
public void run() {
try {
HttpURLConnection.setFollowRedirects(false);
// note : you may also need
//HttpURLConnection.setInstanceFollowRedirects(false)
HttpURLConnection con = (HttpURLConnection) new URL("http://vrt.ro/remote/delete-torrent.php?id="+id_stream).openConnection();
con.setRequestMethod("HEAD");
if(con.getResponseCode() == HttpURLConnection.HTTP_OK) {
//--refresh fragment
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.detach(playlist_torrent.this).attach(playlist_torrent.this).commit();
//Fin refresh fragment
// startActivity(getIntent());
// finish();
/* final Handler handler = new Handler();
Runnable refresh = new Runnable() {
#Override
public void run() {
new onPreExecute().execute();
handler.postDelayed(this, 60 * 1000);
}
};
handler.postDelayed(refresh, 60 * 1000); */
}
else{
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}.start();
// ----fin Control remote api----
}
});
bar.show();
break;
}
}
});
builder.create().show();
}
});
// Calling async task to get json
new GetContacts().execute();
}
public static void createDirectory(File dir) throws IllegalStateException{
if (!dir.exists()){
if(!dir.mkdirs()){
throw new IllegalStateException(
"Check if you've added permissions in AndroidManifest.xml: \n" +
"<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/> \n"
);
}
}
}
/**
* Async task class to get json by making HTTP call
*
* */
private class GetContacts extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// Showing progress dialog
pDialog = new ProgressDialog(getActivity());
pDialog.setMessage("Please wait...");
pDialog.setCancelable(false);
pDialog.show();
}
#Override
protected Void doInBackground(Void... arg0) {
// Creating service handler class instance
ServiceHandler sh = new ServiceHandler();
// Bundle bundle = getActivity().getIntent().getExtras();
//String token = bundle.getString("id");
Bundle args = getArguments();
String myString = args.getString("token");
// Making a request to url and getting response
String jsonStr = sh.makeServiceCall(url+myString, ServiceHandler.GET);
Log.d("Response: ", "> " + jsonStr);
if (jsonStr != null) {
try {
JSONObject jsonObj = new JSONObject(jsonStr);
// Getting JSON Array node
contacts = jsonObj.getJSONArray(myString);
// looping through All Contacts
for (int i = 0; i < contacts.length(); i++) {
JSONObject c = contacts.getJSONObject(i);
String id = c.getString(TAG_ID);
String name = c.getString(TAG_NAME);
String image = c.getString(TAG_IMAGE);
String address = c.getString(TAG_ADDRESS);
// tmp hashmap for single contact
HashMap<String, String> contact = new HashMap<String, String>();
// adding each child node to HashMap key => value
contact.put(TAG_ID, id);
contact.put(TAG_NAME, name);
contact.put(TAG_IMAGE, image);
contact.put(TAG_ADDRESS, address);
// adding contact to contact list
contactList.add(contact);
}
} catch (JSONException e) {
e.printStackTrace();
}
} else {
Log.e("ServiceHandler", "Couldn't get any data from the url");
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// Dismiss the progress dialog
if (pDialog.isShowing())
pDialog.dismiss();
/**
* Updating parsed JSON data into ListView
* */
ListAdapter adapter = new SimpleAdapter(
getActivity(), contactList,
R.layout.list_item, new String[]{TAG_NAME, TAG_ID,
TAG_ADDRESS}, new int[]{R.id.name, R.id.id_streaming, R.id.mobile});
setListAdapter(adapter);
}
}
}
This is the code from refresh:
//--refresh fragment
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.detach(playlist_torrent.this).attach(playlist_torrent.this).commit();
//Fin refresh fragment
please help. thank you.
Edit:
if you leave an interval of a few minutes and refresh it goes. but only one time. as if the connection remains open and no longer responds.
Fixed this problem from changed ngix from apache2 and now is work fine.
I'm fighting with this for a week, without luck.
From the begining:
There is an Activity with Navigation Drawer included. This activity has it's own fragments. Fragments have logic to send requests to a weather api and logic to update themselves with given data. At the first run everything seems to work fine! I'm able to send request and fill views with given data (using okHttp).
Everything is starting to collapse after fragments recreations, I'm getting constantly getActivity() to be null ;(
Code Sample below:
Fragments first initialisation:
public abstract class DoubleFragmentActivity extends AppCompatActivity {
protected static final String TOP_FRAGMENT = "TOP_FRAGMENT";
protected static final String BOTTOM_FRAGMENT = "BOTTOM_FRAGMENT";
protected abstract Fragment topFragment();
protected abstract Fragment bottomFragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_container);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.topFragmentContainer, topFragment(), TOP_FRAGMENT)
.add(R.id.bottomFragmentContainer, bottomFragment(), BOTTOM_FRAGMENT)
.commit();
getSupportFragmentManager().executePendingTransactions();
}
}
}
Navigation Drawer:
private void selectDrawerItem(MenuItem menuItem) {
Fragment f;
Fragment f2;
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
switch (menuItem.getItemId()) {
case R.id.forecastFragment:
f = getSupportFragmentManager().findFragmentByTag("TOP_FRAGMENT");
f2 = getSupportFragmentManager().findFragmentByTag("BOTTOM_FRAGMENT");
if (f != mCurrentForecastFragment || f2 != mDailyForecastFragment) {
ft.replace(R.id.topFragmentContainer, new CurrentForecastFragment(), "TOP_FRAGMENT");
ft.replace(R.id.bottomFragmentContainer, new DailyForecastFragment(), "BOTTOM_FRAGMENT");
} else {
}
break;
case R.id.settingsFragment:
mToolbar.setVisibility(View.INVISIBLE);
f = new SettingsFragment();
ft.replace(R.id.topFragmentContainer, f);
break;
case R.id.paymentsFragment:
f = new PaymentsFragment();
ft.replace(R.id.topFragmentContainer, f);
break;
case R.id.aboutFragment:
break;
default:
}
getSupportFragmentManager().executePendingTransactions();
ft.commit();
menuItem.setChecked(true);
setTitle(menuItem.getTitle());
mDrawer.closeDrawers();
}
Fragment`s logic for connecting and fullfilling data:
public void makeConnectionToApi(String lat, String lon) {
mWeatherParams.setLanguage(Locale.getDefault().getLanguage());
Activity a = getActivity();
Uri.Builder currentBuilder = new Uri.Builder();
currentBuilder.scheme("http")
.authority("api.openweathermap.org")
.appendPath("data")
.appendPath("2.5")
.appendPath("weather")
.appendQueryParameter(WeatherConstants.KEY_LATITUDE, lat)
.appendQueryParameter(WeatherConstants.KEY_LONGITUDE, lon)
.appendQueryParameter(WeatherConstants.KEY_UNITS, mUnit)
.appendQueryParameter(WeatherConstants.KEY_LANGUAGE, mWeatherParams.getLanguage())
.appendQueryParameter("APPID", "###");
String currentUrl = currentBuilder.build().toString();
if (mUtility.isNetworkAvalaible()) {
Request requestCurrent = new Request.Builder().url(currentUrl).build();
//FIRST CALL
mCall = client.newCall(requestCurrent);
mCall.enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
Bundle args = new Bundle();
args.putString(TAG, e.toString());
Utility.invokeDialog(TAG, e.toString(), getFragmentManager());
}
#Override
public void onResponse(Response response) throws IOException {
String responseBody = String.valueOf(response.body().string());
try {
mForecast.setCurrent(fetchCurrent(responseBody));
} catch (JSONException e) {
e.printStackTrace();
}
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
fillViewWithValues();
}
});
}
});
} else {
Utility.invokeDialog(TAG, "Check your internet connection!", getFragmentManager());
}
}
private Current fetchCurrent(String responseBody) throws JSONException {
Current current = new Current();
JSONObject jo = new JSONObject(responseBody);
//FETCH WEATHER ARRAY
JSONArray weather = jo.getJSONArray(WeatherConstants.KEY_CURRENT_CONDITIONS_ARRAY);
for (int j = 0; j < weather.length(); j++) {
JSONObject weatherParser = weather.getJSONObject(j);
current.setIcon(weatherParser.getString(WeatherConstants.KEY_ICON_ID));
Log.i(TAG, "Icons ID: " + weatherParser.getString(WeatherConstants.KEY_ICON_ID));
current.setConditions(weatherParser.getString(WeatherConstants.KEY_DESCRIPTION));
}
//FETCH TEMP
JSONObject temp = jo.getJSONObject(WeatherConstants.KEY_MAIN_OBJECT);
current.setDay(temp.getDouble(WeatherConstants.KEY_TEMP));
current.setPressure(temp.getDouble(WeatherConstants.KEY_PRESSURE));
current.setHumidity(temp.getDouble(WeatherConstants.KEY_HUMIDITY));
current.setDayMax(temp.getDouble(WeatherConstants.KEY_TEMP_DAY_MAX));
// FETCH VISIBILITY
if (jo.has(WeatherConstants.KEY_VISIBILITY)) {
current.setVisibility(jo.getInt(WeatherConstants.KEY_VISIBILITY));
}
//FETCH WIND
JSONObject wind = jo.getJSONObject(WeatherConstants.KEY_WIND_OBJECT);
current.setWindSpeed(wind.getDouble(WeatherConstants.KEY_WIND_SPEED));
if (wind.has(WeatherConstants.KEY_WIND_DEGREES)) {
current.setWindDegrees(wind.getInt(WeatherConstants.KEY_WIND_DEGREES));
}
JSONObject clouds = jo.getJSONObject(WeatherConstants.KEY_CLOUDS);
current.setClouds(clouds.getInt("all"));
current.setTimeStamp(jo.getInt(WeatherConstants.KEY_TIMESTAMP));
current.setCurrentLocation(jo.getString(WeatherConstants.KEY_CITY_NAME));
return current;
}
private void fillViewWithValues() {
Current current = mForecast.getCurrent();
if (mDeegreSwitch == 0) {
mCurrentTemperature.setText(current.getDay() + "\u00B0");
// setBackgroundColor(current.getDay());
} else {
int c = current.getDay();
double f = (9.0 / 5.0) * c + 32;
int e = (int) Math.round(f);
mCurrentTemperature.setText(String.valueOf((int) Math.round(f)) + "\u00B0");
// setBackgroundColor(e);
}
mCurrentCondition.setText(current.getConditions());
mPressure.setText(String.valueOf(current.getPressure()) + "hPa");
mClouds.setText(String.valueOf(current.getClouds()) + "%");
mHumidity.setText(String.valueOf(current.getHumidity()) + "%");
mCurrentIcon.setImageResource(current.getIcon());
}
Problems occurs here: getActivity().runOnUiThread inside makeConnectionToApi method. I've tried to fetch an activity from onAttach method and pass it makeConnectionToApi as parameter, it worked...but partially. App didn't crash but fragment`s view was not updated, like there was a second fragment underneath or something.
I have filling it might be something with threads or I'm doing sth wrong with fragments transaction...
I have an listview that contacts a web service whenever it is called and this is what it looks like
public class ListView extends ListActivity {
ArrayList<HashMap<String, String>> questionList;
final String TAG_DATA_WEB = "data";
private String stringxxx;
ProgressDialog pDialog;
LoadAllData mTask;
JSONArray question = null;
android.widget.ListView lv;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.listview);
stringxxx = getIntent().getStringExtra("TAG_SEARCH");
questionList = new ArrayList<HashMap<String, String>>();
mTask = new LoadAllData();
mTask.execute();
}
#Override
protected void onListItemClick(android.widget.ListView l, View v, int pos, long id) {
super.onListItemClick(l, v, pos, id);
HashMap<String, String> item = questionList.get(pos);
Intent i = new Intent(ListView.this, SingleListItem.class);
i.putExtra(TAG_DATA_WEB, item.get(TAG_DATA_WEB));
startActivity(i);
}
#Override
public void onBackPressed()
{
/** If user Pressed BackButton While Running Asynctask
this will close the ASynctask.
*/
if (mTask != null && mTask.getStatus() != AsyncTask.Status.FINISHED)
{
mTask.cancel(true);
}
super.onBackPressed();
Intent i = new Intent(ListView.this, PREV.class);
startActivity(i);
finish();
}
#Override
protected void onDestroy() {
if (mTask != null && mTask.getStatus() != AsyncTask.Status.FINISHED)
{
mTask.cancel(true);
}
super.onDestroy();
}
#Override
protected void onPause() {
if (pDialog != null)
{
if(pDialog.isShowing())
{
pDialog.dismiss();
}
super.onPause();
}
}
class LoadAllData extends AsyncTask<String, Void, JSONObject> {
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(ListView.this);
pDialog.setMessage("Loading Data. Please wait...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
#Override
protected JSONObject doInBackground(String... args) {
pDialog.setOnCancelListener(new DialogInterface.OnCancelListener(){
public void onCancel(DialogInterface dialog) {
mTask.cancel(true);
Intent i = new Intent(ListView.this, PREV.class);
startActivity(i);
finish();
}
});
JSONObject json = new JSONObject();
try {
String query = URLEncoder.encode(searchTerm, "utf-8");
String URL = "http://example.com";
JSONParsser jParser = new JSONParsser();
json = jParser.readJSONFeed(URL);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return json;
}
#Override
protected void onPostExecute(JSONObject json) {
try {
JSONArray questions = json.getJSONObject("all").getJSONArray("questions");
for(int i = 0; i < DT.length(); i++) {
JSONObject question = DT.getJSONObject(i);
String data = question.getString(TAG_DATA_WEB);
HashMap<String, String> map = new HashMap<String, String>();
map.put(TAG_DATA_WEB, data);
questionList.add(map);
pDialog.dismiss();
ListAdapter adapter = new SimpleAdapter(getBaseContext(), questionList,
R.layout.listelements,
new String[] { TAG_DATA_WEB }, new int[] {
R.id.Subject,});
setListAdapter(adapter);
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
The problem I have is that when I click on an item on the listview to go to the next activity, it does as its suppose too with no problem its just when I pressed the back button to go back the listview, the listview activity restarts and it also contacts the web service again to retrieve the information like as if I put finish(); after startArtivity(I); in the onItemClick part of the code. Now normally this wouldn't be a problem if you web service didn't have a search limit but the one i am using does. So basically what Im saying is that when the user clicks on an listview item to go to the next activity and when they press the onBack button, I want the information to still be there instead of the application contacting the web service again to retrieve information and the end result will be the search limit being reached. Can anybody help me with this?
I have used XML parsing so I can probably give you help logically.
You can use bean class with get and set methods and store the results
you get from web service.
Use Set methods to store the values where you have written the
parsing code.
Use get methods in your activity's adapter code to retrieve those
values.
This way web service won't be called again when you reach that
activity using back button.
But remember, if you launch that activity with service again from its parent, web service will be called again.
You would have several options:
Replace the AsyncTask data loading with an AsyncTaskLoader data loading. Check the Loader developer article first. I dropped using AsyncTasks for data loading long time ago...
The scond option is to store the data you receive and don't call the webservice next time. For this, store the data somehow in onSaveInstanceState and in onCreate check if Bundle parameter is not null and if you have data set there for th same key you used in onSaveInstanceState. If true, you already have the data. If false, query.
Depending on data importance and volatility you could save it once in some kind of app persistence (shared preference or sqlite) once you downloaded it and use it every time the activity recreates or creates itself.