2016-08-23 17 views
5

Tôi cần sử dụng bối cảnh hoạt động trong mô hình trong khi sử dụng MVP trong Android để có danh sách tất cả các ứng dụng đã cài đặt.đó là cách chính xác để truy cập ngữ cảnh hoặc bất kỳ thay thế nào để đạt được trong khi theo mẫu MVP.Cần bối cảnh trong mô hình trong MVP

đây là các lớp:

public class MainActivity extends BaseActivity 
    implements MainView,View.OnClickListener { 

private MainPresenter mPresenter; 



private Button sendButton; 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    init(); 
    createPresenter(); 


} 

private void init(){ 

    sendButton= (Button) findViewById(R.id.button_send); 
    sendButton.setOnClickListener(this); 
} 

private void createPresenter() { 
    mPresenter=new MainPresenter(); 
    mPresenter.addView(this); 
} 





@Override 
public void onClick(View view) { 
    switch (view.getId()){ 
     case R.id.button_send: 
      mPresenter.onSendButtonClick(); 
      break; 
    } 
} 

@Override 
public void openOptionsActivity() { 
    Intent intent=new Intent(this,OptionsActivity.class); 
    startActivity(intent); 
} 

}

public class MainPresenter kéo dài BasePresenter {

MainModel model; 
public void onSendButtonClick(){ 

    model.getListOfAllApps(); 

} 

@Override 
public void addView(MainView view) { 
    super.addView(view); 
model=new MainModel(); 
} 

}

public class MainModel { 

public void getListOfAllApps(){ 
    final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); 
    mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); 
    final List pkgAppsList = getPackageManager().queryIntentActivities(mainIntent, 0); 

} 

}

có vấn đề trong getPackageManager(). QueryIntentActivities (mainIntent, 0) .cách làm như không có bất kỳ ngữ cảnh nào ở đây.

+1

Bạn không có 'Lớp ứng dụng'? –

+0

Tôi có lớp application.but làm thế nào để sử dụng nó.Bạn có nói rằng sử dụng một số trường liên tục cho bối cảnh để sử dụng trong lớp ứng dụng? Vấn đề là theo mô hình chúng ta không nên sử dụng bất kỳ lớp/đối tượng cụ thể trong mô hình Android. –

+0

Không hề. Chỉ cần tạo applicationContext trong onCreate (...) và sử dụng nó –

Trả lời

14

Tôi đã trả lời câu hỏi tương tự here mà bạn có thể muốn xem qua. Tôi sẽ cung cấp cho các phân tích về cách tôi nghĩ rằng bạn có thể giải quyết vấn đề này cụ thể mặc dù.

Sử dụng một bối cảnh tĩnh từ lớp Application

Phương pháp này sẽ làm việc nhưng tôi không ngây thơ của nó. Nó làm cho thử nghiệm khó hơn và kết hợp mã của bạn với nhau.

public class App extends Application { 

    private static Context context; 

    public static Context getContext() { 
     return context; 
    } 

    @Override 
    public void onCreate() { 
     super.onCreate(); 
     context = getApplicationContext(); 
    } 
} 

Sau đó, trong MainModel của bạn:

public class MainModel { 

    public List<String> getListOfAllApps(){ 

     final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); 
     mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); 
     final List<ResolveInfo> pkgAppsList = App.getContext().getPackageManager().queryIntentActivities(mainIntent, 0); 

     List<String> results = new ArrayList<>(); 
     for (ResolveInfo app : pkgAppsList) { 
      results.add(app.resolvePackageName); 
     } 
     return results; 
    } 
} 

Bây giờ chúng tôi đã có mà ra đường đi, chúng ta hãy xem xét một số lựa chọn tốt hơn.

Do nó trong các Hoạt động

Vì vậy, hoạt động của bạn thực hiện Xem của bạn. Nó có thể làm một vài thứ Anrdoidy quá như onActivityResult. Có một cuộc tranh cãi để giữ mã Android trong hoạt động và chỉ truy cập nó qua Xem giao diện:

public interface MainView { 

    List<String> getListOfAllApps(); 
} 

Các Hoạt động:

public class MainActivity extends BaseActivity implements MainView { 

    //.. 

    @Override 
    public List<String> getListOfAllApps(){ 

     final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); 
     mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); 
     final List<ResolveInfo> pkgAppsList = getPackageManager().queryIntentActivities(mainIntent, 0); 

     List<String> results = new ArrayList<>(); 
     for (ResolveInfo app : pkgAppsList) { 
      results.add(app.resolvePackageName); 
     } 
     return results; 
    } 

    //.. 
} 

Và Người trình bày:

public class MainPresenter extends BasePresenter { 

    public void onSendButtonClick(){ 

     view.getListOfAllApps(); 
    } 
} 

Tóm tắt các chi tiết trong một lớp riêng biệt

