2017-01-19 2 views
0

これは非常に奇妙な動作で、私はそれを修正する方法がわかりません。ビュー階層を作成した元のスレッドのみがそのビューに触れることができます。 - 奇妙な振る舞い

私はプレゼンターとしての活動を持っています(MVPアーキテクチャで)。 アクティビティが開始されると、ビューとしてフラグメントを添付します。断片自体は非常に単純です。

public class CurrentSaleFragment extends BaseFragment { 

private MainMVP.SalesPresenterOps salesPresenterOps; 
private SaleAdapter adapter; 
private ListView lv; 


@BindView(R.id.btn_sell) 
FloatingActionButton btnAdd; 

public static CurrentSaleFragment newInstance(){ 
    CurrentSaleFragment fragment = new CurrentSaleFragment(); 
    Bundle arguments = new Bundle(); 
    arguments.putInt(LAYOUT_RES_ID, R.layout.fragment_quick_sale); 
    fragment.setArguments(arguments); 
    return fragment; 
} 

@Override 
protected void init() { 
    super.init(); 
    lv = (ListView)view.findViewById(R.id.lv_sale); 
} 

@OnClick(R.id.btn_sell) 
public void addToSale(View view){ 
    mPresenter.moveToFragment(SellProductFragment.newInstance()); 
} 

@Override 
public void onAttach(Context context) { 
    super.onAttach(context); 
    salesPresenterOps = (MainMVP.SalesPresenterOps)context; 
} 

@Override 
public void onDetach() { 
    salesPresenterOps = null; 
    super.onDetach(); 
} 
} 

このfragmendが延びるBaseFragment:

public class BaseFragment extends Fragment implements MainMVP.RequiredViewOps, View.OnClickListener, 
    LoaderRequiredOps{ 

protected View view; 
protected MainMVP.PresenterOps mPresenter; 


protected final static String LAYOUT_RES_ID = "layout_res_id"; 

@Override 
public void showOperationResult(String message, final long rowId) { 
    Snackbar.make(view, message, Snackbar.LENGTH_LONG).setAction(
      R.string.see, new View.OnClickListener() { 
       @Override 
       public void onClick(View v) { 
        onOperationResultClick(rowId); 
       } 
      } 
    ).show(); 
} 

@Override 
public void showSnackBar(String msg) { 
    Snackbar.make(view, msg, Snackbar.LENGTH_SHORT).show(); 
} 

@Override 
public void showAlert(String msg) {} 



protected void onOperationResultClick(long rowId){} 

@Override 
public void onAttach(Context context) { 
    super.onAttach(context); 
    mPresenter = (MainMVP.PresenterOps)context; 
} 

@Nullable 
@Override 
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 
    this.view = inflater.inflate(getArguments().getInt(LAYOUT_RES_ID), null); 
    init(); 
    return view; 
} 

protected void addToClickListener(View ... params){ 
    for (View v : params){ 
     v.setOnClickListener(this); 
    } 
} 

protected void init() { 
    if (view != null){ 
     ButterKnife.bind(this, view); 
    } 
} 

@Override 
public void onDetach() { 
    mPresenter = null; 
    Log.d(getClass().getSimpleName(), "Fragment was detached"); 
    super.onDetach(); 
} 

@Override 
public void onClick(View v) {} 

@Override 
public void onPreLoad() { 
    Dialogs.buildLoadingDialog(getContext(), "Loading...").show(); 
} 

@Override 
public void onLoad() {} 

@Override 
public void onDoneLoading() { 
    Dialogs.dismiss(); 
} 

} 

を私は方法入力すると 'moveToFragmentは()' 私はちょうど新しいフラグメントのためCurrentSaleFragmentを置き換える:

protected void addFragment(BaseFragment fragment){ 
    mView = fragment; 
    getSupportFragmentManager().beginTransaction().replace(R.id.fragment_holder, 
      fragment, null).addToBackStack(null).commit(); 
} 

その後新しい断片が添付されます:

