2016-03-20 41 views
0

我有一個Android應用程序需要從網站加載一些數據,然後顯示它。爲此,用戶會看到一個加載欄,在後臺線程加載網站,然後切換回主線程(帶有Handler)並顯示信息。到目前爲止這麼好,這裏沒有問題。但是,如果用戶在加載信息時關閉手機,並在顯示時未返回,則應用程序會崩潰。當屏幕關閉時,會調用Android onStart()事件

因此,當用戶關閉手機並重新打開手機時,需要中斷該過程。這應該不是問題,有很多事情要做這樣的事情。

但我的調試信息顯示onStart() -Event(這對我的問題來說是完美的)以某種方式稱爲,當用戶的手機仍然關閉時!這會導致錯誤。有什麼辦法可以避免這種情況?

編輯: 這裏是我的代碼(修剪,當然)

(MainActivity.java)

private static MainActivity activity; 
//Handler to run code from other threads in the main thread (needed to modify the GUI) 
private static Handler handler; 

private static ProgressBar progressBar; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    this.requestWindowFeature(Window.FEATURE_NO_TITLE); 
    setContentView(R.layout.activity_main); 

    activity = this; 
    handler = new Handler(); 

    [...] 

} 

@Override 
public void onStart(){ 
    super.onStart(); 

    Log.e("s", "start"); 
    PageManager.mayContinue(true); 

    if(PageManager.getCurrentPage() == null) { 
     PageManager.loadPage(new StatusPage()); 
    }else{ 
     PageManager.loadPage(PageManager.getCurrentPage()); 
    } 
} 

@Override 
public void onStop(){ 
    super.onStop(); 


    Log.e("s", "Stop"); 
    PageManager.mayContinue(false); 
} 

public static MainActivity getActivity(){ 
    return activity; 
} 

public static void runOnMainThread(Runnable r){ 
    handler.post(r); 
} 

(PageManager.java)

private static Boolean isPageLoading = false; 

private static Page currentPage; 

private static boolean mayContinue; 

public static void loadPage(final Page page){ 

    if(isPageLoading){ 
     return; 
    } 

    if(currentPage != null) { 
     boolean allowedToLoadDifferentPage = currentPage.onPageLeft(); 
     if (!allowedToLoadDifferentPage) { 
      return; 
     } 
    } 

    isPageLoading = true; 

    FragmentManager fragmentManager = MainActivity.getActivity().getFragmentManager(); 
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); 

    DisplayFragment fragment = new DisplayFragment(); 
    fragment.setPage(page); 
    fragmentTransaction.replace(R.id.display_fragment, fragment); 
    fragmentTransaction.commit(); 

    MainActivity.getProgressBar().setVisibility(View.VISIBLE); 

    Runnable r = new Runnable(){ 

     @Override 
     public void run() { 

      //Load the required data 
      page.loadPage(); 

      isPageLoading = false; 

      if(!mayContinue){ 

       MainActivity.runOnMainThread(new Runnable() { 
        @Override 
        public void run() { 
         MainActivity.getProgressBar().setVisibility(View.INVISIBLE); 
        } 
       }); 

       Log.e("PageManager", "Loading process got blocked!"); 

       return; 
      } 

      currentPage = page; 

      MainActivity.runOnMainThread(new Runnable() { 

       @Override 
       public void run() { 
        MainActivity.getProgressBar().setVisibility(View.INVISIBLE); 
        //Display the loaded data 
        page.setViewValues(); 
       } 

      }); 
     } 


    }; 

    new Thread(r).start(); 
} 

public static Page getCurrentPage(){ 
    return currentPage; 
} 

public static void mayContinue(boolean value) { 
    mayContinue = value; 
} 

StatusPage的一部分.java:

@Override 
public void setViewValues() { 

    RecyclerView rv = (RecyclerView)MainActivity.getActivity().findViewById(R.id.insert_values); 
    LinearLayoutManager llm = new LinearLayoutManager(MainActivity.getActivity()); 
    llm.setOrientation(LinearLayoutManager.VERTICAL); 
    rv.setLayoutManager(llm); 

    RecyclerViewAdapter adapter = new RecyclerViewAdapter(); 
    rv.setAdapter(adapter); 
    [...] 
} 

的logcat的:

03-21 07:50:38.109 6121-6121/de.namnodorel.app E/s: start //The Activity got launched 
    03-21 07:50:38.261 6121-6121/de.namnodorel.app E/RecyclerView: No adapter attached; skipping layout 
    03-21 07:50:38.342 6121-6121/de.namnodorel.app E/RecyclerView: No adapter attached; skipping layout 
    //I turn the phone off 
    03-21 07:50:39.541 6121-6121/de.namnodorel.app E/s: Stop 
    //??? (I didn't turn it on) 
    03-21 07:50:40.326 6121-6121/de.namnodorel.app E/s: start 
    //The app crashes because the findViewById() returned null (which means there is nothing with that ID on the current screen) 
    03-21 07:50:41.337 6121-6121/de.namnodorel.app E/AndroidRuntime: FATAL EXCEPTION: main 

                     Process: de.namnodorel.app, PID: 6121 
                     java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setLayoutManager(android.support.v7.widget.RecyclerView$LayoutManager)' on a null object reference 
                      at 