Trong khi tùy chọn cuối cùng không phá vỡ các quy tắc của MVP nó không cảm thấy khá đúng khi nhận được một danh sách các gói không phải là thực sự một hoạt động Xem. Tùy chọn ưa thích của tôi là ẩn sử dụng Ngữ cảnh phía sau một giao diện/lớp.

Tạo một lớp PackageModel (hoặc bất kỳ tên có ưa thích của bạn):

public class PackageModel { 

    private Context context; 

    public PackageModel(Context context) { 
     this.context = context; 
    } 

    public List<String> getListOfAllApps(){ 

     final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); 
     mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); 
     final List<ResolveInfo> pkgAppsList = context.getPackageManager().queryIntentActivities(mainIntent, 0); 

     List<String> results = new ArrayList<>(); 
     for (ResolveInfo app : pkgAppsList) { 
      results.add(app.resolvePackageName); 
     } 
     return results; 
    } 
} 

Bây giờ có Presenter của bạn yêu cầu này như một tham số constructor:

public class MainPresenter extends BasePresenter { 

    private PackageModel packageModel; 

    public MainPresenter(PackageModel packageModel) { 
     this.packageModel = packageModel; 
    } 

    public void onSendButtonClick(){ 

     packageModel.getListOfAllApps(); 
    } 
} 

Cuối cùng trong hoạt động của bạn:

public class MainActivity extends BaseActivity implements MainView { 

    private MainPresenter presenter; 

    private void createPresenter() { 

     PackageModel packageModel = new PackageModel(this); 
     presenter = new MainPresenter(packageModel); 
     presenter.addView(this); 
    } 
} 

Giờ việc sử dụng Ngữ cảnh bị ẩn khỏi Trình dẫn và nó c mang theo mà không có bất kỳ kiến ​​thức nào về Android. Điều này được gọi là tiêm constructor. Nếu bạn đang sử dụng một khuôn khổ tiêm phụ thuộc, nó có thể xây dựng tất cả các phụ thuộc cho bạn.

Nếu bạn muốn bạn có thể tạo giao diện cho PackageModel nhưng tôi không nghĩ rằng nó thực sự cần thiết như một khuôn khổ nhạo báng như Mockito có thể tạo ra một nhánh mà không cần sử dụng giao diện.

+3

Là [bình luận này] (http: // stackoverflow.com/questions/37137624/how-to-use-shared-preferences-in-mvp-without-dagger-and-not-gây-presenter-to # comment61849985_37138822) cho biết, nó chỉ ẩn phụ thuộc, điều đó còn tồi tệ hơn. [Câu trả lời] (http://stackoverflow.com/a/37216407/1276636) trên cùng một chủ đề là rất tốt vì nó làm cho phụ thuộc rất rõ ràng. Tôi đã tìm thấy [video này] (https://www.youtube.com/watch?v=-FRm3VPhseI&index=2&list=PL693EFD059797C21E) tuyệt vời về người độc thân và phụ thuộc ẩn. – Sufian

+0

Tôi chỉ cần thực hiện một điều chỉnh nhỏ để điểm 3 và làm cho PackageModel một giao diện và làm cho getListOfAllApps() phương pháp duy nhất của nó. –

+0

cách đầu tiên của bạn là khủng khiếp. chỉ cần xóa cách nắm tay. hoàn toàn sai. người trình bày và mô hình phải ở trong java thuần túy. giao diện là đúng cách. –

-1

Về cơ bản, bạn có các tùy chọn sau:

1) Luôn luôn vượt qua một Context đến Mẫu. Bất kể sự kiện nào xảy ra trong Android, bạn luôn có sẵn một số loại Context. (Và mã của bạn chỉ được gọi để trả lời các sự kiện.)

2) getApplicationContext() và lưu nó để sử dụng trong tương lai trong biến tĩnh.

Có gotchas sau:

Một Activity là một Context, nhưng nếu bạn lưu trữ một liên kết đến một hoạt động, bạn sẽ có được một sự rò rỉ bộ nhớ. Các hoạt động được tạo lại khi ví dụ màn hình quay. Tương tự về ngữ cảnh được truyền cho BroadcastReceivers và các loại Ngữ cảnh khác. Tất cả chúng đều có tuổi thọ và tuổi thọ đó không phải là những gì bạn cần cho Mẫu.

Có thể ứng dụng của bạn đã bị Android khởi động và bị xóa. Trong trường hợp này, một số biến toàn cầu (tĩnh) có thể được đặt thành rỗng. Nghĩa là, chúng sẽ bị vô hiệu trừ khi ứng dụng của bạn xảy ra để viết một cái gì đó cho chúng. Đặc biệt, một biến tĩnh trỏ đến ngữ cảnh ứng dụng có thể trở thành null trong một trong các kịch bản khởi động lại. Những vấn đề như vậy rất khó để kiểm tra.

+2

bạn không nên sử dụng ngữ cảnh trong trình bày và mô hình. mã này sẽ không thể kiểm tra được. –

Các vấn đề liên quan