public class SellProductFragment extends BaseFragment{ 

private ListView listView; 
private ProductListAdapter adapter; 
private MainMVP.SalesPresenterOps mSalesPresenter; 

public static SellProductFragment newInstance(){ 
    SellProductFragment fragment = new SellProductFragment(); 
    Bundle arguments = new Bundle(); 
    arguments.putInt(LAYOUT_RES_ID, R.layout.fragment_inventory); 
    fragment.setArguments(arguments); 
    return fragment; 
} 

private void reload(){ 
    final Loader loader = new Loader(this); 
    loader.execute(); 
} 

@Override 
public void onAttach(Context context) { 
    super.onAttach(context); 
    mSalesPresenter = (MainMVP.SalesPresenterOps)context; 
} 

@Override 
protected void init() { 
    super.init(); 
    listView = (ListView)view.findViewById(R.id.lv_inventory); 
    reload(); 
    FloatingActionButton button = (FloatingActionButton)view.findViewById(R.id.btn_add); 
    addToClickListener(button); 
} 

@Override 
public void onLoad() { 
    adapter = new ProductListAdapter(getActivity().getApplicationContext(), R.layout.row_product_item, 
      mSalesPresenter.getProducts()); 
    try{ 
     updateListView(); 
    }catch (Exception e){ 
     Log.w(getClass().getSimpleName(), e.getMessage()); 
    } 
} 

private void updateListView(){ 
    if (adapter != null && listView != null){ 
     listView.setAdapter(adapter); 
    }else{ 
     throw new RuntimeException(); 
    } 
} 
} 

参照このフラグメントもBaseFragmentから拡張され、LoaderRequiredOpsを実装しています。インタフェースは、データをロードするために使用されます。私は、メソッドのリロードを()SellProductFragmentから私は、ビュー階層を作成し「のみ元のスレッドを取得し、実行しようとすると、今

public class Loader extends AsyncTask<Void, Void, Void> { 

private LoaderRequiredOps presenter; 

public Loader(LoaderRequiredOps presenter){ 
    this.presenter = presenter; 
} 

@Override 
protected void onPreExecute() { 
    super.onPreExecute(); 
    presenter.onPreLoad(); 
} 

@Override 
protected Void doInBackground(Void... params) { 
    presenter.onLoad(); 
    return null; 
} 

@Override 
protected void onPostExecute(Void aVoid) { 
    super.onPostExecute(aVoid); 
    presenter.onDoneLoading(); 
    presenter = null; 
} 
} 

:それは、ダイアログおよび更新のロードが行われているアダプタを追加しますその意見に触れることができる。

これは、CurrentSaleFragmentの代わりにSellProductFragmentが最初にアタッチされている場合は発生しません。

ここで何が起こっているか

+1

特定の構成で例外が発生しない場合は、ラッキー(?)になります。最終的に 'doInBackground()'の 'ListView'に' Adapter'を設定しています。あなたはそれをすることはできません。 –

+0

あなたは正しいです!ありがとうございました。 'updateListView()'を 'onPostExecute()'に移動しました – chntgomez

+1

ええ、そこには問題ありません。 'onPostExecute()'はUIスレッド上で動作します。 (私はあなたが 'doInBackground()'または 'onLoad()'から最小限の例のためにいくつかの処理コードを省略していると仮定していますが、そうでない場合、 'AsyncTask'それはむしろ無意味です。) –

答えて

0

不明な理由があるため、未確認の設定では、doInBackground()メソッドでListViewのアダプターの設定を実行することができます。 はonPostExecute()にそれを移動し、今では

0

を働いているあなたの非同期LoaderクラスはdoInBackground()中にバックグラウンドスレッドからのプレゼンター方法onLoad()を呼び出します。

私の推測では、プレゼンターのonLoad()メソッドでは、ビューが参照されています。

この時点でビューを変更するには、表示ロジックをRunnableとしてUIスレッドに投稿します(発表者はアクティビティだと言いましたので、これはonLoadメソッドから可能であるはずです)。

@Override 
public void onLoad() { 
    runOnUiThread(new Runnable() { 
     @Override 
     public void run() { 
      // Your ui code here... 
     } 
    }); 

    // Rest of your code here... 
} 
関連する問題