Этот ответ может быть запоздалым, но я хотел бы упомянуть несколько вещей, когда ваш Activity
зависит от AsyncTask
. Это поможет вам предотвратить сбои и управление памятью. Как уже упоминалось в приведенных выше ответах, переходите к interface
, мы также говорим, что они обратные вызовы. Они будут работать как информатор, но никогда не будут отправлять ссылки Activity
или interface
всегда использовать слабую ссылку в этих случаях.
Пожалуйста, обратитесь к скриншоту ниже, чтобы узнать, как это может вызвать проблемы.
Как вы можете видеть, начали ли мы AsyncTask
с сильной ссылки, тогда нет гарантии, что наш Activity
/ Fragment
будет до тех пор, пока мы не получим данные, поэтому было бы лучше использовать WeakReference
в этих случаях, и это также поможет в управлении памятью, поскольку мы никогда не будем придерживаться сильной ссылки на наш Activity
, тогда он будет иметь право на сбор мусора после его искажения.
Проверьте ниже фрагмент кода, чтобы узнать, как использовать awesome WeakReference -
MyTaskInformer.java
Интерфейс, который будет работать как информатор.
public interface MyTaskInformer {
void onTaskDone(String output);
}
MySmallAsyncTask.java
AsyncTask выполняет длительную задачу, которая будет использовать WeakReference
.
public class MySmallAsyncTask extends AsyncTask {
// ***** Hold weak reference *****
private WeakReference mCallBack;
public MySmallAsyncTask(MyTaskInformer callback) {
this.mCallBack = new WeakReference<>(callback);
}
@Override
protected String doInBackground(String... params) {
// Here do whatever your task is like reading/writing file
// or read data from your server or any other heavy task
// Let us suppose here you get response, just return it
final String output = "Any out, mine is just demo output";
// Return it from here to post execute
return output;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
// Here you can't guarantee that Activity/Fragment is alive who started this AsyncTask
// Make sure your caller is active
final MyTaskInformer callBack = mCallBack.get();
if(callBack != null) {
callBack.onTaskDone(s);
}
}
}
MainActivity.java
Этот класс используется для запуска моего AsyncTask
реализации interface
в этом классе и override
этот обязательный метод.
public class MainActivity extends Activity implements MyTaskInformer {
private TextView mMyTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMyTextView = (TextView) findViewById(R.id.tv_text_view);
// Start your AsyncTask and pass reference of MyTaskInformer in constructor
new MySmallAsyncTask(this).execute();
}
@Override
public void onTaskDone(String output) {
// Here you will receive output only if your Activity is alive.
// no need to add checks like if(!isFinishing())
mMyTextView.setText(output);
}
}
Пересматривая этот вопрос, я теперь 'обнаружил' 5 различных способов сделать это, которые являются следующие:
System.ComponentModel.DesignMode property
System.ComponentModel.LicenseManager.UsageMode property
private string ServiceString()
{
if (GetService(typeof(System.ComponentModel.Design.IDesignerHost)) != null)
return "Present";
else
return "Not present";
}
public bool IsDesignerHosted
{
get
{
Control ctrl = this;
while(ctrl != null)
{
if((ctrl.Site != null) && ctrl.Site.DesignMode)
return true;
ctrl = ctrl.Parent;
}
return false;
}
}
public static bool IsInDesignMode()
{
return System.Reflection.Assembly.GetExecutingAssembly()
.Location.Contains("VisualStudio"))
}
Чтобы попытаться получить подвешивание на этих трех предложенных решениях, я создал немного тестового решения - с тремя проектами:
Я затем встроил SubSubControl в SubControl, затем один из каждого в TestApp. Форма.
Этот снимок экрана показывает результат при выполнении.
Этот снимок экрана показывает результат с формой, открытой в Visual Studio:
Заключение: казалось бы, что без отражения единственным, которое надежно в конструкторе, является LicenseUsage, и единственным, который надежен вне конструктора, является 'IsDesignedHosted' (BlueRaja ниже)
PS: См. комментарий ToolmakerSteve ниже (который я не протестировал): "Обратите внимание, что ответ IsDesignerHosted был обновлен для включения LicenseUsage..., поэтому теперь тест может просто быть то, если (IsDesignerHosted). Альтернативный подход является тестом LicenseManager в конструкторе, и кэшируйте результат".
Почему Вы не проверяете LicenseManager. UsageMode. Это свойство может иметь значения LicenseUsageMode. Время выполнения или LicenseUsageMode. Время проектирования.
Вы, хотят, чтобы код только работал во времени выполнения, использовал следующий код:
if (LicenseManager.UsageMode == LicenseUsageMode.Runtime)
{
bla bla bla...
}
DesignMode является частной собственностью (от того, что я могу сказать). Ответ должен обеспечить общественную собственность, которая представляет опору DesignMode. Тогда Вы можете cascasde создавать резервную копию цепочки пользовательских элементов управления, пока Вы не сталкиваетесь с управлением лица, не использующего своего права или управлением, которое находится в режиме проектирования. Что-то вроде этого....
public bool RealDesignMode()
{
if (Parent is MyBaseUserControl)
{
return (DesignMode ? true : (MyBaseUserControl) Parent.RealDesignMode;
}
return DesignMode;
}
, Где все Ваши UserControls наследовались MyBaseUserControl. Кроме того, Вы могли реализовать интерфейс, который представляет "RealDeisgnMode".
обратите внимание, что этот код не является живым кодом, рядом с размышлениями манжеты.:)
Я никогда не был пойман этим сам, но не могли, Вы просто идти создаете резервную копию Родительской цепочки от управления, чтобы видеть, установлен ли DesignMode где-нибудь выше Вас?
Я не понял, что Вы не можете назвать Родителя. DesignMode (и я учился, что-то о 'защищенном' в C# также...)
Вот отражающая версия: (Я подозреваю, что могло бы быть преимущество производительности для создания designModeProperty статическое поле)
static bool IsDesignMode(Control control)
{
PropertyInfo designModeProperty = typeof(Component).
GetProperty("DesignMode", BindingFlags.Instance | BindingFlags.NonPublic);
while (designModeProperty != null && control != null)
{
if((bool)designModeProperty.GetValue(control, null))
{
return true;
}
control = control.Parent;
}
return false;
}
От эта страница :
( [Edit 2013] Отредактировано для работы в конструкторах с использованием метода, предоставленного @hopla)
/// <summary>
/// The DesignMode property does not correctly tell you if
/// you are in design mode. IsDesignerHosted is a corrected
/// version of that property.
/// (see https://connect.microsoft.com/VisualStudio/feedback/details/553305
/// and http://stackoverflow.com/a/2693338/238419 )
/// </summary>
public bool IsDesignerHosted
{
get
{
if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
return true;
Control ctrl = this;
while (ctrl != null)
{
if ((ctrl.Site != null) && ctrl.Site.DesignMode)
return true;
ctrl = ctrl.Parent;
}
return false;
}
}
Я отправил ошибку - отчет с Microsoft; Я сомневаюсь, что он куда-то пойдет, но все равно проголосуйте за него, так как это, очевидно, ошибка (независимо от того, это или нет ).
Я использую метод LicenseManager, но кэширую значение из конструктора для использования в течение всего жизненного цикла экземпляра.
public MyUserControl()
{
InitializeComponent();
m_IsInDesignMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
}
private bool m_IsInDesignMode = true;
public bool IsInDesignMode { get { return m_IsInDesignMode; } }
Версия VB:
Sub New()
InitializeComponent()
m_IsInDesignMode = (LicenseManager.UsageMode = LicenseUsageMode.Designtime)
End Sub
Private ReadOnly m_IsInDesignMode As Boolean = True
Public ReadOnly Property IsInDesignMode As Boolean
Get
Return m_IsInDesignMode
End Get
End Property