de.namnodorel.app.game.status.StatusPage.setViewValues(StatusPage.java:47) 
                      at de.namnodorel.app.game.PageManager$1$2.run(PageManager.java:75) 
                      at android.os.Handler.handleCallback(Handler.java:739) 
                      at android.os.Handler.dispatchMessage(Handler.java:95) 
                      at android.os.Looper.loop(Looper.java:135) 
                      at android.app.ActivityThread.main(ActivityThread.java:5294) 
                      at java.lang.reflect.Method.invoke(Native Method) 
                      at java.lang.reflect.Method.invoke(Method.java:372) 
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904) 
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699) 
                      at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:115) 

我希望onStartonStop()被又稱,當屏幕被關閉。文檔說,他們被稱爲,當活動不再可見/再次可見時。而且因爲當屏幕關閉時,沒有任何東西可見(或至少是LockScreen),我期望它們被調用。他們是,但onStart()被調用在錯誤的地方。

+0

onStart沒有按照屏幕打開和關閉來定義。它是根據用戶可見的活動來定義的。你真的需要在屏幕上開啓/關閉,還是需要觸發可視性?他們是不同的東西。 –

+0

@Doug Stevenson在某種程度上,兩者都有。加載數據後,該進程嘗試顯示它。如果活動不可見或屏幕已關閉,則這不起作用 – Namnodorel

+0

實際上,更新停止且不可見(但尚未銷燬)的活動的視圖層次結構沒有問題。直到下一次onStart才能看到更改。 –

回答

0

爲什麼onStart()適合您的問題?爲什麼不是onCreate()?爲了解決這個問題

的方法之一是必須在

onRestart() 

方法設置爲true,一個全球性的布爾值。而在

onStart() 

方法檢查如果布爾值爲true,如果是,不引起錯誤的過程中去,否則,繼續。之後,在

onStart() 

方法將布爾值設置爲false。

+0

當Activtiy開始時,onCreate()被調用;我需要一些在屏幕關閉/打開時調用的東西;)我嘗試了類似的東西(用onStop()而不是onRestart());我在onStop()中設置布爾值爲false(如果一個操作正在運行,它會在發現bug之前停止),並將onStart()設置爲true(另外我正在重新啓動加載過程,因爲不應該存在一個空白屏幕)。但是因爲onStart()在屏幕關閉時被調用,所以如果一個正在運行的進程出現了這個bug,它就不會停下來。我想這也是解決方案中存在的問題。 – Namnodorel

+0

當屏幕處於關閉狀態時,onStart不會被調用,它會在打開並調用此Activity時被調用。你能分享一下bug或logcat來看看錯誤嗎? – mmcoder10

+0

剛剛添加的代碼和logcat – Namnodorel

0

可能是你可以做到另一種方式。用Intent.ACTION_SCREEN_OFF註冊廣播接收機,Intent.ACTION_SCREEN_ON

0

好的,我已經想通了。在onStart() - 方法我只是檢查屏幕是否打開。如果不是,則不處理該呼叫。這可能不是一個解決方案,但最終是一種解決方法。這是我的代碼現在看起來像:

@Override 
public void onStart(){ 
    super.onStart(); 

    if(isScreenOn()) { 
     PageManager.mayContinue(true); 

     if(PageManager.getCurrentPage() == null) { 
      PageManager.loadPage(new StatusPage()); 
     }else{ 
      PageManager.loadPage(PageManager.getCurrentPage()); 
     } 
    } 

} 


@Override 
public void onStop(){ 
    super.onStop(); 

    PageManager.mayContinue(false); 
} 

    public boolean isScreenOn(){ 
    PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 

    if (Build.VERSION.SDK_INT < 21) { 
     return pm.isScreenOn(); 
    }else{ 
     return pm.isInteractive(); 
    } 
} 
+0

順便說一句,它並沒有完全解決Bug,因爲onStart()有時也被稱爲手機尚未解鎖時調用。但這不是問題所在。 – Namnodorel

0

當手機關機時,可以通過通知或其他一些系統服務醒了,可能使你的活動是活動的。

onStart():當活動對用戶變得可見時調用。

onResume():當活動開始與用戶交互時調用。

您可以更改爲在onResume()中執行您的代碼。

如果這對您來說太遲了,您可以添加一個判斷,如果電話被PowerManager關閉。

相關問題