используйте moment.js из https://momentjs.com/ Посмотрите первые несколько примеров того, как использовать его для переформатирования дат.
Я собираюсь поделиться своим подходом к решению этой проблемы ротации. Это может не относиться к OP, поскольку он не использует AsyncTask
, но, возможно, другие найдут его полезным. Это довольно просто, но мне кажется, что эта работа мне подходит:
У меня есть вход в систему с вложенным классом AsyncTask
, который называется BackgroundLoginTask
.
В моем BackgroundLoginTask
я не делаю ничего необычного, кроме добавления нулевой проверки при вызове dismiss ProgressDialog
:
@Override
protected void onPostExecute(Boolean result)
{
if (pleaseWaitDialog != null)
pleaseWaitDialog.dismiss();
[...]
}
Это для обработки случая, когда Фоновое задание завершается, пока Activity
не виден, и поэтому диалоговое окно прогресса уже закрыто методом onPause()
.
Затем, в моем родительском классе Activity
, я создаю глобальные статические дескрипторы для моего класса AsyncTask
и моего ProgressDialog
(будучи вложенным, AsyncTask
может обращаться к этим переменным):
private static BackgroundLoginTask backgroundLoginTask;
private static ProgressDialog pleaseWaitDialog;
Это служит двум целям: во-первых, это позволяет my Activity
всегда получать доступ к объекту AsyncTask
даже из новой, пост-повернутой деятельности. Во-вторых, он позволяет моему BackgroundLoginTask
получать доступ и отклонять ProgressDialog
даже после поворота.
Затем я добавляю это к onPause()
, в результате чего диалоговое окно прогресса исчезает, когда наш Activity
покидает передний план (предотвращая это безобразное «принудительное закрытие» сбоя):
if (pleaseWaitDialog != null)
pleaseWaitDialog.dismiss();
Наконец, У меня есть следующее в моем методе onResume()
:
if ((backgroundLoginTask != null) && (backgroundLoginTask.getStatus() == Status.RUNNING))
{
if (pleaseWaitDialog != null)
pleaseWaitDialog.show();
}
Это позволяет Dialog
снова появляться после воссоздания Activity
.
Вот весь класс:
public class NSFkioskLoginActivity extends NSFkioskBaseActivity {
private static BackgroundLoginTask backgroundLoginTask;
private static ProgressDialog pleaseWaitDialog;
private Controller cont;
// This is the app entry point.
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (CredentialsAvailableAndValidated())
{
//Go to main menu and don't run rest of onCreate method.
gotoMainMenu();
return;
}
setContentView(R.layout.login);
populateStoredCredentials();
}
//Save current progress to options when app is leaving foreground
@Override
public void onPause()
{
super.onPause();
saveCredentialsToPreferences(false);
//Get rid of progress dialog in the event of a screen rotation. Prevents a crash.
if (pleaseWaitDialog != null)
pleaseWaitDialog.dismiss();
}
@Override
public void onResume()
{
super.onResume();
if ((backgroundLoginTask != null) && (backgroundLoginTask.getStatus() == Status.RUNNING))
{
if (pleaseWaitDialog != null)
pleaseWaitDialog.show();
}
}
/**
* Go to main menu, finishing this activity
*/
private void gotoMainMenu()
{
startActivity(new Intent(getApplicationContext(), NSFkioskMainMenuActivity.class));
finish();
}
/**
*
* @param setValidatedBooleanTrue If set true, method will set CREDS_HAVE_BEEN_VALIDATED to true in addition to saving username/password.
*/
private void saveCredentialsToPreferences(boolean setValidatedBooleanTrue)
{
SharedPreferences settings = getSharedPreferences(APP_PREFERENCES, MODE_PRIVATE);
SharedPreferences.Editor prefEditor = settings.edit();
EditText usernameText = (EditText) findViewById(R.id.editTextUsername);
EditText pswText = (EditText) findViewById(R.id.editTextPassword);
prefEditor.putString(USERNAME, usernameText.getText().toString());
prefEditor.putString(PASSWORD, pswText.getText().toString());
if (setValidatedBooleanTrue)
prefEditor.putBoolean(CREDS_HAVE_BEEN_VALIDATED, true);
prefEditor.commit();
}
/**
* Checks if user is already signed in
*/
private boolean CredentialsAvailableAndValidated() {
SharedPreferences settings = getSharedPreferences(APP_PREFERENCES,
MODE_PRIVATE);
if (settings.contains(USERNAME) && settings.contains(PASSWORD) && settings.getBoolean(CREDS_HAVE_BEEN_VALIDATED, false) == true)
return true;
else
return false;
}
//Populate stored credentials, if any available
private void populateStoredCredentials()
{
SharedPreferences settings = getSharedPreferences(APP_PREFERENCES,
MODE_PRIVATE);
settings.getString(USERNAME, "");
EditText usernameText = (EditText) findViewById(R.id.editTextUsername);
usernameText.setText(settings.getString(USERNAME, ""));
EditText pswText = (EditText) findViewById(R.id.editTextPassword);
pswText.setText(settings.getString(PASSWORD, ""));
}
/**
* Validate credentials in a seperate thread, displaying a progress circle in the meantime
* If successful, save credentials in preferences and proceed to main menu activity
* If not, display an error message
*/
public void loginButtonClick(View view)
{
if (phoneIsOnline())
{
EditText usernameText = (EditText) findViewById(R.id.editTextUsername);
EditText pswText = (EditText) findViewById(R.id.editTextPassword);
//Call background task worker with username and password params
backgroundLoginTask = new BackgroundLoginTask();
backgroundLoginTask.execute(usernameText.getText().toString(), pswText.getText().toString());
}
else
{
//Display toast informing of no internet access
String notOnlineMessage = getResources().getString(R.string.noNetworkAccessAvailable);
Toast toast = Toast.makeText(getApplicationContext(), notOnlineMessage, Toast.LENGTH_SHORT);
toast.show();
}
}
/**
*
* Takes two params: username and password
*
*/
public class BackgroundLoginTask extends AsyncTask<Object, String, Boolean>
{
private Exception e = null;
@Override
protected void onPreExecute()
{
cont = Controller.getInstance();
//Show progress dialog
String pleaseWait = getResources().getString(R.string.pleaseWait);
String commWithServer = getResources().getString(R.string.communicatingWithServer);
if (pleaseWaitDialog == null)
pleaseWaitDialog= ProgressDialog.show(NSFkioskLoginActivity.this, pleaseWait, commWithServer, true);
}
@Override
protected Boolean doInBackground(Object... params)
{
try {
//Returns true if credentials were valid. False if not. Exception if server could not be reached.
return cont.validateCredentials((String)params[0], (String)params[1]);
} catch (Exception e) {
this.e=e;
return false;
}
}
/**
* result is passed from doInBackground. Indicates whether credentials were validated.
*/
@Override
protected void onPostExecute(Boolean result)
{
//Hide progress dialog and handle exceptions
//Progress dialog may be null if rotation has been switched
if (pleaseWaitDialog != null)
{
pleaseWaitDialog.dismiss();
pleaseWaitDialog = null;
}
if (e != null)
{
//Show toast with exception text
String networkError = getResources().getString(R.string.serverErrorException);
Toast toast = Toast.makeText(getApplicationContext(), networkError, Toast.LENGTH_SHORT);
toast.show();
}
else
{
if (result == true)
{
saveCredentialsToPreferences(true);
gotoMainMenu();
}
else
{
String toastText = getResources().getString(R.string.invalidCredentialsEntered);
Toast toast = Toast.makeText(getApplicationContext(), toastText, Toast.LENGTH_SHORT);
toast.show();
}
}
}
}
}
Я ни в коем случае не опытный разработчик Android, поэтому не стесняйтесь комментировать.
Если вы создадите фон Service
, который выполняет всю тяжелую работу (запросы / ответы tcp, демаршаллинг), View
и Activity
могут быть уничтожены и воссозданы без утечки окна или потерять данные. Это позволяет поведение, рекомендованное Android, которое заключается в уничтожении активности при каждом изменении конфигурации (например, для каждого изменения ориентации).
Это немного сложнее, но это лучший способ для вызова запроса к серверу, предварительной / пост-обработки данных и т. Д.
Вы можете даже использовать Service
для постановки каждого запроса в очередь на сервер, поэтому с ним легко и эффективно справляться.
В руководстве разработчика есть полная глава , посвященная Services
.
Service
больше работы, чем AsyncTask
, но может быть лучший подход в некоторых ситуациях. Это не обязательно лучше, не так ли? Однако я don' t понимают, как это решает проблему ProgressDialog
, который пропущен от основного Activity
. Где делают Вас instanciate ProgressDialog
? Где Вы отклоняете его?
– rds
05.05.2020, 02:29
Первоначальная проблема заключалась в том, что код не выдерживал изменения ориентации экрана. По-видимому, это было «решено», когда программа сама обрабатывала изменение ориентации экрана, а не позволяла каркасу пользовательского интерфейса (через вызов onDestroy)).
Я бы сказал, что если основная проблема заключается в том, что программа не выживет в Destroy (), то принятое решение - это просто обходной путь, который оставляет программу с другими серьезными проблемами и уязвимостями. Помните, что платформа Android специально заявляет, что ваша деятельность может быть уничтожена практически в любое время из-за обстоятельств, не зависящих от вас. Таким образом, ваша деятельность должна быть в состоянии выжить в onDestroy () и последующих onCreate () по любой причине, а не только в изменении ориентации экрана.
Если вы собираетесь самостоятельно обрабатывать изменения ориентации экрана для решения проблемы OP, вам необходимо убедиться, что другие причины onDestroy () не приводят к той же ошибке. Вы можете сделать это? Если нет, я бы спросил, действительно ли «принятый» ответ очень хороший.
Я придумал надежное решение для этих проблем, которое соответствует «Android Way» вещей. У меня есть все мои длительные операции с использованием шаблона IntentService.
То есть, моя деятельность передает намерения, IntentService выполняет работу, сохраняет данные в БД и затем передает липкие намерения. Важная часть важна, так что даже если действие было приостановлено в течение времени после того, как пользователь начал работу и пропускает трансляцию в реальном времени от IntentService, мы все равно можем ответить и забрать данные из вызывающего действия. ProgressDialog
с этим паттерном вполне могут работать с onSaveInstanceState()
.
По сути, вам нужно сохранить флаг, что у вас есть запущенный диалог в сохраненном экземпляре пакета. Не сохраняйте объект диалога прогресса, потому что это приведет к утечке всей активности. Чтобы иметь постоянный дескриптор диалога прогресса, я храню его как слабую ссылку в объекте приложения. В случае изменения ориентации или чего-либо еще, что приводит к приостановке действия (телефонный звонок, пользователь попадает домой и т. Д.), А затем возобновляется, я закрываю старый диалог и заново создаю новый диалог во вновь созданном действии.
Для неопределенных диалогов прогресса это легко. Для стиля индикатора выполнения вы должны поместить в пакет последний известный прогресс и любую информацию, которую вы используете локально в упражнении, чтобы отслеживать прогресс. При восстановлении прогресса вы будете использовать эту информацию, чтобы повторно вызывать индикатор выполнения в том же состоянии, что и раньше, а затем обновлять его в зависимости от текущего состояния.
Итак, подведем итог: размещение длительных задач в IntentService в сочетании с разумным использованием onSaveInstanceState()
позволяет эффективно отслеживать диалоги и затем восстанавливать их в событиях жизненного цикла Activity. Соответствующие биты кода активности приведены ниже. Вам также понадобится логика в BroadcastReceiver для надлежащей обработки намерений Sticky, но это выходит за рамки этого.
public void doSignIn(View view) {
waiting=true;
AppClass app=(AppClass) getApplication();
String logingon=getString(R.string.signon);
app.Dialog=new WeakReference<ProgressDialog>(ProgressDialog.show(AddAccount.this, "", logingon, true));
...
}
@Override
protected void onSaveInstanceState(Bundle saveState) {
super.onSaveInstanceState(saveState);
saveState.putBoolean("waiting",waiting);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState!=null) {
restoreProgress(savedInstanceState);
}
...
}
private void restoreProgress(Bundle savedInstanceState) {
waiting=savedInstanceState.getBoolean("waiting");
if (waiting) {
AppClass app=(AppClass) getApplication();
ProgressDialog refresher=(ProgressDialog) app.Dialog.get();
refresher.dismiss();
String logingon=getString(R.string.signon);
app.Dialog=new WeakReference<ProgressDialog>(ProgressDialog.show(AddAccount.this, "", logingon, true));
}
}
Если вы боретесь с обнаружением событий изменения ориентации в диалоге НЕЗАВИСИМО ОТ ССЫЛКИ О ДЕЯТЕЛЬНОСТИ , этот метод работает потрясающе хорошо. Я использую это, потому что у меня есть свой собственный класс диалога, который может отображаться в нескольких различных действиях, поэтому я не всегда знаю, в каком действии он отображается. С этим методом вам не нужно изменять AndroidManifest, беспокойтесь о ссылках на действия, и вам не нужен пользовательский диалог (как у меня). Тем не менее, вам нужен пользовательский вид контента, чтобы вы могли обнаружить изменения ориентации, используя этот конкретный вид. Вот мой пример:
public class MyContentView extends View{
public MyContentView(Context context){
super(context);
}
@Override
public void onConfigurationChanged(Configuration newConfig){
super.onConfigurationChanged(newConfig);
//DO SOMETHING HERE!! :D
}
}
Dialog dialog = new Dialog(context);
//set up dialog
dialog.setContentView(new MyContentView(context));
dialog.show();
AlertDialog.Builder builder = new AlertDialog.Builder(context);
//set up dialog builder
builder.setView(new MyContentView(context)); //Can use this method
builder.setCustomTitle(new MycontentView(context)); // or this method
builder.build().show();
ProgressDialog progress = new ProgressDialog(context);
//set up progress dialog
progress.setView(new MyContentView(context)); //Can use this method
progress.setCustomTitle(new MyContentView(context)); // or this method
progress.show();
Самое простое и гибкое решение - использовать AsyncTask со статической ссылкой на ProgressBar . Это обеспечивает инкапсулированное и, следовательно, многоразовое решение проблем изменения ориентации. Это решение хорошо мне помогло для решения различных асинхронных задач, включая загрузку через Интернет, обмен данными с Сервисами и сканирование файловой системы. Решение было хорошо протестировано на нескольких версиях Android и моделях телефонов. Полная демонстрация может быть найдена здесь с особым интересом к DownloadFile.java
Я представляю следующее в качестве примера концепции
public class SimpleAsync extends AsyncTask<String, Integer, String> {
private static ProgressDialog mProgressDialog = null;
private final Context mContext;
public SimpleAsync(Context context) {
mContext = context;
if ( mProgressDialog != null ) {
onPreExecute();
}
}
@Override
protected void onPreExecute() {
mProgressDialog = new ProgressDialog( mContext );
mProgressDialog.show();
}
@Override
protected void onPostExecute(String result) {
if ( mProgressDialog != null ) {
mProgressDialog.dismiss();
mProgressDialog = null;
}
}
@Override
protected void onProgressUpdate(Integer... progress) {
mProgressDialog.setProgress( progress[0] );
}
@Override
protected String doInBackground(String... sUrl) {
// Do some work here
publishProgress(1);
return null;
}
public void dismiss() {
if ( mProgressDialog != null ) {
mProgressDialog.dismiss();
}
}
}
Использование в Android Активность проста
public class MainActivity extends Activity {
DemoServiceClient mClient = null;
DownloadFile mDownloadFile = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.main );
mDownloadFile = new DownloadFile( this );
Button downloadButton = (Button) findViewById( R.id.download_file_button );
downloadButton.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
mDownloadFile.execute( "http://www.textfiles.com/food/bakebred.txt");
}
});
}
@Override
public void onPause() {
super.onPause();
mDownloadFile.dismiss();
}
}
Я более свежий в Android, и я попробовал это, и это сработало.
public class loadTotalMemberByBranch extends AsyncTask<Void, Void,Void> {
ProgressDialog progressDialog = new ProgressDialog(Login.this);
int ranSucess=0;
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
progressDialog.setTitle("");
progressDialog.isIndeterminate();
progressDialog.setCancelable(false);
progressDialog.show();
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
}
@Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
return null;
}
@Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
progressDialog.dismiss();
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
}
}
Я пробовал ВСЕ. Провел дни экспериментов. Я не хотел блокировать вращение активности. Мой сценарий был:
Проблема заключалась в том, что при повороте экрана каждое решение в книге не удавалось. Даже с классом AsyncTask, который является правильным способом Android для решения этих ситуаций. При повороте экрана текущий контекст, с которым работает начальный поток, исчезает, и это портится в отображаемом диалоговом окне. Проблема всегда была в диалоге, независимо от того, сколько трюков я добавил в код (передача нового контекста запущенным потокам, сохранение состояний потоков посредством вращений и т. Д.). Сложность кода в конце всегда была огромной, и всегда было что-то, что могло пойти не так.
Единственное решение, которое сработало для меня, это трюк «Активность / Диалог». Это просто и гениально, и все это доказательство вращения:
Вместо того, чтобы создавать диалог и просить показать его, создайте действие, которое было установлено в манифесте с android: theme = "@ Android: стиль / Theme.Dialog». Так что это просто похоже на диалог.
Замените showDialog (DIALOG_ID) на startActivityForResult (yourActivityDialog, yourCode);
Используйте onActivityResult в вызывающем Activity для получения результатов из выполняющегося потока (даже ошибок) и обновите пользовательский интерфейс.
В «ActivityDialog» используйте потоки или AsyncTask для выполнения длинных задач и onRetainNonConfigurationInstance для сохранения «диалогового» состояния при повороте экрана.
Это быстро и отлично работает. Я все еще использую диалоги для других задач и AsyncTask для чего-то, что не требует постоянного диалога на экране. Но в этом сценарии я всегда использую шаблон «Активность / Диалог».
И я не пробовал, но даже можно заблокировать вращение Activity / Dialog во время работы потока, ускоряя процесс, одновременно позволяя вызывающему Activity вращаться.
Intent
, который более строг, чем эти Object
позволенный AsyncTask
– rds
05.05.2020, 02:38
this.val()
. Этот ответ ужасен.:-) – David Murdoch 05.03.2014, 09:22